吃透动态代理,解密spring AOP源码(二)

少年阿涛 2019-07-01

紧接着上节,为了解决静态代理的问题,出现了动态代理, 假设动态代理是一个代购公司,私有变量Object factory为动态生成的具体的真实对象,可代购对应的产品 。代码:

/**
 * 动态代理
 */
public class DynamicProxyCompanyC implements InvocationHandler {

    // 被代理的对象,即真实对象
    private Object factory;

    public Object getFactory() {
        return factory;
    }

    public void setFactory(Object factory) {
        this.factory = factory;
    }

    // 通过proxy获取动态代理的对象
    public Object getProxyInstance() {
    //第三个参数是InvocationHandler,传入自身说明此proxy对象是和自身的invoke方法合作的,代理对象方法调用会经过下面invoke的增强


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

    @Override
     /**通过动态代理对象对方法进行增强
 *  @param proxy 代理对象
 *  @param method 要增强的方法(拦截的方法)
 *  @param args 方法参数
 */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        dosomeThingBefore();
        Object ret = method.invoke(factory, args);// 通过反射机制调用方法
        dosomeThingAfter();
        return ret;
    }

    public void dosomeThingBefore() {
        System.out.println("售前服务,负责产品调研,兴趣爱好");
    }

    public void dosomeThingAfter() {
        System.out.println("售后服务,包装丶送货上门一条龙服务");
    }
}

测试类:

public class Proxytest {

    public static void main(String[] args) {
        // 代购公司C,负责代购所有产品
        DynamicProxyCompanyC proxy = new DynamicProxyCompanyC();
        // 日本有家A公司生产男性用品
        ManToolFactory dogToolFactory = new AManFactory();
        // 代购A公司的产品
        proxy.setFactory(dogToolFactory);
        // 创建A公司的代理对象
        ManToolFactory proxyObject = (ManToolFactory) proxy.getProxyInstance();
        // 代理对象完成代购男性用品
        proxyObject.saleManTool("D");
        System.out.println("--------------");
        // 日本有家B公司生产女性用品
        WomanToolFactory womanToolFactory = new BWomanFactory();
        // 代购B公司的产品
        proxy.setFactory(womanToolFactory);
        // 创建B公司的代理对象
        WomanToolFactory proxyObject1 = (WomanToolFactory) proxy.getProxyInstance();
        // 代理对象完成代购女性用品
        proxyObject1.saleWomanTool(1.8);
    }
}
// 售前服务,负责产品调研,兴趣爱好
// A工厂出售男性用品,D罩杯
// 售后服务,包装丶送货上门一条龙服务
// --------------
// 售前服务,负责产品调研,兴趣爱好
// B工厂生产女性用品,长度1.8米
// 售后服务,包装丶送货上门一条龙服务
  • 动态代理解决了上节说的开闭原则,那么接下来我们要解密动态代理的原理,重点类DynamicProxyCompanyC

1.实现了InvocationHandler接口;

2.通过proxy获取动态代理的对象。

根据我们此例子里面来说,动态代理就类似一个代购公司,可代购所有产品,需要购买哪个产品的时候就实例化一个真实对象(如测试类需要男性用品则将接口引用指向真实对象AManFactory),根据真实对象创建代理对象来执行具体的方法,图解如下:

吃透动态代理,解密spring AOP源码(二)

吃透动态代理,解密spring AOP源码(二)

Proxy:

接下来我们先初步看一下JDK里面的Proxy这个源码。
这个注释是说Proxy提供个一个静态方法来创建代理类和代理实例,它也是所有由此方法创建的代理类的父类。
静态方法创建代理实例即方法newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h);

InvocationHandler :

InvocationHandler 是一个接口,定义了invoke(Object proxy, Method method, Object[] args)方法

总的来说Proxy专门负责new一个实例(真实对象),而具体方法做什么,业务怎样增强就由InvocationHandler(抽象对象)的invoke方法(抽象对象即接口定义的方法)来决定。

接下来我们要搞清楚动态代理的底层原理,首先我们调试一下test类,会发现 ManToolFactory proxyObject = (ManToolFactory) proxy.getProxyInstance()中创建的proxyObject 对象类名是$Proxy0,是ManToolFactory接口的实现类。但是我们项目工程里面却没有$Proxy0这个类,那它究竟是怎么出现的,下节讲解。

相关推荐