就是当你写了一个接口,里面有方法,然后写了实现类实现方法,完成方法逻辑,然后有一天,想对这个方法进行修改,但是不想改源码,所以有两种方式可以实现。第一种是静态代理,创建一个类继承实现类,然后对方法进行修改,这样太局限,因为只能针对特定的类增强方法,有100个实现类就要创建100个子类去实现。第二种方式是动态代理,可以动态地生成代理类,这是可以接受的。
当现有的类的代码只能满足一些基本的功能,而这些功能满足不了新需求,但又不能改动以前的代码,这时候就可以考虑使用代理,通过代理类,扩展原有类的功能,客户端访问的入口只是聪目标对象切换到代理对象而已;
JDK动态代理是有JDK提供的工具类Proxy实现的,动态代理类是在运行时生成指定接口的代理类,每个代理实例(实现需要代理的接口)都有一个关联的调用处理程序对象,此对象实现了InvocationHandler,最终的业务逻辑是在InvocationHandler实现类的invoke方法上。
也即是在invoke方法上可以实现原方法中没有的业务逻辑,相当于spring aop的@Before、@After等注解。
为什么需要代理
1、原有功能增强
举例来说,当现有的类的代码只能满足一些基本的功能,而这些功能满足不了新需求,但又不能改动以前的代码,这时候就可以考虑使用代理,通过代理类,扩展原有类的功能,客户端访问的入口只是聪目标对象切换到代理对象而已;
2、降低耦合
在程序设计时,需要遵循一个叫做“单一职责”的原则,该原则要求每个类功能尽可能单一,为什么要单一,因为只有功能单一这个类被改动的可能性才会最小。
现在突然接到需求,需要对现有类的增删改这样的事务性操作增加审计日志,很多人第一想到的是给每个增删改的地方增加日志,如果这样的类特别多,这就很折腾了,比较好的办法就是,使用代理类,在不对原来类修改的基础上,进行日志功能的扩展即可(spring aop功能即是如此);
JDK 动态代理是基于拦截器和反射实现的,不需要第三方库支持,只需要 JDK 环境即可
必须实现 InvocationHandler 接口;
使用 Proxy.newProxyInstance 产生代理对象;
被代理的对象必须要实现接口;
内部采用asm技术动态生成字节码;
需要代理的接口
1. public interface Service { 2. void send(String msg); 3. }
代理类、
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class InvocationHandle<T> implements InvocationHandler { private T target; public InvocationHandle(T target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("之前执行"+method.getName()); Object invoke = method.invoke(target, args); System.out.println("之后执行"+method.getName()); return invoke; } }
获取代理对象的工厂类
import java.lang.reflect.Proxy; public class ProxyFactory { public static <T extends Service> Service getProxy(T target){ Class<? extends Service> aClass = target.getClass(); return (Service) Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),new InvocationHandle<>(target)); }//类加载获得应用类加载器,class文件可以任意 }
主函数
public class test { public static void main(String args[]) throws Exception { // Service proxy = ProxyFactory.getProxy(new Service() { // @Override // public void send(String msg) { // System.out.println(msg); // } // }); Service proxy = ProxyFactory.getProxy(msg -> System.out.println(msg)); proxy.send("hello"); } }