代理模式 
        代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。

在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

一、静态代理
1. 接口类:Count.java

  1. public interface Count {
  2. // 查看账户方法
  3. public void queryCount();
  4. // 修改账户方法
  5. public void updateCount();
  6. }

2. 实现类:CountImpl.java

  1. public class CountImpl implements Count {
  2. @Override
  3. public void queryCount() {
  4. System.out.println("查看账户方法...");
  5. }
  6.  
  7. @Override
  8. public void updateCount() {
  9. System.out.println("修改账户方法...");
  10. }
  11. }

3. 代理类:CountProxy.java

  1. public class CountProxy implements Count {
  2. private CountImpl countImpl;
  3.  
  4. /**
  5. * 覆盖默认构造器
  6. * @param countImpl
  7. */
  8. public CountProxy(CountImpl countImpl) {
  9. this.countImpl = countImpl;
  10. }
  11.  
  12. @Override
  13. public void queryCount() {
  14. System.out.println("事务处理之前");
  15. // 调用委托类的方法;
  16. countImpl.queryCount();
  17. System.out.println("事务处理之后");
  18. }
  19.  
  20. @Override
  21. public void updateCount() {
  22. System.out.println("事务处理之前");
  23. // 调用委托类的方法;
  24. countImpl.updateCount();
  25. System.out.println("事务处理之后");
  26. }
  27. }

4. 测试类:TestCount.java

  1. public class TestCount {
  2. public static void main(String[] args) {
  3. CountImpl countImpl = new CountImpl();
  4. CountProxy countProxy = new CountProxy(countImpl);
  5. countProxy.updateCount();
  6. countProxy.queryCount();
  7. }
  8. }

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

二、动态代理

1. 接口类:

  1. public interface PersonService {
  2.  
  3. public String getPersonName(Integer personId);
  4.  
  5. public void save(String name);
  6.  
  7. public void update(Integer personId, String name);
  8. }

2. 实现类:

  1. public class PersonServiceBean implements PersonService {
  2.  
  3. public String user = null;
  4.  
  5. public PersonServiceBean(){};
  6.  
  7. public PersonServiceBean(String user){
  8. this.user = user;
  9. }
  10.  
  11. @Override
  12. public String getPersonName(Integer personId) {
  13. System.out.println("这是find方法");
  14.  
  15. return this.user;
  16. }
  17.  
  18. @Override
  19. public void save(String name) {
  20. System.out.println("这是save方法");
  21. }
  22.  
  23. @Override
  24. public void update(Integer personId, String name) {
  25. System.out.println("这是update方法");
  26. }
  27.  
  28. public String getUser() {
  29. return user;
  30. }
  31.  
  32. public void setUser(String user) {
  33. this.user = user;
  34. }
  35. }

3. JDK动态代理代理类:

  1. /**
  2. * 切面
  3. */
  4. public class JDKProxyFactory implements InvocationHandler {
  5.  
  6. private Object proxyObject; //目标对象
  7.  
  8. /**
  9. * 绑定委托对象并返回一个代理类
  10. * @param proxyObject
  11. * @return
  12. */
  13. public Object createProxyInstance(Object proxyObject) {
  14. this.proxyObject = proxyObject;
  15. //生成代理类的字节码加载器
  16. ClassLoader classLoader = proxyObject.getClass().getClassLoader();
  17. //需要代理的接口,被代理类实现的多个接口都必须在这里定义 (这是一个缺陷,cglib弥补了这一缺陷)
  18. Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();
  19. //织入器,织入代码并生成代理类
  20. return Proxy.newProxyInstance(classLoader, proxyInterface, this);
  21. }
  22.  
  23. @Override
  24. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    PersonServiceBean bean = (PersonServiceBean)this.proxyObject;
  25. Object result = null;
  26. //控制哪些用户执行切入逻辑
  27. if(bean.getUser() != null) {
  28. //执行原有逻辑
  29. result = method.invoke(this.proxyObject, args);
  30. }
  31.  
  32. return result;
  33. }
  34. }

4. 测试类:

  1. public class AopTest {
  2. @Test
  3. public void proxyTest() {
  4. JDKProxyFactory jpf = new JDKProxyFactory();
  5. PersonServiceBean personService = (PersonServiceBean) jpf.createProxyInstance(new PersonServiceBean("XXX"));
  6. personService.save("888");
  7. }
  8. }

上面是提供了用户名的,所以终端会打印出”我是save()方法“,然后我们将 Java代码

PersonServiceBean personService = (PersonServiceBean)jpf.createProxyInstance(new PersonServiceBean("XXX"));  
改为不提供用户名,即
PersonServiceBean personService = (PersonServiceBean) jpf.createProxyInstance(new PersonServiceBean());  

这时候在允许代码发现终端不打印出"我是save()方法",证明我们的动态代理是成功的。

[转]JDK动态代理的更多相关文章

  1. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  2. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  3. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  4. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  5. JDK动态代理的实现原理

    学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504

  6. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  7. JDK动态代理与CGLib动态代理

    1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...

  8. jdk动态代理实现

    1.jdk动态代理的简单实现类 package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.refl ...

  9. java jdk动态代理

    在面试的时候面试题里有一道jdk的动态代理是原理,并给一个事例直接写代码出来,现在再整理一下 jdk动态代理主要是想动态在代码中增加一些功能,不影响现有代码,实现动态代理需要做如下几个操作 1.首先必 ...

  10. JDK动态代理的实现及原理

    Proxy.newProxyInstance(classloader,Class,invocationHandler) 调用getProxyClass0(loader, interfaces)生成代理 ...

随机推荐

  1. ClickOnce 和管理员权限

    有些程序需要管理员权限需要运行,同时又想用ClickOnce进行发布,这时候就麻烦了,两者是互斥的. 解决方案是,去掉管理员权限的要求,可以进行发布. 程序启动的时候,加载程序员权限的请求. 代码如下 ...

  2. vue中使用sass 做减法计算

    首先确认已安装sass依赖, yarn指令:yarn add sass-loader, style中写法如下: 注意calc(100% - 200px); 之间有两个空格的,

  3. 若sql语句中order by指定了多个字段,怎么排序?

    举个例子吧: order by id desc,time desc 先是按 id 降序排列 (优先)如果 id 字段 有些是一样的话 再按time 降序排列 (前提是满足id降序排列)

  4. [转]Cross-type joins in Elasticsearch

    Cross-type joins in Elasticsearch http://rore.im/posts/elasticsearch-joins December 31, 2014 When mo ...

  5. tomcat多实例的端口设置

    需要改4个端口 8080  8009 8005 8443 8080改成8081 8005改成8105 8009改成8109 8443 改成8543

  6. asm磁盘组,asm磁盘状态学习

    说明:在数据库中巡检,发现,数据库某个磁盘组状态为mount,其余磁盘组均为CONNECTED状态,排除是否异常 文档流程: 1.实际环境查询校验 2.官方文档视图中对磁盘组,磁盘状态的解释说明 3. ...

  7. fatal: unable to access 'https://xxxxx': SSL connect error

    /********************************************************************** * fatal: unable to access 'h ...

  8. 【Java】输出目录结构

    import java.io.*; import java.io.File; import java.io.IOException; public class FileUtil { public st ...

  9. golang 3des/ecb/cbc/pkcs5 加解密

    本人新手,参考文档: http://blog.studygolang.com/2013/01/go%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E4%B9%8Bdes/ h ...

  10. jQuery事件委托方法 bind live delegate on

    1.bind    jquery 1.3之前 定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数 语法:  bind(type,[data],function(e)); 特点: a.适合页 ...