码迷,mamicode.com
首页 > 编程语言 > 详细

java动态代理【一】

时间:2017-05-10 18:52:42      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:int   tor   定义   不同   image   super   调用   override   接口   

java动态代理的定义:为其他目标类的方法增加切面的逻辑,即在执行目标类方法的时候,先去执行一段如校验检测的逻辑代码。java通俗一点就是生成一个继承目标类的子类,并在每个调用方法都添加一段逻辑。

应用场景:当我们从别的项目迁移过来的代码进行修改的时候,如果有一个需求是当要执行某个业务类的所有方法前,需要校验其权限或其他的时候,如果这个类是源代码,我们还可以在类的基础上对每个方法区更改,但若是打包成jar包的类,若该类有接口还可以实现一个代理模式创建一个代理类,没有接口就比较麻烦,但接口一旦多起来,那编写的话也比较麻烦。这时我们就需要用到动态代理,由jdk动态创建一个proxy类,我们通过proxy类来调用目标类的方法。

动态代理的实现有三种方法:
1、使用代理模式。
    1)创建一个Star(明星)类,其实现了Speak,Eat接口
    
  1. package cglib;
  2. public class Star implements Speak,Eat{
  3. @Override
  4. public void say() {
  5. // TODO Auto-generated method stub
  6. System.out.println("i am a star");
  7. }
  8. @Override
  9. public void eat() {
  10. // TODO Auto-generated method stub
  11. System.out.println("star eats some fruit");
  12. }
  13. }
    2)创建一个Broker(经纪人)类,其实现了Speak接口,如下代码:
        
  1. package cglib;
  2. //装饰器模式
  3. public class Broker implements Speak{
  4. private Speak speak;
  5. public Broker(Speak speak){
  6. this.speak=speak;
  7. }
  8. @Override
  9. public void say() {
  10. // TODO Auto-generated method stub
  11. speak.say();
  12. }
  13. }

    3)测试代码:
    技术分享
 
       输出I am Star! 一个经纪人可以代理不同的明星表述,这在现实中是符合的。
2、使用JDK动态代理(原理是通过映射,动态生成java字节码Proxy类)
    1)同样以Star类为目标类,实现JDK动态代理需要实现InvocationHandler接口,如下:
        
  1. package cglib;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. public class JDKDynamicProxy implements InvocationHandler{
  6. private Object speak;
  7. private JDKDynamicProxy(Object speak){
  8. //传入star对象
  9. this.speak=speak;
  10. }
  11. //创建一个静态方法,生成代理类,
  12. public static Object newProxyInstance(Object speak){
  13. System.out.println(JDKDynamicProxy.class.getClassLoader().toString());
  14. return Proxy.newProxyInstance(JDKDynamicProxy.class.getClassLoader(),new Class[]{Speak.class,Eat.class}, new JDKDynamicProxy(speak));
  15. }
  16. //覆盖InvocationHandler的invoke方法,从参数可以看出,这个方法明显使用了jdk的方法映射来调用Star的方法,在调用Star的方法前后,我们都可以增加自己的逻辑代码
  17. @Override
  18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  19. // TODO Auto-generated method stub
  20. System.out.println("call the JDKDynamicProxy");
  21. return method.invoke(speak, args);
  22. }
  23. }

        2)测试类
    
  1. package cglib;
  2. import java.lang.reflect.Constructor;
  3. public class ProxyTest {
  4. public static void main(String[] args) {
  5. //装饰者模式
  6. Star star=new Star();
  7. Speak b=new Broker(star);
  8. b.say();
  9. //jdk动态代理模式
  10. Speak s=(Speak) JDKDynamicProxy.newProxyInstance(star);
  11. s.say();
  12. Eat e=(Eat) JDKDynamicProxy.newProxyInstance(star);
  13. e.eat();
  14. //CGlib动态代理
  15. Speak sp=CGProxy.newCGproxyInstance(Star.class);
  16. sp.say();
  17. }
  18. }
技术分享
 可以看出在调用Star的say()方法之前,调用了JDKDynamicProxy 的invoke方法。
   3、使用CGLib动态代理(原理使用了asm)
        1)CGProxy类,因为是方法拦截,故实现的是MethodInterceptor 接口,下面是一个简单的实现方法。
                
 
  1. package cglib;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6. public class CGProxy implements MethodInterceptor {
  7. public static <T extends Speak> Speak newCGproxyInstance(Class<T> superClass){
  8. Enhancer en=new Enhancer();
  9. en.setSuperclass(superClass);
  10. en.setCallback(new CGProxy());
  11. return (Speak)en.create();
  12. }
  13. @Override
  14. public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
  15. // TODO Auto-generated method stub
  16. System.out.println("call the CGProxy");
  17. return arg3.invokeSuper(arg0, arg2);
  18. }
  19. }
    看代码和JDK动态代理的写法差不多,但其内部实现的原理却不同。明显的区别从代码可以看出,JDK动态代理要传入目标类的接口作为参数,所以目标类必须要有一个统一的接口,即如上的Speak,Eat接口,这就使得JDK动态代理有一定的局限性。而CGlib从代码看出,传入的是Class,不是接口,使用范围更广一些。


下一章探讨一下JDK动态代理内部的实现原理。






java动态代理【一】

标签:int   tor   定义   不同   image   super   调用   override   接口   

原文地址:http://www.cnblogs.com/zhenyimo/p/6837321.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!