JDK动态代理和CGLIB动态代理

动态代理模式:

动态代理的意义在于生成一个代理对象,来代理真实的对象,在真实对象访问之前或者之后加入对应的逻辑,或者控制是否使用真实的对象。

为了实现代理的功能,代理的两个步骤为:

l  代理对象和真实对象之间建立代理关系

l  实现代理对象的逻辑方法

在java中有多种动态代理技术,其中常用的动态代理技术有两种:一种是JDK动态代理技术(jdk自带的功能),另一种是CGLIB(第三方提供)

一. JDK动态代理

Java.lang.reflect.*提供的动态代理方式,其必须定义一个接口才能产生代理对象。

  1. 定义接口
    package proxy;
    
    public interface Helloworld {
        public void sayHelloworld();
    }

    2.接口实现类

    package proxy;
    
    public class HelloworldImpl implements Helloworld{
    
        @Override
        public void sayHelloworld() {
            // TODO Auto-generated method stub
            System.out.println("Hello world");
        }
        
    
    }

    3.建立JDK动态代理,根据刚开始我们说的两个步骤分别实现bind和invoke方法

    package proxy;
    import java.lang.reflect.*;
    
    public class JdkProxyExample implements InvocationHandler{
        public Object target = null;
        
    //    建立真实对象和代理对象之间的代理关系,并返回代理关系
        public Object bind(Object target) {
            this.target = target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
    //    @Override
    //    代理方法逻辑
    //    @param proxy 代理对象
    //    @param method 当前调度方法
    //    @param args 当前方法参数
    //    @return 代理结果返回
    //    @throes Throwable 异常
        
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            System.out.println("进入代理逻辑方法");
            System.out.println("在调度真实对象之前的调度");
            Object obj = method.invoke(target, args);//相当于调用了sayHelloworld方法
            System.out.println("在调用真实对象之后的服务");
            return obj;
        }
        
    
    }

    步骤一:建立代理对象与真实对象之间的代理关系(bind方法)方法里首先使用了类属性保存了真实对象 在通过如下代码生成代理对象

    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

    NewProxyInstance包含三个参数:

    l  Target.getClass().getClassLoader():真实对象的类加载器,

    l  Target.getClass().getInterfaces():把生成的代理对象挂在Helloworld的接口上

    l  This:定义实现方法咯及的代理类,this表示当前对象,它必须是实现InvocationHandler接口的invoke方法,是动态代理逻辑方法的现实方法。

     

    步骤二:实现代理逻辑方法:

    Invoke方法的参数含义:

    Proxy:代理对象,即bind方法生成的对象

    Method:当前调用的方法

    Args:调度方法的参数

    我们使用了代理对象的方法后,它就会进入invoke方法里面

     Object obj = method.invoke(target, args);//相当于调用了真实对象的sayHelloworld方法

    这是通过反射实现对真实方法的调用。

     

    测试JDK动态代理代码:

    package proxy;
    
    public class TestJdkProxy {
        public static void main(String[] args) {
        JdkProxyExample jdk = new JdkProxyExample();
        Helloworld proxy = (Helloworld)jdk.bind(new HelloworldImpl());
        proxy.sayHelloworld();
        }
    
    }

    结果:

  2. 二. CGLIB动态代理:

    CGLIB动态代理的优势在于不需要提供接口,只需要一个非抽象类就能实现动态代理。

    非抽象类代码如下:

    package cglib;
    
    public class Helloworld {
        public void sayHelloworld(String name) {
            System.out.println("Hello,"+name);
        }
    
    }
    
    

    Cglib动态代理:

    package cglib;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class CglibProxyExample implements MethodInterceptor{
        
        public Object getProxy(Class cls) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(cls);
            enhancer.setCallback(this);
            return enhancer.create();
            
        }
    
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("调用真实对象前");
            Object result = methodProxy.invokeSuper(proxy,args);
            System.out.println("调用真实对象后");
            return result;
            
        }
    
    }

    这里用了CGLIB的加强者Enhancer,通过设置超类的方法建立代理关系,通过setCallback方法设置代理类,this指当前对象,实现MethodInterceptor的方法(intercept)

    方法参数含义:

    Proxy:代理对象

    Method:方法

    Args:方法参数

    MethodProxy:方法代理

    Return  返回代理逻辑

     

    测试类:

    package cglib;
    
    public class TestCglibProxy {
        public static void main(String[] args) {
            CglibProxyExample Cglib = new CglibProxyExample();
            Helloworld proxy = (Helloworld)Cglib.getProxy(Helloworld.class);
            proxy.sayHelloworld("fanl");
        }
    
    }

     

 

posted @ 2018-08-17 11:04  Mrfanl  阅读(196)  评论(0编辑  收藏  举报