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
标签:System,代理,proxy,CGLIB,UserService,动态,public From: https://blog.51cto.com/u_15784725/6454477