动态代理主要解决一个问题:面向切面编程aop
如:日志、探针监控/mybatis的实现原理
动态代理原理一句话描述:
首先需要依赖一个interface,然后需要一个增强器hander,然后需要一个proxy根据素材去动态的实现这个接口。
- interface:是动态代理的对象
- hander:是怎么样去增强这个代理对象被调用的方法。
- proxy:是一个调度,告诉JVM在运行期动态用什么素材(interface和hander等)创建实现类的class字节码并加载的过程,以供调用,默认是注入到内存里面,不生成具体的.class文件(可以修改配置参数让其生成)
直接上demo
->接口类
package com.example.demo.proxy;public interface Animal { void eat(String s); }
->实现类
package com.example.demo.proxy;public class Cat implements Animal { public void eat(String s) { System.out.println("hello world"); } }
->增强handler
package com.example.demo.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class Handler implements InvocationHandler { private Animal animal; public Handler() { super(); } public Handler(Animal animal) { super(); this.animal = animal; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.printf("前置增强\n"); System.out.printf(method.getName() + " " + args[0]+"\n"); if (this.animal != null) { method.invoke(animal, args); } System.out.printf("后置增强\n==========================\n"); return null; } }
->测试
package com.example.demo.proxy;import java.lang.reflect.Proxy;public class Test { public static void main(String[] args) throws NoSuchMethodException { //接口类的动态代理,让接口也可以实例化并调用接口方法并实现方法增强 InvocationHandler handler1 = new Handler(); Animal proxy1 = (Animal) Proxy.newProxyInstance( Animal.class.getClassLoader(), new Class[] { Animal.class }, handler1); proxy1.eat("meat"); //实现类的动态代理并实现方法增强 Animal animal = new Cat(); InvocationHandler handler2 = new Handler(animal); Animal proxy2 = (Animal) Proxy.newProxyInstance( Animal.class.getClassLoader(), // 传入ClassLoader,确定要用哪个加载器来加载.class new Class[] { Animal.class }, // 传入要实现的接口,这里也意味这这种方式,只能支持接口或者实现类的动态代理。 handler2); // 传入处理调用方法的InvocationHandler,核心方法,在实例化这个接口的时候,重写类方法,用来增强类方法的逻辑依据。 //如果hander里面没有传入接口的实例,则只增强这个空的接口方法。例如mybatis的动态代理,实现dao接口层和mapper.xml的绑定。 //如果hander里面有传入接口的实例,则可以在这个增强逻辑里面调用这个实例方法,实现aop注入。 proxy2.eat("meat"); } }
->结果