java动态代理(jdk动态代理和CGLIB动态代理)

1.什么是代理

根据原有对象生成一个占位(代理对象),然后由代理对象来代理真实对象,控制对真实对象的访问的操作就叫做代理。

2.代理的必要步骤

1)让代理对象和真实对象建立联系(建立关系的过程会生成代理对象,基于java反射)

2)实现代理对象的代理逻辑方法

3.代理的作用(好处)

4.常用的代理技术有哪些

1)JDK动态代理

2)CGLIB动态代理

5.JDK动态代理

1)代理功能由java.lang.reflect提供。实现一个简单的动态代理,需要原料有:

1.接口一个(被代理对象对应的接口)

2.普通类一个(被代理对象)

3.代理类一个(用于生成代理对象,并完成代理逻辑方法的实现),该类必须实现InvocationHandler接口,如下所示:

public class JdkProxyExample implements InvocationHandler {

    private Object target;//被代理的类对象

    public Object bind(Object target){

        this.target = target;

        //根据传入的对象(被代理对象)生成代理对象,newProxyInstance方法的三个参数分别为(被代理类的类加载器,被代理类的接口类型,InvocationHandler类型的对象)

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

    }

 

    /**

     * 代理逻辑的实现方法

     * @param proxy 代理对象

     * @param method 被代理的方法对象,类似于切面中被通知的方法

     * @param args 被代理方法传参

     * @return

     * @throws Throwable

     */

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("现在已经进入代理方法");

        System.out.println("先走一波代理逻辑,走完调用被代理对象的方法");

        //invoke方法传入了对象的引用已经方法的参数,具体调用哪个方法由method对象自己记录(自己知道自己是谁)

        Object object = method.invoke(target,args);

        System.out.println("成功完成被代理对象方法的调用");

        return object;

    }

}

类中,bind(代理类对象)方法用于实现代理类和真实对象之间建立联系,并生成代理类返回(代理类同样实现了真实对象实现的接口)。

invoke(代理对象,调用的方法对象,方法参数)方法为代理逻辑实现方法,当调用代理类方法时,就会进入invoke方法。也能在invoke方法中利用反射来调用真实对象(被代理对象)的方法。

接下来书写一个测试类进行测试

Public static void main(String[] arg){

JdkProxyExample jdkProxyExample = new JdkProxyExample();

//建立连接,返回代理对象

ProxyInterface proxy = (ProxyInterface)jdkProxyExample.bind(new ProxyTestImpl());

//调用代理逻辑

proxy.sayHello();

}

测试结果为:

可以代理对象在调用真实对象方法时,会主动调用代理类里面的代理逻辑。

 

需要注意的是jdk动态代理必须基于接口才能使用,如果类不存在接口,则类不能使用jdk动态代理进行代理。

 

 

6.CGLIB动态代理

同样是动态代理,不过和jdk动态代理不同之处在于,jdk需要接口(代理对象的类型是真实对象实现的所有的接口),而CGLIB却不需要接口,代理对象类型就是真实对象类本身。

首先,还是先定义代理对象类,CGLIB的代理类必须实现MethodInterceptor接口:

/**

 * CGLIB代理类

 */

public class CglibProxyExample implements MethodInterceptor {

    /**

     * 生成代理对象

     * @param cla 被代理的类

     * @return 代理对象

     */

    public Object bind(Class cla){

        //获取CGLIB增强类对象

        Enhancer enhancer = new Enhancer();

        //设置对哪个类进行增强

        enhancer.setSuperclass(cla);

        //设置哪个类为代理类,代理类必须实现MethodInterceptor接口

        enhancer.setCallback(this);

        //生成代理对象并返回(根据之前的设置来生成代理对象)

        return enhancer.create();

    }

    /**

     * 代理类逻辑方法

     * @param proxy 被代理对象

     * @param method 代理类执行的方法对象

     * @param args 方法传参

     * @param methodProxy 方法代理对象

     * @return 方法执行结果

     * @throws Throwable

     */

    @Override

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        System.out.println("开始执行代理类逻辑");

        System.out.println("执行完代理类逻辑,准备执行真实对象方法");

        //调用真实对象的方法

        Object result = methodProxy.invokeSuper(proxy,args);

        System.out.println("真实对象方法执行完毕");

        return null;

    }

}

bind方法同样为创建代理对象和真实对象之前的关联关系,并返回代理对象。

intercept为代理逻辑方法,代理类执行的所有方法都会执行该方法。

接着搞个简单的被代理类

Public class CglibTest{

Public void justSayHello(){

System.out.println("我打印啦!");

}

}

最后搞个测试类:

由于环境是spring boot的,所以搞的是spring boot test,

@RunWith(SpringRunner.class)

@SpringBootTest

public class JavaReflectTest {

    @Test

    public void cglibTest(){

        try{

            //创建代理类对象

            CglibProxyExample cglibProxyExample = new CglibProxyExample();

            //通过代理类获取CglibTest类的代理对象

            CglibTest cglibTest =(CglibTest)cglibProxyExample.bind(CglibTest.class);//绑定管理,确定代理哪个类

            //由代理类执行真实对象方法

            cglibTest.justSayHello();

        }catch(Exception e){

            e.printStackTrace();

        }

    }

}

最后启动程序,走一波:

 

可见,和jdk动态代理一样,用代理类执行方法时,触发的是代理类中的实现逻辑,从而实现了对类原方法的扩展(比如spring AOP)。

 

注:针对生成对象,new是静态编译,而反射是动态编译。静态编译会在一开始就把对象写入内存,而动态编译是在具体用到对象的时候才会在内存中创建对象。这样就能做到一个代理类去代理多个对象。

你可能感兴趣的:(学习)