CGLIB动态代理
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; //CGLIB动态代理 102 public class Client { public static void main(String[] args) { // 创建字节码增强器对象 // 这个对象是CGLIB库当中的核心对象,就是依靠它来生成代理类。 Enhancer enhancer = new Enhancer(); // 告诉CGLIB父类是谁。告诉CGLIB目标类是谁。 enhancer.setSuperclass(UserService.class); // 设置回调(等同于JDK动态代理当中的调用处理器。InvocationHandler) // 在CGLIB当中不是InvocationHandler接口,是方法拦截器接口: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(),该方法有4个参数:
第一个参数:目标对象
第二个参数:目标方法
第三个参数:目标方法调用时的实参
第四个参数:代理方法
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-opens java.base/java.lang=ALL-UNNAMED
● --add-opens java.base/sun.net.util=ALL-UNNAMED
代理模式-动态代理详解(JDK动态代理和CGLIB动态代理)jdk cglib动态代理
谁与争锋,JDK动态代理大战CGLib动态代理jdk动态代理和cglib动态代理
代理模式之静态代理,JDK动态代理和cglib动态代理jdk cglib动态代理
静态代理与JDK动态代理与CGLIB动态代理cglib动态代理
java中的静态代理、jdk动态代理和cglib动态代理jdk cglib动态代理
Java JDK中的静态代理、动态代理&Cglib动态代理jdk cglib动态代理
9分钟带你搞懂代理模式、静态代理、JDK+CGLIB动态代理jdk cglib动态代理