概念
- 动态产生代理,实现对不同类,不同方法的代理
- 动态代理实现可采用:JDK动态代理和cglib产生代理(spring采用cglib继承方式实现动态代理)
JDK动态代理
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
- Interface InvocationHandler:该接口仅定义了一个方法
public Object invoke(Object proxy, Method method, Object[] args)
proxy:代理类
method:被代理的方法
args:该方法的参数数组
- Proxy:该类即为动态代理类
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在接口中声明过的方法)
-
所谓Dynamic Proxy是在运行时生成的class,该class需要实现一组interface,使用jdk动态代理类时,必须要实现InvocationHandler接口
-
只能代理实现了接口的类
-
没有实现接口的类不能实现JDK的动态代理
cglib动态代理
cglib包介绍
代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(mock)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(mock)对象。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
cglib代码包结构
-
core (核心代码)
EmitUtils
ReflectUtils
KeyFactory
ClassEmitter/CodeEmitter
NamingPolicy/DefaultNamingPolicy
GeneratorStrategy/DefaultGeneratorStrategy
DebuggingClassWriter
ClassGenerator/AbstractClassGenerator
-
beans (bean操作类)
BeanCopier
BulkBean
BeanMap
ImmutableBean
BeanGenerator
-
reflect
FastClass
-
proxy
MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)
Enhancer
CallbackGenerator
Callback
CallbackFilter
-
util
StringSwitcher
ParallelSorter
-
transform
代码实现
业务需求
业务要求对已有的http api请求的接口:实现对请求的url和请求结果记录日志
- HttpApi 接口定义
package cn.tswine.dp.proxy; /** * @Author: silly * @Date: 2020/1/31 20:44 * @Version 1.0 * @Desc */ public interface HttpApi { String request(String url); } 复制代码
- RealHttpApi业务实现类
public class RealHttpApi implements HttpApi { @Override public String request(String url) { try { //模拟请求的时间 Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } //模式返回结果 return "success"; } } 复制代码
JDK动态代理实现
- 实现步骤
1.创建一个实现接口InvocationHandler 的类,必须实现invoke方法
2.创建被代理的类以及接口
3.调用Proxy的静态方法,创建一个代理类newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
4.通过代理调用方法
- LogInvocationHandler
/** * 实现打印日志事务 */ public class LogInvocationHandler implements InvocationHandler { private Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("request params:" + (args == null ? "" : Arrays.toString(args))); Object invoke = method.invoke(target, args); System.out.println("response :" + (invoke == null ? "NULL" : invoke.toString())); return invoke; } } 复制代码
- Client
/** * 客户端 */ public class Client { public static void main(String[] args) { String url = "https://www.csdn.net"; RealHttpApi realHttpApi = new RealHttpApi(); InvocationHandler invocationHandler = new LogInvocationHandler(realHttpApi); HttpApi httpApiProxy = (HttpApi) Proxy.newProxyInstance(realHttpApi.getClass().getClassLoader(), realHttpApi.getClass().getInterfaces(), invocationHandler); httpApiProxy.request(url); } } 复制代码
cglib动态代理实现
- 引入cglib包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> 复制代码
- CglibProxy
/** * cglib代理类 */ public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); /** * 获取代理类 * * @param clazz * @return */ public Object getProxy(Class clazz) { //设置创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //创建子类的实例 return enhancer.create(); } /** * 拦截所有目标类方法的调用 * * @param obj 目标类的实例 * @param method 目标方法的反射对象 * @param args 方法的参数 * @param methodProxy 代理类的实例方法 * @return * @throws Throwable */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("request params:" + (args == null ? "" : Arrays.toString(args))); //代理类调用父类的方法 Object invoke = methodProxy.invokeSuper(obj, args); System.out.println("response :" + (invoke == null ? "NULL" : invoke.toString())); return invoke; } } 复制代码