1.引入依赖102
CGLIB既可以代理界面,也可以代理类别。底层是通过继承来实现的。因此,代理的目标类别不能用final来修改。
使用CGLIB,需要引入其依赖性:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version></dependency>
2.具体实现102我们准备了一个未实现接口的类别,如下:
package com.powernode.proxy.service;/** * 目标类 动态代理CGLIB 102 **/public class UserService { // 目标方法 public boolean login(String username, String password){ System.out.println(”系统正在验证身份..."); if ("admin".equals(username) && "123".equals(password)) { return true; } return false; } // 目标方法 public void logout(){ System.out.println(”系统正在退出..."); }}
在内存中使用CGLIB为UserService类生成代理类,并创建对象:
package com.powernode.proxy.client;import com.powernode.proxy.service.TimerMethodInterceptor;import com.powernode.proxy.service.UserService;import net.sf.cglib.proxy.Enhancer;///// 102public class Client { public static void main(String[] args) { // 创建字节码增强器对象 // 这个对象是CGLIB库的核心对象,依靠它来生成代理类。 Enhancer enhancer = new Enhancer(); // 告诉CGLIB父类是谁。 Enhancer enhancer = new Enhancer(); // 告诉CGLIB父类是谁。告诉CGLIB目标类是谁。 enhancer.setSuperclass(UserService.class); // 设置回调(相当于JDK动态代理中的调用处理器。InvocationHandler) // InvocationHandler接口不在CGLIB中,方法拦截器接口:MethodInterceptor enhancer.setCallback(new TimerMethodInterceptor()); // 创建代理对象 // 这一步将做两件事: // 第一件事:在内存中生成UserService子类,其实是代理类的字节码。 // 第二件事:创建代理对象。 // 父类是UserService,代理类子类必须是UserService UserService userServiceProxy = (UserService) enhancer.create(); // 建议您对CGLIB动态代理生成的代理对象的名称格式有一点印象。 // 根据这个名字,可以推测框架底部是否使用CGLIB动态代理 System.out.println(userServiceProxy); // 调用代理对象的代理方法。 boolean success = userServiceProxy.login("admin", "123"); System.out.println(success ? “成功登录” : “登录失败”; userServiceProxy.logout(); }}// 底层的本质///class UserService$$EnhancerByCGLIB$$82cb55e3 extends UserService{}
与JDK动态代理原理相似,在CGLIB中需要提供的不是InvocationHandler,而是:net.sf.cglib.proxy.MethodInterceptor
编写Methodinterceptor接口实现类:
在Methodinterceptor接口中,intercept()有四个参数:
第一个参数:目标对象
第二个参数:目标方法
第三个参数:调用目标方法时的实际参数
第四个参数:代理方法
package com.powernode.proxy.service;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * 动态代理CGLIB 102 **/public class TimerMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // 前面增强 long begin = System.currentTimeMillis(); // 目标对象的目标方法如何调用? Object retValue = methodProxy.invokeSuper(target, objects); // 后面增强 long end = System.currentTimeMillis(); System.out.println("耗时"+(end - begin)+"毫秒"); return retValue; }}
对于高版JDK,如果使用CGLIB,则需要在启动项中添加两个启动参数:
●--add-opensjava.base/java.lang=ALL-UNNAMED
●--add-opensjava.base/sun.net.util=ALL-UNNAMED