CGLIB实现AOP,MethodInterceptor接口和Enhancer详解——Spring AOP(四)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34598667/article/details/83414835

上一章讲到了使用JDK的Proxy实现AOP:
https://blog.csdn.net/qq_34598667/article/details/83380628
这一章我们讲另外一种方式,使用CGLIB实现AOP


使用CGLIB实现AOP功能

上一章我们已经说过,要产生某个对象的代理对象,这个对象必须实现一个接口,动态代理技术只能基于接口进行代理。
可是有时候我们在开发时碰到一些对象没有接口,那想要为它创建一个代理对象是否可以为它创建一个接口呢?那当然是不行的!这些对象可能是服务器或者容器给我们的,我们怎么能随便给它定义一个接口实现呢,不能水表就给它找个干爹吧…
这时候我们如果想为它创建代理对象,就要用到另外一种方法了——CGLIB,这个API即使没有接口也能去创建这个对象的代理对象。

CGLIB产生代理对象的原理

实际上产生的是这个对象的子类,也即我们把一个对象交给CGLIB,它返回出来的似乎是一个代理对象,但其实这个代理对象就是这个对象的子类,利用子类的方式来创建代理对象。


案例讲解

本章案例基于上一章案例做:
要使用CGLIB,需要导入以下jar包:


修改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。


猜你喜欢

转载自blog.csdn.net/qq_34598667/article/details/83414835