在此之前先介绍一下静态代理:通过被代理类和代理类实现同个接口,在代理类中实例化被代理类,再加上代理方法,组成静态代理模式,缺点是每想要代理一个类就要写一个代理类,类过多;而且实现接口还必须实现接口的方法,冗余过多。
引入动态代理:通过反射,在运行时才进行相关代理,而不像静态代理在编译器就已经确定被代理的对象动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强动态代理不知道要代理什么东西,只有在运行时才知道动态代理是代理一个接口下的多个实现类。
动态代理优点:在编码时,代理逻辑与业务逻辑互相独立,各不影响,没有侵入,没有耦合,而静态代理接口增加一个方法代理类也得改。减少代理类的数量,只要同一接口下的类都可以使用同一个代理。

JDK动态代理实现

关于java动态代理的理解

JDK提供了java.lang.reflect.InvocationHandler(调用处理程序)接口和 java.lang.reflect.Proxy(代理)类,这两个类相互配合,入口是Proxy,所以我们先聊它。

Proxy有个静态方法:getProxyClass(ClassLoader, interfaces),只要你给它传入类加载器和一组接口,它就给你返回代理Class对象。
所以,一旦我们明确接口,完全可以通过接口的Class对象,创建一个代理Class,通过Class利用反射即可创建代理对象。
但是还有一个更方便的方法:newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h,下面会解释到三个参数的意思,改方法可以直接返回一个代理类的实例,直接给我们创建好的实例,即代理类的对象。

接下来看一下InvocationHandler 调用处理程序---- 接口的唯一一个方法 invoke

实际编程中,一般不用getProxyClass(),而是使用Proxy类的另一个静态方法:Proxy.newProxyInstance(),直接返回代理实例,连中间得到代理Class对象的过程都帮你隐藏:
/**

proxy:指代我们的代理类

method:指代的是我们所要调用真实对象的某个方法的Method对象

args:指代的是调用真实对象某个方法时接受的参数


*/
/*三个参数

loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

handler:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

*/


动态代理优点
相比之前的静态代理,我们可以发现,现在的调用代码多了一行。不过相较这多出来的一行,更令人兴奋的时,我们通过实用 jdk 为我们提供的动态代理实现,达到了我们的 cook() 或者 swap() 方法可以被任意的复用的效果(只要我们在调用代码处使用这个通用代理类去包装任意想要需要包装的被代理类即可)。 当接口改变的时候,虽然被代理类需要改变,但是我们的代理类却不用改变了。

缺点
我们可以看到,无论是静态代理还是动态代理,它都需要一个接口。那如果我们想要包装的方法,它就没有实现接口怎么办呢?这个问题问的好,JDK为我们提供的代理实现方案确实没法解决这个问题。。。那么怎么办呢?别急,接下来就是我们的终极大杀器,CGLib动态代理登场的时候了。

总结

1.动态代理就是在运行时动态生成对象,这个对象是用来代理方法的。

2.在这个动态代理对象的invoke方法中可以做任何操作。如果需要aop功能,则只需在invoke中加入被代理对象的方法和before、after方法即可。

CGLib动态代理

Enhancer的create也可以改成写在main函数中: