关于静态代理和动态代理的个人总结

具体实现类

[java]  view plain  copy
  1. public class UserManagerImpl implements UserManager {  
  2.   
  3.     @Override  
  4.     public void addUser(String userId, String userName) {  
  5.         System.out.println("UserManagerImpl.addUser");  
  6.     }  

  7. }  

代理类--代理实现类

[java]  view plain  copy
  1. public class UserManagerImplProxy implements UserManager {  
  2.   
  3.     // 目标对象  
  4.     private UserManager userManager;  
  5.     // 通过构造方法传入目标对象  
  6.     public UserManagerImplProxy(UserManager userManager){  
  7.         this.userManager=userManager;  
  8.     }  
  9.     @Override  
  10.     public void addUser(String userId, String userName) {  
  11.         try{  
  12.                 //添加打印日志的功能  
  13.                 //开始添加用户  
  14.                 System.out.println("start-->addUser()");  
  15.                 userManager.addUser(userId, userName);  
  16.                 //添加用户成功  
  17.                 System.out.println("success-->addUser()");  
  18.             }catch(Exception e){  
  19.                 //添加用户失败  
  20.                 System.out.println("error-->addUser()");  
  21.             }  
  22.     }  
  23.  
  24. }  

客户端调用


[java]  view plain  copy
  1. public class Client {  
  2.   
  3.     public static void main(String[] args){  
  4.         //UserManager userManager=new UserManagerImpl();  
  5.         UserManager userManager=new UserManagerImplProxy(new UserManagerImpl());  
  6.         userManager.addUser("1111""张三");  
  7.     }  
  8. }  

静态代理类优缺点

 

优点:

 

代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)。

 

缺点:

1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。




在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持

 

java.lang.reflect.InvocationHandler接口的定义如下:

[java]  view plain  copy
  1. //Object proxy:被代理的对象  
  2. //Method method:要调用的方法  
  3. //Object[] args:方法调用时所需要参数  
  4. public interface InvocationHandler {  
  5.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;  
  6. }  


java.lang.reflect.Proxy类的定义如下:

[java]  view plain  copy
  1. //CLassLoader loader:类的加载器  
  2. //Class<?> interfaces:得到全部的接口  
  3. //InvocationHandler h:得到InvocationHandler接口的子类的实例  
  4. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException  


 

具体实现类

[java]  view plain  copy
  1. public class UserManagerImpl implements UserManager {  
  2.     @Override  
  3.     public void addUser(String userId, String userName) {  
  4.         System.out.println("UserManagerImpl.addUser");  
  5.     }  

  6. }  

动态创建代理对象的类

[java]  view plain  copy
  1. //动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类  
  2.      
  3. public class LogHandler implements InvocationHandler {  
  4.     // 目标对象  
  5.     private Object targetObject;  
  6.     //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。              
  7.     public Object newProxyInstance(Object targetObject){  
  8.         this.targetObject=targetObject;  
  9.         //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例    
  10.         //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
  11.         //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
  12.         //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
  13.         //根据传入的目标返回一个代理对象  
  14.         return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),  
  15.                 targetObject.getClass().getInterfaces(),this);  
  16.     }  
  17.     @Override  
  18.     //关联的这个实现类的方法被调用时将被执行  
  19.     /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/  
  20.     public Object invoke(Object proxy, Method method, Object[] args)  
  21.             throws Throwable {  
  22.         System.out.println("start-->>");  
  23.         for(int i=0;i<args.length;i++){  
  24.             System.out.println(args[i]);  
  25.         }  
  26.         Object ret=null;  
  27.         try{  
  28.             /*原对象方法调用前处理日志信息*/  
  29.             System.out.println("satrt-->>");  
  30.             //调用目标方法  
  31.             ret=method.invoke(targetObject, args);  
  32.             /*原对象方法调用后处理日志信息*/  
  33.             System.out.println("success-->>");  
  34.         }catch(Exception e){  
  35.             e.printStackTrace();  
  36.             System.out.println("error-->>");  
  37.             throw e;  
  38.         }  
  39.         return ret;  
  40.     }  
  41.   
  42. }  

被代理对象targetObject通过参数传递进来,我们通过targetObject.getClass().getClassLoader()获取ClassLoader对象,然后通过targetObject.getClass().getInterfaces()获取它实现的所有接口,然后将targetObject包装到实现了InvocationHandler接口的LogHandler对象中。通过newProxyInstance函数我们就获得了一个动态代理对象。

 

客户端代码

[java]  view plain  copy
  1. public class Client {  
  2.   
  3.     public static void main(String[] args){  
  4.         LogHandler logHandler=new LogHandler();  
  5.         UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImpl());  
  6.         //UserManager userManager=new UserManagerImpl();  
  7.         userManager.addUser("1111""张三");  
  8.     }  
  9. }  

可以看到,我们可以通过LogHandler代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。


另,spring中aop的实现分为两种,一种是JdkDynamicAopProxy,就是上面这种,另一种是基于Cglib2AopProxy。第一种使用于目标对象是接口类的情况,原因是java不支持多继承(单根继承性),目标类不是接口类的情况不适用于java自身的动态代理,需要借助于cglib这种代码生成工具完成动态代理。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值