电子商务网站建设实践报告,iis7wordpress,高端网站建设设计公司排名,图床外链生成工具文章目录 静态代理Jdk动态代理cglib动态代理使用案例低配Mybatis低配Feign拦截器 附录代码 大家好#xff0c;我是入错行的bug猫。#xff08;http://blog.csdn.net/qq_41399429#xff0c;谢绝转载#xff09; 每天进步一点#xff0c;今日再接再励~ 动态代理在Java中有着… 文章目录 静态代理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只实现了一个接口IUserServiceClass[] 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方法都是从InterfaceIUserService中获取 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 MapString, MapString, String mapperMap new HashMap();static {//初始化模拟Mapper.xml文件MapString, 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();MapString, 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没有任何具体的实现类因此超类设置为默认的Objectenhancer.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)ResponseEntityVoid 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();MapString, 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);}MapString, 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没有任何具体的实现类因此超类设置为默认的Objectenhancer.setInterfaces(new Class[]{MyFeign.class});enhancer.setCallback(proxyHandler);MyFeign feign (MyFeign)enhancer.create(); // 创建代理类ResponseEntityVoid 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只实现了一个接口IUserServiceClass[] 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没有任何具体的实现类因此超类设置为默认的Objectenhancer.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没有任何具体的实现类因此超类设置为默认的Objectenhancer.setInterfaces(new Class[]{MyFeign.class});enhancer.setCallback(proxyHandler);MyFeign feign (MyFeign)enhancer.create(); // 创建代理类ResponseEntityVoid 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 ListMyProxyInterceptor interceptors; // 100public CglibProxyHandler1(ListMyProxyInterceptor interceptors) {this.interceptors interceptors;}Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//2ListMyProxyInterceptor 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 MapString, MapString, String mapperMap new HashMap();static {//初始化模拟Mapper.xml文件MapString, 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();MapString, 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)ResponseEntityVoid 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();MapString, 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);}MapString, 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);}
}