Java动态代理

Java动态代理的实现方式主要有两种:

   1、基于JDK的动态代理:动态代理类和被代理类必须继承相同的接口(没有实现接口的类,无法通过这种方式实现动态代理。所以也称基于接口的动态代理)

   2、基于CGLIB的动态代理:没有上面的限制

在业务中使用动态代理,一般是为了给需要实现的方法添加预处理或者后续操作,同时又不干预原先的业务实现。    把一些基本业务和主要的业务逻辑分离,Spring的AOP就是基于动态代理实现的

 

关于动态代理或者说AOP的好处:在业务处理代码中,通常都有日志记录、性能统计、安全控制、事务处理、异常处理等操作,尽管使用OOP(面向对象),可以通过封装或继承达到代码的重用,但仍然存在同样的代码分散到各个方法中。为了解决此类问题,AOP(面向切面)诞生了,它采取横向抽取机制,将分散在各个方法中的重复代码抽取出来,然后再程序编译或运行阶段,再将这些抽取出来的代码应用到需要执行的地方。这种横向抽取机制,是OOP无法做到的,因为OOP实现的是父子关系的纵向继承,而AOP则对OOP的缺陷做了补充,两者相辅相成。

 

下面进入正题


1、基于JDK的动态代理

基于JDK的动态代理是通过两个类      1、InvocationHandler(调用处理 接口)   2、Proxy(代理 类)         来实现的

 实现基于JDK的动态代理               首先要创建具有一定功能的接口,然后创建接口的实现类(也就是被代理类)

譬如,我们假设周杰伦要开演唱会了             为了实现这一逻辑,我需要创建一个歌手接口Singer,接口里有演唱的方法sing。之后我们为这个接口创建一个实现类(也就是我们的被代理类)ZhouJielun

代码如下:

interface Singer{
    void sing();
}
//接口实现类(也就是被代理类)
class ZhouJielun implements Singer{
    @Override
    public void sing() {
        System.out.println("周杰伦在演唱会进行演唱");
    }
}

在开演唱会之前,造型师势必会对他的造型进行修理,这个过程是必须的,而这个过程它不由歌手本人负责,因为每个人的精力都是有限的。这个逻辑换成工作开发就是什么呢?每个人都负责一定的功能模块,如果一个人负责过多的任务,那么就很有可能出现各种各样的问题,同时也会造成各种功能代码耦合在一起,不便于维护。         希望这个解释帮助大家更清晰的认识到AOP的好处。

接着说如何实现动态代理,现在,接口创建好了,被代理的类也创建好了 ,之后我们创建一个代理工厂。

这就需要用到上面说的 InvocationHandler接口 和 Proxy 类了(先贴代码,再说流程)

首先,我们创建一个MyInvocationHandler类并实现InvocationHandler接口,代码如下:

class MyInvocationHandler implements InvocationHandler {
    //这是 被代理类的对象
    private Object obj;

    //捆绑方法:将被代理的对象捆绑到 MyInvocationHandler(调用处理器) 类
    //当然,该操作也可以在构造函数中完成
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过”代理对象“调用方法时,就会自动调用如下方法:invoke()
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为要调用的被代理类的方法
        //args:即为要调用方法的参数

        doBefore();
        //调用被代理类中的方法
        Object returnValue = method.invoke(obj,args);
        doAfter();

        return returnValue;
    }
    //需要插入的前置代码
    private void doBefore(){
        System.out.println("造型师帮助化妆");
    }
    //需要插入的后置代码
    private void doAfter(){
        System.out.println("造型师帮助卸妆");
    }
}

接着创建一个代理工厂类,代码如下:

class ProxyFactory{
    public static Object getProxyInstance(Object obj){
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}

在main方法中测试一下:

public class ProxyTest {
    public static void main(String[] args) {
        ZhouJielun zhouJielun = new ZhouJielun();
        Singer proxyInstance = (Singer) ProxyFactory.getProxyInstance(zhouJielun);
        proxyInstance.sing();
    }
}

简单说一下整个过程:在Proxy类中有一个静态方法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h),它需要传入一个类加载器,一个代表对象实现接口的Class数组,一个调用处理器,然后返回一个实现了所有传入接口代理对象。           在上面的代码中,我们选择创建了一个代理工厂,它的静态方法可以根据接受的对象,返回需要的代理类。       

InvocationHandler顾名思义,就是调用处理器。   就是它完成了额外功能的插入:它里面内置了一个被代理类的对象 和 一个invoke()方法,当我们通过代理类调用任意方法时,都会调用invoke()方法。       它的代码逻辑很简单:通过反射调用被代理对象的同名方法,而我们在原方法执行前后,可以插入一些其他代码。        比如在执行这段方法前,进行日志记录。     这样一来,成功将不同的功能分离,使得代码更加易于阅读。


2、基于CGLIB的动态代理

还没学

posted @ 2020-09-10 09:07  leatral  阅读(247)  评论(0编辑  收藏  举报