<aop:aspectj-autoproxy proxy-target-class="true"/>
配置proxy-target-class="true"则强制使用了CGLIB生成代理,mybatis的mapper没有默认构造方法,会报错:
Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy22]: Common causes of this problem include using a final class or a non-visible classnested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy22
修改成
<aop:aspectj-autoproxy/>
这个的意思我原本以为是完全不使用cglib的代理,现在发现应该是spring会自动在JDK动态代理和CGLIB之间转换。
statement:本篇内容只是建立在我目前经验的基础之上,必然有不完善甚至是不正确的地方,请谨慎阅读,如果能指出错误与不足之处,更是不甚感激
附:本篇内容旨在基本探究一下CGLib提供了哪些功能,并提供基础示例和使用方法,本文主要内容来自于Rafael Winterhalter的文章《CGLib: The Missing Manual》,并在此基础上进行一些添加与修正。本篇内容将可能会被多次更新(如果有更深的理解,或者是需要添加的说明之处)
CGLib是一个基于ASM字节码 *** 纵框架之上的类生成工具,相比于底层的ASM,CGLib不需要你理解那么多必需的和字节码相关底层知识,你可以很轻松的就在运行时动态生成一个类或者一个接口。CGLib广泛应用于AOP方面和代理方面,比如Spring、Hibernate,甚至也可以用于Mock测试方面。
CGLib有些地方需要提前引起注意,至于原因为何,我将会在最后一节说明。
参考文档:
[1] CGLib: The Missing Manual
[2] https://github.com/cglib/cglib/wiki/How-To
CGLIB 和 JDK生成动态代理类区别
jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。
cglib这种第三方类库实现的动态代理应用更加广泛,并不需要目标类基于统一的接口,且在效率上更有优势。
下面分别用2个具体例子来详细阐述
jdk生成代理类
为目标类(target)定义统一的接口类Service,这个是jdk动态代理必须的前提
public interface Service {/**
* add方法
*/
public void add()
/**
* update方法
*/
public void update()
}
2.目标类AService
public class AService implements Service {/*
* (non-Javadoc)
*
* @see jdkproxy.Service#add()
*/
public void add() {
System.out.println("AService add>>>>>>>>>>>>>>>>>>")
}
/*
* (non-Javadoc)
*
* @see jdkproxy.Service#update()
*/
public void update() {
System.out.println("AService update>>>>>>>>>>>>>>>")
}
}
3.实现动态代理类MyInvocationHandler,实现InvocationHandler接口,并且实现接口中的invoke方法。在
invoke方法中加入一些代理功能。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。
public class MyInvocationHandler implements InvocationHandler {private Object target
MyInvocationHandler() {
super()
}
MyInvocationHandler(Object target) {
super()
this.target = target
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
System.out.println("before-----------------------------")
// 程序执行
Object result = method.invoke(target, args)
// 程序执行后加入逻辑,MethodAfterAdviceInterceptor
System.out.println("after------------------------------")
return result
}
}
4.测试类,其中增强的目标对象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler)来生成的。
public class Test {public static void main(String[] args) {
Service aService = new AService()
MyInvocationHandler handler = new MyInvocationHandler(aService)
// Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
.getClass().getClassLoader(), aService.getClass()
.getInterfaces(), handler)
// 由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口
aServiceProxy.add()
System.out.println()
aServiceProxy.update()
}
cglib动态代理实现AOP拦截
被代理目标类,cglib不需要目标类实现接口
public class Base {/**
* 一个模拟的add方法
*/
public void add() {
System.out.println("add ------------")
}
}
实现动态代理类CglibProxy,需要实现MethodInterceptor接口,实现intercept方法。
public class CglibProxy implements MethodInterceptor {
public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
System.out.println("before-------------")
// 执行目标类add方法
proxy.invokeSuper(object, args)
// 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
System.out.println("after--------------")
return null
}
}
获取增强的目标类的工厂Factory,其中增强的方法类对象是有Enhancer来实现的
public class Factory {/**
* 获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
*
* @param proxy
* @return
*/
public static Base getInstance(CglibProxy proxy) {
Enhancer enhancer = new Enhancer()
enhancer.setSuperclass(Base.class)
//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
enhancer.setCallback(proxy)
// 此刻,base不是单纯的目标类,而是增强过的目标类
Base base = (Base) enhancer.create()
return base
}
}
测试类
public class Test {public static void main(String[] args) {
CglibProxy proxy = new CglibProxy()
// base为生成的增强过的目标类
Base base = Factory.getInstance(proxy)
base.add()
}
}
从上面2个例子,可看出cglib中目标类Base并没有实现接口,而jdk生成代理类例子中AService 实现了Service接口,所以CGLIB 和 JDK生成动态代理类的区别最大的区别就是目标类是否需要实现接口。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)