上一章讲到了使用JDK的Proxy实现AOP:
https://blog.csdn.net/qq_34598667/article/details/83380628
这一章我们讲另外一种方式,使用CGLIB实现AOP
使用CGLIB实现AOP功能
上一章我们已经说过,要产生某个对象的代理对象,这个对象必须实现一个接口,动态代理技术只能基于接口进行代理。
可是有时候我们在开发时碰到一些对象没有接口,那想要为它创建一个代理对象是否可以为它创建一个接口呢?那当然是不行的!这些对象可能是服务器或者容器给我们的,我们怎么能随便给它定义一个接口实现呢,不能水表就给它找个干爹吧…
这时候我们如果想为它创建代理对象,就要用到另外一种方法了——CGLIB,这个API即使没有接口也能去创建这个对象的代理对象。
CGLIB产生代理对象的原理
实际上产生的是这个对象的子类,也即我们把一个对象交给CGLIB,它返回出来的似乎是一个代理对象,但其实这个代理对象就是这个对象的子类,利用子类的方式来创建代理对象。
案例讲解
本章案例基于上一章案例做:
要使用CGLIB,需要导入以下jar包:
- asm-2.2.3.jar
- cglib-nodep-2.2.jar
没有jar包的可以去1积分下载:
https://download.csdn.net/download/qq_34598667/10746196
修改UserServiceImpl类
修改UserServiceImpl类,去掉接口实现:
public class UserServiceImpl{
//假设有该user是个User对象
private String user=null;
public String getUser(){
return user;
}
public UserServiceImpl(){
}
public UserServiceImpl(String user){
this.user=user;
}
public void add(String name) {
System.out.println("我要增加");
}
public void delete(int id) {
System.out.println("我要删除");
}
}
没有实现接口,若想产生它的代理对象,就要使用CGLIB了
在com.oak.aop下新建一个类:CGLIBProxyFactory用于创建代理对象:
public class CGLIBProxyFactory implements MethodInterceptor{
@Override
public Object intercept(Object object, Method method, Object[] arg,
MethodProxy methodProxy) throws Throwable {
return null;
}
}
Enhancer
Enhancer类是CGLib中的一个字节码增强器,作用用于生成代理对象,跟上一章所学的Proxy类相似,常用方式为:
Enhancer enhancer=new Enhancer();
//将被代理类ConcreteClassNoInterface设置成父类,
enhancer.setSuperclass(ConcreteClassNoInterface.class);
//设置拦截器 回调对象为本身对象
enhancer.setCallback(this);
//执行enhancer.create()动态生成一个代理类,并从Object强制转型成父类型ConcreteClassNoInterface。
ConcreteClassNoInterface ccni=(ConcreteClassNoInterface)enhancer.create();
下面我们使用它生成一个代理对象,在CGLIBProxyFactory中新建一个targetObject属性作为代理的目标对象,新建createProxyInstance(Object targetObject)方法用于生产代理对象:
public class CGLIBProxyFactory implements MethodInterceptor{
//代理的目标对象
private Object targetObject;
//产生一个代理对象
public Object createProxyInstance(Object targetObject){
this.targetObject=targetObject;
//用于生成代理对象
Enhancer enhancer=new Enhancer();
//设置目标类为代理对象的父类
enhancer.setSuperclass(this.targetObject.getClass());
//设置回调对象为本身
enhancer.setCallback(this);
//生成一个代理类对象
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] arg,
MethodProxy methodProxy) throws Throwable {
return null;
}
}
MethodInterceptor接口–拦截器
在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable
其中参数:
Object:由CGLib动态生成的代理类实例,
Method:上文中实体类所调用的被代理的方法引用,
Object[]:参数值列表,
MethodProxy:生成的代理类对方法的代理引用。
返回值
返回:从代理实例的方法调用返回的值。
proxy.invokeSuper(obj,arg):
调用代理类实例上的proxy方法的父类方法,即真实对象中的方法
编写CGLIBProxyFactory中回调的intercept方法
public class CGLIBProxyFactory implements MethodInterceptor{
//代理的目标对象
private Object targetObject;
//产生一个代理对象
public Object createProxyInstance(Object targetObject){
this.targetObject=targetObject;
//用于生成代理对象
Enhancer enhancer=new Enhancer();
//设置目标类为代理对象的父类
enhancer.setSuperclass(this.targetObject.getClass());
//设置回调对象为本身
enhancer.setCallback(this);
//生成一个代理类对象
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] arg,
MethodProxy methodProxy) throws Throwable {
UserServiceImpl service=(UserServiceImpl) this.targetObject;
Object result = null;
//在代理真实对象方法执行前我们可以添加一些自己的操作
System.out.println("Before 真实对象方法执行...");
if(service.getUser()!=null){//判断权限
result=methodProxy.invoke(targetObject, arg);
}
//在代理真实对象方法执行后我们也可以添加一些自己的操作
System.out.println("After 真实对象方法执行...");
return result;
}
}
测试
新加测试方法testCglibProxy:
@Test
public void testCglibProxy(){
//UserServiceImpl不设置user值--没有对象
UserServiceImpl service=(UserServiceImpl) new CGLIBProxyFactory().
createProxyInstance(new UserServiceImpl());
service.add("哈哈");
}
运行查看控制台,没有权限,真实对象的方法没有执行:
Before 真实对象方法执行...
After 真实对象方法执行...
给UserServiceImpl的user赋值,给权限:
@Test
public void testCglibProxy(){
//UserServiceImpl不设置user值--没有对象
UserServiceImpl service=(UserServiceImpl) new CGLIBProxyFactory().
createProxyInstance(new UserServiceImpl("狗子"));
service.add("哈哈");
}
测试,控制台:
Before 真实对象方法执行...
我要增加
After 真实对象方法执行...
已经有了权限,真实对象执行了add方法。
Spring中的AOP编程
Spring里面有一个AOP编程。即面向切面编程,其实就是动态代理。当我们交给Spring一个对象,它就会返回代理给我们,它在返回代理对象的时候,首先会检查我们这个对象有没有实现一个接口,如果我们这个类有接口,它使用Java的动态代理技术来帮我们构建出代理对象;如果我们这个类没有实现接口,它会使用CGLIB这套API,采用创建子类的方式来创建代理对象。
所以我们所实现AOP动态代理的两种方式就是JDK的Proxy和CGLIB。