使用JDK动态代理存在一定的局限性,使用动态代理的对象必须实现一个或多个接口。如果要对没有实现接口的类进行代理,可以使用CGLIB代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。
接下来,通过一个案例来演示CGLIB代理的实现过程,具体步骤如下。
- 创建一个目标类UserDao,UserDao不需要实现任何接口,只需定义一个添加用户的方法和一个删除用户的方法。
public class UserDao{
public void addUser(){
System.out.println("添加用户");
}
public void deleteUser(){
System.out.println("删除用户");
}
}
- 创建切面类MyAspect,在该类中定义一个模拟权限检查的方法和一个模拟记录日志的方法,这两个方法就表示切面中的通知。
//切面类:可以存在多个通知Advice(即增强的方法)
public class MyAspect{
public void check_Permissions(){
System.out.println("模拟检查权限...");
}
public void log(){
System.out.println("模拟记录日志");
}
}
- 创建代理类CglibProxy,该代理类需要实现MethodInterceptor接口,并实现接口中的intercept()方法。
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import MyAspect;
//代理类
public class CglibProxy implements MethodInterceptor{
//代理方法
public Object createProxy(Object target){
//创建一个动态类对象
Enhancer enhancer = new Enhancer();
//确定需要增强的类,设置其父类
enhancer.setSuperClass(targer.getClass());
//添加回调函数
enhancer.setCallback(this);
//返回创建的代理类
return enhancer.create();
}
/**
*proxy CGlib根据指定父类生成的代理对象
*method 拦截的方法
*args 拦截方法的参数数组
*methodProxy 方法的代理对象,用执行父类的方法
*/
@Override
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy)throws Throwable{
//创建切面类对象
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
//目标方法执行
Object obj = methodProxy.invokeSuper(proxy,args);
//后增强
myAspect.log();
return obj;
}
}
在代理方法中,首先创建一个动态类对象Enhancer,它是CGLIB的核心类;然后调用了Enhancer类的setSuperClass()方法来确定目标对象;接下来调用了setCallback()方法添加回调函数,其中this代表的就是代理类CglibProxy本身;最后通过return语句将创建的代理类对象返回。intercept()方法会在程序执行目标方法时被调用,方法运行时会将执行切面类中的增强方法。
- 创建测试类CglibTest,在该类的main()方法中首先创建代理对象和目标对象,然后从代理对象中获得增强后的目标,最后调用对象的添加和删除方法。
public class CglibTest{
public static void main(String[] args){
//创建代理对象
CglibProxy cglibProxy = new CglibProxy();
//创建目标对象
UserDao userDao = new UserDao();
//获取增强后的目标对象
UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
//执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}
输出结果如下:
模拟检查权限...
添加用户
模拟记录日志...
模拟检查权限...
删除用户
模拟记录日志...
可以看出,目标类UserDao中的方法被成功调用并增强了。这种没有实现接口的代理方法,就是CGLIB代理。1
Java EE企业级应用开发教程 ↩︎