文章来自我的个人笔记,可以移步到 -> 创造者MC的个人笔记 继续浏览
前言
在使用 SpingAOP 时接触到了代理,觉得非常神奇,明明没有在目标类中添加代码,却能在方法执行前后编写额外代码。
多数文章没有把代理真正讲明白,我看了一些文章后进行了汇总,明白了代理的本质。
图解代理模式
静态代理和动态代理的区别和联系
区别
静态代理:自己写代理类,自己创建代理类的对象。
动态代理:利用 ASM 动态生成代理类并创建代理类的对象。
联系
静态代理和动态代理的原理都是组合或继承!
JDK 动态代理使用组合方式实现。
CGLIB 动态代理使用继承方式实现。
测试代码
把图中的测试代码贴到下方,大家可以自己去尝试。
静态代理
继承
class Eat { public void eat() { System.out.println("吃饭"); } } public class EatProxy extends Eat { @Override public void eat() { System.out.println("饭前"); super.eat(); System.out.println("饭后"); } public static void main(String[] args) { // 这里的类型与图里的不一样,改成父类了,大家可以好好感受一下多态。 Eat eatProxy = new EatProxy(); eatProxy.eat(); } }
组合
interface Fly { void fly(); } class Bird implements Fly { @Override public void fly() { System.out.println("鸟在飞"); } } class Plane implements Fly { @Override public void fly() { System.out.println("飞机在飞"); } } public class FlyProxy implements Fly{ private Fly fly; public FlyProxy(Fly fly) { this.fly = fly; } @Override public void fly() { System.out.println("飞之前"); fly.fly(); System.out.println("飞之后"); } } class Test { public static void main(String[] args) { Fly fly = new FlyProxy(new Bird()); fly.fly(); fly = new FlyProxy(new Plane()); fly.fly(); } }
动态代理
JDK 动态代理
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Work { void work(); } class JavaEngineer implements Work { @Override public void work() { System.out.println("IDEA 启动!"); } } class WorkProxy implements InvocationHandler { private Work work; public WorkProxy(Work work) { this.work = work; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法:" + method.getName() + "() 执行前"); Object invoke = method.invoke(work, args); System.out.println("方法:" + method.getName() + "() 执行后"); return invoke; } } public class JDKProxy { public static void main(String[] args) { // 把下方注释掉的代码去掉注释,可以在执行后得到生成类的 .class 文件,用 IDEA 打开即可通过 IDEA 的反编译查看生成的具体类的内容(JDK 1.8)。 // System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); JavaEngineer javaEngineer = new JavaEngineer(); /* 参数一: 被代理类的 CLass 对象 参数二:接口类的 Class 对象。被代理对象所实现的接口 参数三:调用处理器。被调用对象的那个方法被调用后该如何处理 */ Work work = (Work) Proxy.newProxyInstance(JavaEngineer.class.getClassLoader(), new Class[]{Work.class}, new WorkProxy(javaEngineer)); work.work(); } }
CGLIB 动态代理
注意:需要先引入依赖!
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; class MinecraftPlayer { public void play() { System.out.println("玩 Minecraft"); } } class PlayerProxy implements MethodInterceptor { // 代理对象 private Object object; public PlayerProxy(Object target) { // 创建加强器,用来创建动态代理类 Enhancer enhancer = new Enhancer(); // 为加强器指定要代理的业务类(为下面要生成的代理类指定父类) enhancer.setSuperclass(target.getClass()); // 设置回调对象,对于代理类上的所有的方法调用,都会调用 CallBack,而 CallBack 需要实现 intercept 方法进行拦截 enhancer.setCallback(this); // 创建动态代理类的对象 object = enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("方法:" + method.getName() + "() 执行之前"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("方法:" + method.getName() + "() 执行之后"); return result; } public Object getObject() { return object; } } public class CGLIBProxy { public static void main(String[] args) { PlayerProxy playerProxy = new PlayerProxy(new MinecraftPlayer()); MinecraftPlayer minecraftPlayer = (MinecraftPlayer) playerProxy.getObject(); minecraftPlayer.play(); } }