文章目录
- 静态代理
- Jdk动态代理
- cglib动态代理
- 使用案例
- 低配Mybatis
- 低配Feign
- 拦截器
- 附录代码
大家好,我是入错行的bug猫。(http://blog.csdn.net/qq_41399429,谢绝转载)
每天进步一点,今日再接再励~
动态代理在Java中有着广泛的应用,比如Spring AOP、Mybatis数据查询、RPC远程调用、性能监控,甚至事务处理等。
代理模式,根据代码的生成时机,分为两种:
- 静态代理:代码块在源码阶段已存在,经过编译之后生成在class文件中;
- 动态代理:代码块在运行过程中,根据运行环境参数决定代码如何生成,自动生成class字节码,然后再加载到JVM中;
所谓静态,也就是在程序运行前,就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就确定了。
而动态代理的源码,是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件。
而根据动态生成字节码的技术手段,又分两种:
- Jdk动态代理
- cglib动态代理
静态代理
先了解静态代理,然后理解静态代理的优缺点缺点,再来学习动态代理;
编写一个接口IUserService
,以及该接口的一个实现类UserService
interface IUserService {void findById(String uid);void update(Object user, String uid);
}class UserService implements IUserService {public void findById(String uid) {System.out.println("查询 findById");}public void update(Object user, String uid) {System.out.println("更新 update");}
}
通过静态代理对IUserService
已存在的实例,进行功能增强;在调用findById
和update
之前记录一些日志,模拟开启事务。
写一个代理类UserServiceProxy
,代理类需要实现IUserService
;整体结构有些类似装饰模式;
class UserServiceProxy implements IUserService {private final IUserService target; // 被代理的对象public UserServiceProxy() {this.target = new UserService(); //被代理对象,是在代理类中生成}@Overridepublic void findById(String uid) {try {before();target.findById(uid); // 这里才实际调用真实对象的方法after();} catch ( Exception ex ) {exception(ex);throw ex;}}@Overridepublic void update(Object user, String uid) {try {before();target.update(user, uid); // 这里才实际调用真实对象的方法after();} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}
客户端测试:
@Testpublic void demo1(){IUserService proxy = new UserServiceProxy();proxy.findById("1");System.out.println("");proxy.update(new Object(), "4");}
输出:
log start time [Sat Jun 17 09:34:05 CST 2023]
开启事务
查询 selectById
log end time [Sat Jun 17 09:34:05 CST 2023]
提交事务log start time [Sat Jun 17 09:34:05 CST 2023]
开启事务
更新 update
log end time [Sat Jun 17 09:34:05 CST 2023]
提交事务
通过静态代理,我们达到了功能增强的目的,而且没有侵入原代码,这是静态代理的一个优点。
静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来:
-
当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
1.1 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大;
1.2 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类 -
当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
如何改进?
可以发现,代理类的代码块流程绝大部分是相似的:在执行真实方法之前执行before
,在执行真实方法成功之后执行after
,发生异常执行exception
;
类似固定的模板,就可以使用程序来自动编写代码,用程序自动写程序,也就是动态代理。
哪些类可以动态生成代码?Enhancer
、InterfaceMaker
、BeanGenerator
有机会再单独写一篇
实现动态代理的思考方向:
为了让生成的代理类与目标对象保持一致性,从现在开始将介绍以下两种最常见的方式:
通过实现接口的方式:JDK动态代理
通过继承类的方式:CGLIB动态代理
Jdk动态代理
JDK动态代理主要涉及两个类:java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
编写一个调用逻辑处理器JdkProxyHandler
类,提供日志增强功能,并实现InvocationHandler
接口;
在JdkProxyHandler
中维护一个目标对象,这个对象是被代理的对象;在invoke
方法中编写方法调用的逻辑处理;
class JdkProxyHandler implements InvocationHandler {private final Object target; // 被代理的对象,实际的方法执行者public JdkProxyHandler(Object target) {this.target = target;}/*** @param proxy 代理对象实例 todo ①* @param method 被代理类的Interface中的方法; todo ②* @param args * */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {before();//反射调用 target 的 method 方法。//proxy是代理对象实例,因此在反射调用的时候,需要替换成被代理类target对象;Object result = method.invoke(target, args); after();return result; // 返回方法的执行结果} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}
编写客户端,获取动态生成的代理类的对象须借助java.lang.reflect.Proxy
类的newProxyInstance
方法:
@Testpublic void demo2(){// 设置变量可以保存动态代理类,默认名称以 $Proxy0 格式命名System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");// 1. 创建被代理的对象。实际代码中,可以使用到对象工厂IUserService userService = new UserService();// 2. 代理类请求处理器:拦截处理代理对象上的所有的方法调用。// 和demo1中的UserServiceProxy类相似。// 由于JdkProxyHandler可以复用,被代理类(userService)可以使多例,所以JdkProxyHandler也应该是多例,被代理类应该显示传入。// 主要JdkProxyHandler构造器使用Interface作为入参,因此JdkProxyHandler可以代理一切Interface的实现类。InvocationHandler proxyHandler = new JdkProxyHandler(userService);// 3. 获取对应的 ClassLoader。类加载机制,如果搞错ClassLoader,可能会导致动态生成的代理类,无法被加载:提示 ClassNotFoundException;保持和被代理类在一个ClassLoader中ClassLoader classLoader = userService.getClass().getClassLoader();// 4. 获取所有接口的Class,这里的UserService只实现了一个接口IUserService,Class[] interfaces = userService.getClass().getInterfaces();/*5.根据上面提供的信息,创建代理对象 在这个过程中,a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等相关字节码;b.然后根据相应的字节码转换成对应的class加载到JVM中;c.然后调用newInstance()创建代理实例;*/IUserService proxy = (IUserService) Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);//输出动态代理之后的class代码//generateClassFile(proxy.getClass(), "UserServiceProxy"); //在代码在文章最后// 调用代理的方法proxy.findById("3");System.out.println("");proxy.update(new Object(), "4");//JDK动态代理,底层本质是使用方法反射;性能瓶颈受Jdk版本影响}
执行之后可以查看动态生成的代理类:
//Jdk动态生成的类片段
public final class UserServiceProxy extends Proxy implements IUserService {private static Method m3;private static Method m4;//注意这个入参,就是JdkProxyHandlerpublic UserServiceProxy(InvocationHandler var1) throws {super(var1);}public final void findById(String var1) throws {try {//注意第一个参数this,即代表JdkProxyHandler.invoke的第一个入参,是代理类本身; todo ①//第二个参数m4,是从cn.bugcat.code.IUserService中获取 todo ②super.h.invoke(this, m4, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final void update(Object var1, String var2) throws {try {super.h.invoke(this, m3, new Object[]{var1, var2});} catch (RuntimeException | Error var4) {throw var4;} catch (Throwable var5) {throw new UndeclaredThrowableException(var5);}}static {try {//findById、update方法,都是从Interface(IUserService)中获取 todo ②m4 = Class.forName("cn.bugcat.code.IUserService").getMethod("findById", Class.forName("java.lang.String"));m3 = Class.forName("cn.bugcat.code.IUserService").getMethod("update", Class.forName("java.lang.Object"), Class.forName("java.lang.String"));} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}
UserServiceProxy
继承了Proxy类,并且实现了被代理的所有接口,以及equals、hashCode、toString等方法;- 由于
UserServiceProxy
继承了Proxy
类,所以每个代理类都会关联一个InvocationHandler
方法调用处理器; - 类和所有方法都被
public final
修饰,所以代理类只可被使用,不可以再被继承; - 每个方法都有一个Method对象来描述,Method对象在
static
静态代码块中创建,以m + 数字
的格式命名; - 调用方法的时候通过
super.h.invoke(this, m1, new Object[]{});
调用,其中的super.h.invoke
实际上是在创建代理的时候传递给Proxy.newProxyInstance
的 JdkProxyHandler对象,它继承InvocationHandler
类,负责实际的调用处理逻辑; - 而
JdkProxyHandler
的invoke方法接收到method、args等参数后,进行一些处理,然后通过反射让被代理的对象target执行方法;
仔细观察JdkProxyHandler
,构造器中入参使用Object类型接受,也就是意味JdkProxyHandler
类不光可以传入UserService
实现类,也可以传入其他任何对象实例;
Proxy.newProxyInstance
是根据第二个参数Interfaces动态生成方法,而这些方法恰好UserService
也实现了,代理类和具体类,通过interfaces
联系到一起;
最终执行JdkProxyHandler
构造器 入参对象的所有方法 ,都会统一执行JdkProxyHandler.invoke
代码。
cglib动态代理
spring 框架中内置了cglib
相关Jar包内容,spring项目可以直接使用:
被代理类:原对象;
代理子类:由cglib自动根据原对象生成的子类;
class CglibProxyHandler implements MethodInterceptor {/*** @param target 代理子类对象;* @param method 被代理类的方法;* @param args * @param methodProxy 被代理的句柄方法 todo ③* */@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {try {before();//注意这里是调用invokeSuper而不是invoke,否则死循环。 todo ③//method是被代理的方法,但是由于tagert是代理子类,执行method.invoke,实际上是表示执行代理子类的方法,代理子类又会继续执行MethodInterceptor.intercept方法,导致又回到此处代码,造成死循环;//此处应该直接执行invokeSuper,表示直接调用被代理类的句柄方法;Object result = methodProxy.invokeSuper(target, args); after();return result; // 返回方法的执行结果} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}
调用方式:
@Test public void demo3(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new CglibProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); // 设置超类,cglib是通过继承来实现的enhancer.setCallback(proxyHandler);IUserService userService = (IUserService)enhancer.create(); // 创建代理类userService.findById("4");userService.update(new Object(), "4");}
动态生成类片段:
public class UserService$$EnhancerByCGLIB$$a1b35990 extends UserService implements Factory {final void CGLIB$update$0(Object var1, String var2) {super.update(var1, var2); //调用父类方法 => UserService.update}public final void update(Object var1, String var2) { //代理类暴露的方法,等价于重写了父类UserService的update方法MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; // 实际上是我们自定义的CglibProxyHandler对象if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {// 第一个参数,代理类对象 todo ③// CGLIB$update$0$Method 父类对应的方法// CGLIB$update$0$Proxy当前代理的 CGLIB$update$0方法,该方法会继续调用父类的对应方法var10000.intercept(this, CGLIB$update$0$Method, new Object[]{var1, var2}, CGLIB$update$0$Proxy);} else {super.update(var1, var2);}}
}
Jdk动态代理与cglib动态代理对比
- Jdk动态代理:基于Java反射机制实现,必须要实现了接口的类,才能用这种办法生成代理对象。
- cglib动态代理:基于ASM机制实现,通过操作字节码生成子类,代理代码块集成在子类上,实际调用被代理类的方法时,和原生调用效率一样;
- cglib由于使用继承被代理实现,因此如果是类、方法被
final
修饰,则无法使用!被cglib代理的类,无法再次被代理! - Jdk不受
final
关键词影响;被代理之后,仍然可以被Jdk再次代理; - cglib在创建代理子类的时候,可以通过
CallbackFilter
,可以为每个方法创建单独的MethodInterceptor
;后续调用时,方法与方法之间,代码在物理层面隔离,互相不影响; - Jdk只能在
InvocationHandler
实现类中,需要自行做分支处理;
使用案例
低配Mybatis
interface UserDao {String findById(String uid);String update(Object user, String uid);
}class MapperProxyHandler implements MethodInterceptor {private static Map<String, Map<String, String>> mapperMap = new HashMap<>();static {//初始化,模拟Mapper.xml文件Map<String, String> mapper = new HashMap<>();//Map的key,及为UserDao中的方法名,以及Mapper.xml的标签idmapper.put("findById", "select * from user where id = ?");mapper.put("update", "update user set name = ? where id = ?");//UserDao.class.getName(),对应到Mapper.xml的namespacemapperMap.put(UserDao.class.getName(), mapper); }@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {String methodName = method.getName();Class<?> mapperClass = method.getDeclaringClass();Map<String, String> mapper = mapperMap.get(mapperClass.getName());if( mapper != null ){return mapper.get(methodName);}return null;}
}@Testpublic void demo4(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new MapperProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Object.class); // 设置超类;此时UserDao只是一个Interface,没有任何具体的实现类,因此超类设置为默认的Object;enhancer.setInterfaces(new Class[]{UserDao.class});enhancer.setCallback(proxyHandler);UserDao userDao = (UserDao)enhancer.create(); // 创建代理类String findById = userDao.findById("4");System.out.println(findById); //打印sqlString update = userDao.update(new Object(), "4");System.out.println(update);}
低配Feign
interface MyFeign {@RequestMapping(value = "http://127.0.0.1:8080/aq", method = RequestMethod.POST)ResponseEntity<Void> aq();@RequestMapping(value = "https://www.baidu.com/s", method = RequestMethod.GET)String baidu(@RequestParam("wd") String keyword);}class FeignProxyHandler implements MethodInterceptor {/*** target:代理子类* method:被代理类方法*/@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//method是被代理类中的方法,因此可以通过method获取到:方法上注解;入参列表;入参上的注解;方法的返回类型RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);RequestMethod[] requestMethods = requestMapping.method();String[] paths = requestMapping.value();Type returnType = method.getGenericReturnType();Parameter[] parameters = method.getParameters();Map<String, Integer> argsIndex = new HashMap<>();for ( int idx = 0; idx < parameters.length; idx++ ) {Parameter parameter = parameters[idx];RequestParam requestParam = AnnotationUtils.findAnnotation(parameter, RequestParam.class);argsIndex.put(requestParam.name(), idx);}Map<String, Object> reqMap = new HashMap<>();argsIndex.forEach((pname, idx) -> {reqMap.put(pname, args[idx]);});if( requestMethods[0] == RequestMethod.GET ){String resp = HttpFactory.mutate().doGet().send(paths[0], reqMap);return resultType(resp, returnType);} else if (requestMethods[0] == RequestMethod.POST ){String resp = HttpFactory.mutate().doPost().send(paths[0], reqMap);return resultType(resp,returnType);}return null;}private <R> R resultType(String resp, Type type){if( resp == null ){return null;}if( type instanceof Class ){if( String.class.isAssignableFrom((Class) type) ){return (R) resp;}}return JSONObject.parseObject(resp, type);}
}@Testpublic void demo5(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new FeignProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Object.class); // 设置超类;此时MyFeign只是一个Interface,没有任何具体的实现类,因此超类设置为默认的Object;enhancer.setInterfaces(new Class[]{MyFeign.class});enhancer.setCallback(proxyHandler);MyFeign feign = (MyFeign)enhancer.create(); // 创建代理类ResponseEntity<Void> aq = feign.aq();System.out.println(JSONObject.toJSONString(aq));String baidu = feign.baidu("csdn");System.out.println(baidu);}
拦截器
拦截器,不属于sevlet
、filter
这一类物理层面存在的组件,而是通过代码逻辑出来的一种代码结构;通过对动态代理学习,我们可以在Object result = method.invoke(target, args);
Object result = methodProxy.invokeSuper(target, args);
代码的前后,添加自定义的代码,增强被代理类方法;
但是,这部分属于核心代码JdkProxyHandler CglibProxyHandler,一般编写完之后,会统一存放在公共位置。如果业务模块想添加功能,势必需要修改到这部分核心代码;违背了支持扩展、封闭修改原则;
因此在此基础之上,逻辑出一套拦截器模式,对业务模块开放修改;
//切入点对象
class Point {private final Object target;private final Method method;private final Object[] args;private final MethodProxy methodProxy;public Point(Object target, Method method, Object[] args, MethodProxy methodProxy) {this.target = target;this.method = method;this.args = args;this.methodProxy = methodProxy;}public Object postHandle() throws Throwable{Object result = methodProxy.invokeSuper(target, args);return result;}
}//拦截器接口
interface MyInterceptor {default Object doInterceptor(Point point) throws Throwable {return point.postHandle();}
}class MyProxyHandler implements MethodInterceptor {private final MyInterceptor interceptor;public MyProxyHandler(MyInterceptor interceptor) {this.interceptor = interceptor;}@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//注意,本应该在此处执行的「Object result = methodProxy.invokeSuper(target, args);」,被转移到Point#postHandle方法内了 todo ⑤Point point = new Point(target, method, args, methodProxy);return interceptor.doInterceptor(point);}
}@Testpublic void demo6() {MyInterceptor interceptor = new MyInterceptor(){@Overridepublic Object doInterceptor(Point point ) throws Throwable {try {System.out.println("befor");Object resp = point.postHandle(); //在此处,才真正执行被代理类的方法 todo ⑤;//本应该在MethodInterceptor子类中执行的代码,被转移到MyInterceptor子类了;MethodInterceptor子类只能有一个,但是MyInterceptor子类,结合责任链设计模式,却可以有很多个!System.out.println("success");return resp;} catch ( Throwable e ) {System.out.println("error");throw e;} finally {System.out.println("finally");}}};MethodInterceptor proxyHandler = new MyProxyHandler(interceptor);Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); // 设置超类,cglib是通过继承来实现的enhancer.setCallback(proxyHandler);IUserService userService = (IUserService)enhancer.create(); // 创建代理类userService.findById("4");userService.update(new Object(), "4");}
可用来动态生成代码的有很多,这里推荐cglib的Enhancer
、InterfaceMaker
、BeanGenerator
、ClassWriter
类;
毕竟现在基本上都是spring全家桶,而且cglib也被spring收编,只要是spring项目就可以直接使用;
动态代理也是面试必考:涉及到AOP、拦截器;而AOP的运用又是不胜枚举,拦截器结合责任链模式,也是在各种场所都用运用;
以上,就酱~
~the end~
附录代码
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import sun.misc.ProxyGenerator;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class ProxyDemo {private static String paths = "E:\\tmp\\proxy\\";/*** 将根据类信息动态生成的二进制字节码保存到硬盘中,默认的是clazz目录下* params: clazz 需要生成动态代理类的类* proxyName: 为动态生成的代理类的名称*/public static void generateClassFile(Class clazz, String proxyName) {try {File file = new File(paths);FileUtils.deleteDirectory(new File(paths));file.mkdirs();} catch ( IOException e ) {e.printStackTrace();}// 根据类信息和提供的代理类名称,生成字节码byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());try (FileOutputStream out = new FileOutputStream(paths + proxyName + ".class")){out.write(classFile);out.flush();} catch (Exception e) {e.printStackTrace();}}@Testpublic void demo1(){IUserService proxy = new UserServiceProxy();proxy.findById("1");System.out.println("");proxy.update(new Object(), "4");}@Testpublic void demo2(){// 设置变量可以保存动态代理类,默认名称以 $Proxy0 格式命名System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");// 1. 创建被代理的对象。实际代码中,可以使用到对象工厂IUserService userService = new UserService();// 2. 代理类请求处理器:拦截处理代理对象上的所有的方法调用。// 和demo1中的UserServiceProxy类相似。// 由于JdkProxyHandler可以复用,被代理类(userService)可以使多例,所以JdkProxyHandler也应该是多例,被代理类应该显示传入。// 主要JdkProxyHandler构造器使用Interface作为入参,因此JdkProxyHandler可以代理一切Interface的实现类。InvocationHandler proxyHandler = new JdkProxyHandler(userService);// 3. 获取对应的 ClassLoader。类加载机制,如果搞错ClassLoader,可能会导致动态生成的代理类,无法被加载:提示 ClassNotFoundException;保持和被代理类在一个ClassLoader中ClassLoader classLoader = userService.getClass().getClassLoader();// 4. 获取所有接口的Class,这里的UserService只实现了一个接口IUserService,Class[] interfaces = userService.getClass().getInterfaces();/*5.根据上面提供的信息,创建代理对象 在这个过程中,a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等相关字节码;b.然后根据相应的字节码转换成对应的class加载到JVM中;c.然后调用newInstance()创建代理实例;*/IUserService proxy = (IUserService) Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);//输出动态代理之后的class代码//generateClassFile(proxy.getClass(), "UserServiceProxy"); //在代码在文章最后// 调用代理的方法proxy.findById("3");System.out.println("");proxy.update(new Object(), "4");//JDK动态代理,底层本质是使用方法反射;性能瓶颈受Jdk版本影响}@Test public void demo3(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new CglibProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); // 设置超类,cglib是通过继承来实现的enhancer.setCallback(proxyHandler);IUserService userService = (IUserService)enhancer.create(); // 创建代理类userService.findById("4");userService.update(new Object(), "4");}@Testpublic void demo4(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new MapperProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Object.class); // 设置超类;此时UserDao只是一个Interface,没有任何具体的实现类,因此超类设置为默认的Object;enhancer.setInterfaces(new Class[]{UserDao.class});enhancer.setCallback(proxyHandler);UserDao userDao = (UserDao)enhancer.create(); // 创建代理类String findById = userDao.findById("4");System.out.println(findById); //打印sqlString update = userDao.update(new Object(), "4");System.out.println(update);}@Testpublic void demo5(){System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, paths);MethodInterceptor proxyHandler = new FeignProxyHandler();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Object.class); // 设置超类;此时MyFeign只是一个Interface,没有任何具体的实现类,因此超类设置为默认的Object;enhancer.setInterfaces(new Class[]{MyFeign.class});enhancer.setCallback(proxyHandler);MyFeign feign = (MyFeign)enhancer.create(); // 创建代理类ResponseEntity<Void> aq = feign.aq();System.out.println(JSONObject.toJSONString(aq));String baidu = feign.baidu("csdn");System.out.println(baidu);}@Testpublic void demo6() {MyInterceptor interceptor = new MyInterceptor(){@Overridepublic Object doInterceptor(Point point ) throws Throwable {try {System.out.println("befor");Object resp = point.postHandle(); //在此处,才真正执行被代理类的方法 todo ⑤;//本应该在MethodInterceptor子类中执行的代码,被转移到MyInterceptor子类了;MethodInterceptor子类只能有一个,但是MyInterceptor子类,结合责任链设计模式,却可以有很多个!System.out.println("success");return resp;} catch ( Throwable e ) {System.out.println("error");throw e;} finally {System.out.println("finally");}}};MethodInterceptor proxyHandler = new MyProxyHandler(interceptor);Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); // 设置超类,cglib是通过继承来实现的enhancer.setCallback(proxyHandler);IUserService userService = (IUserService)enhancer.create(); // 创建代理类userService.findById("4");userService.update(new Object(), "4");}}interface IUserService {void findById(String uid);void update(Object user, String uid);
}class UserService implements IUserService {public void findById(String uid) {System.out.println("查询 findById");}public void update(Object user, String uid) {System.out.println("更新 update");}
}class UserServiceProxy implements IUserService {private final IUserService target; // 被代理的对象public UserServiceProxy() {this.target = new UserService(); //被代理对象,是在代理类中生成}@Overridepublic void findById(String uid) {try {before();target.findById(uid); // 这里才实际调用真实对象的方法after();} catch ( Exception ex ) {exception(ex);throw ex;}}@Overridepublic void update(Object user, String uid) {try {before();target.update(user, uid); // 这里才实际调用真实对象的方法after();} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}class JdkProxyHandler implements InvocationHandler {private final Object target; // 被代理的对象,实际的方法执行者public JdkProxyHandler(Object target) {this.target = target;}/*** @param proxy 代理对象实例 todo ①* @param method 被代理类的Interface中的方法; todo ②* @param args * */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {before();//反射调用 target 的 method 方法。//proxy是代理对象实例,因此在反射调用的时候,需要替换成被代理类target对象;Object result = method.invoke(target, args);after();return result; // 返回方法的执行结果} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}class CglibProxyHandler implements MethodInterceptor {/*** @param target 代理子类对象;* @param method 被代理类的方法;* @param args * @param methodProxy 被代理的句柄方法 todo ③* */@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {try {before();//注意这里是调用invokeSuper而不是invoke,否则死循环。 todo ③//method是被代理的方法,但是由于tagert是代理子类,执行method.invoke,实际上是表示执行代理子类的方法,代理子类又会继续执行MethodInterceptor.intercept方法,导致又回到此处代码,造成死循环;//此处应该直接执行invokeSuper,表示直接调用被代理类的句柄方法;Object result = methodProxy.invokeSuper(target, args);after();return result; // 返回方法的执行结果} catch ( Exception ex ) {exception(ex);throw ex;}}private void before() { // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));System.out.println("开启事务");}private void after() { // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));System.out.println("提交事务");}private void exception(Exception ex){System.out.println(String.format("log error [%s] ", ex.getMessage()));System.out.println("提交回滚");}
}interface MyProxyInterceptor {boolean preHandler();void before();void after();void exception(Exception ex);
}class CglibProxyHandler1 implements MethodInterceptor {private final List<MyProxyInterceptor> interceptors; // 100public CglibProxyHandler1(List<MyProxyInterceptor> interceptors) {this.interceptors = interceptors;}@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//2List<MyProxyInterceptor> interceptors = this.interceptors.stream().filter(interceptor -> interceptor.preHandler()).collect(Collectors.toList());try {interceptors.forEach(intercept -> {intercept.before();});Object result = methodProxy.invokeSuper(target, args);interceptors.forEach(intercept -> {intercept.after();});return result; // 返回方法的执行结果} catch ( Exception ex ) {interceptors.forEach(intercept -> {intercept.exception(ex);});throw ex;}}
}interface UserDao {String findById(String uid);String update(Object user, String uid);
}class MapperProxyHandler implements MethodInterceptor {private static Map<String, Map<String, String>> mapperMap = new HashMap<>();static {//初始化,模拟Mapper.xml文件Map<String, String> mapper = new HashMap<>();//Map的key,及为UserDao中的方法名,以及Mapper.xml的标签idmapper.put("findById", "select * from user where id = ?");mapper.put("update", "update user set name = ? where id = ?");//UserDao.class.getName(),对应到Mapper.xml的namespacemapperMap.put(UserDao.class.getName(), mapper);}@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {String methodName = method.getName();Class<?> mapperClass = method.getDeclaringClass();Map<String, String> mapper = mapperMap.get(mapperClass.getName());if( mapper != null ){return mapper.get(methodName);}return null;}
}interface MyFeign {@RequestMapping(value = "http://127.0.0.1:8080/aq", method = RequestMethod.POST)ResponseEntity<Void> aq();@RequestMapping(value = "https://www.baidu.com/s", method = RequestMethod.GET)String baidu(@RequestParam("wd") String keyword);}class FeignProxyHandler implements MethodInterceptor {/*** target:代理子类* method:被代理类方法*/@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//method是被代理类中的方法,因此可以通过method获取到:方法上注解;入参列表;入参上的注解;方法的返回类型RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);RequestMethod[] requestMethods = requestMapping.method();String[] paths = requestMapping.value();Type returnType = method.getGenericReturnType();Parameter[] parameters = method.getParameters();Map<String, Integer> argsIndex = new HashMap<>();for ( int idx = 0; idx < parameters.length; idx++ ) {Parameter parameter = parameters[idx];RequestParam requestParam = AnnotationUtils.findAnnotation(parameter, RequestParam.class);argsIndex.put(requestParam.name(), idx);}Map<String, Object> reqMap = new HashMap<>();argsIndex.forEach((pname, idx) -> {reqMap.put(pname, args[idx]);});RestTemplate rest = new RestTemplate();if( requestMethods[0] == RequestMethod.GET ){String resp = rest.getForObject(paths[0], String.class, reqMap);return resultType(resp, returnType);} else if (requestMethods[0] == RequestMethod.POST ){String resp = rest.postForObject(paths[0], reqMap, String.class);return resultType(resp,returnType);}return null;}private <R> R resultType(String resp, Type type){if( resp == null ){return null;}if( type instanceof Class ){if( String.class.isAssignableFrom((Class) type) ){return (R) resp;}}return JSONObject.parseObject(resp, type);}
}class Point {private final Object target;private final Method method;private final Object[] args;private final MethodProxy methodProxy;public Point(Object target, Method method, Object[] args, MethodProxy methodProxy) {this.target = target;this.method = method;this.args = args;this.methodProxy = methodProxy;}public Object postHandle() throws Throwable{Object result = methodProxy.invokeSuper(target, args);return result;}
}//拦截器接口
interface MyInterceptor {default Object doInterceptor(Point point) throws Throwable {return point.postHandle();}
}class MyProxyHandler implements MethodInterceptor {private final MyInterceptor interceptor;public MyProxyHandler(MyInterceptor interceptor) {this.interceptor = interceptor;}@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//注意,本应该在此处执行的[Object result = methodProxy.invokeSuper(target, args);],被转移到Point#postHandle方法内了 todo ⑤Point point = new Point(target, method, args, methodProxy);return interceptor.doInterceptor(point);}
}