阅读 66

Spring 如何实现 AOP,请不要再说 cglib 了!

1. 从注解入手找到对应核心类

2. 画核心类类图,猜测核心方法

3. 读重点方法,理核心流程

4. 总结

1. 从注解入手找到对应核心类

最近工作中我都是基于注解实现 AOP 功能,常用的开启 AOP 的注解是 @EnableAspectJAutoProxy,我们就从它入手。

![](https://upload-images.jianshu.io/upload_images/24533109-0c9c5d8ec32aa09c?imageMogr2/auto-orient/strip|imageView2/2/w/638/format/webp)

上面的动图的流程的步骤就是:@EnableAspectJAutoProxy --> AspectJAutoProxyRegistrar -->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary -->AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator 查看其中文注释(如下),确定它就是 AOP 的核心类!-- 温安适 20191020

AspectJAwareAdvisorAutoProxyCreator的子类 ,用于处理当前应用上下文中的注解切面

任何被AspectJ注解的类将自动被识别。

若SpringAOP代理模式可以识别,优先使用Spring代理模式。

它覆盖了方法执行连接点

如果使用aop:include元素, 则只有名称与include模式匹配的@aspectj bean才被视为切面 ,并由spring自动代理。

Spring Advisors的处理请查阅,

org.springframework.aop

.framework.autoproxy.AbstractAdvisorAutoProxyCreator

@SuppressWarnings("serial")

publicclassAnnotationAwareAspectJAutoProxyCreator

extendsAspectJAwareAdvisorAutoProxyCreator

{

//...省略实现

}注解切面

虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

2. 画核心类类图,猜测核心方法

AnnotationAwareAspectJAutoProxyCreator 的部分类图。

AnnotationAwareAspectJAutoProxyCreator 从类图看到了 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor,而 AOP 功能应该在创建完 Bean 之后执行,猜测 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization(实例化 bean 后处理)是核心方法。查看 AnnotationAwareAspectJAutoProxyCreator 实现的 postProcessAfterInitialization 方法,实际该方法在其父类 AbstractAutoProxyCreator 中。

![](https://upload-images.jianshu.io/upload_images/24533109-33f95cf075382ffe?imageMogr2/auto-orient/strip|imageView2/2/w/486/format/webp)

//AbstractAutoProxyCreator中的postProcessAfterInitialization实现

@Override

publicObjectpostProcessAfterInitialization(Object bean, String beanName)

throwsBeansException

{

if(bean !=null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if(!this.earlyProxyReferences.contains(cacheKey)) {

returnwrapIfNecessary(bean, beanName, cacheKey);

}

}

returnbean;

}

发现发现疑似方法 wrapIfNecessary,查看其源码如下,发现 createProxy 方法。确定找对了地方。

protectedObjectwrapIfNecessary

(Object bean, String beanName, Object cacheKey)

{

if(beanName !=null&&this.targetSourcedBeans.contains(beanName)) {

returnbean;

}

if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

returnbean;

}

if(isInfrastructureClass(bean.getClass())

|| shouldSkip(bean.getClass(), beanName)) {

this.advisedBeans.put(cacheKey, Boolean.FALSE);

returnbean;

}

// 创建代理

Object[] specificInterceptors =

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName,null);

if(specificInterceptors != DO_NOT_PROXY) {

this.advisedBeans.put(cacheKey, Boolean.TRUE);

Object proxy = createProxy(

bean.getClass(), beanName,

specificInterceptors,newSingletonTargetSource(bean));

this.proxyTypes.put(cacheKey, proxy.getClass());

returnproxy;

}

this.advisedBeans.put(cacheKey, Boolean.FALSE);

returnbean;

}

即 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization 方法,在该方法中由 wrapIfNecessary 实现了 AOP 的功能。wrapIfNecessary 中有 2 个和核心方法

getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

createProxy 为当前 bean 创建代理 要想明白核心流程还需要分析这 2 个方法。

3. 读重点方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

查看源码如下,默认实现在 AbstractAdvisorAutoProxyCreator 中。

@Override

@Nullable

protectedObject[] getAdvicesAndAdvisorsForBean(

Class beanClass, String beanName,

@NullableTargetSource targetSource) {

List advisors = findEligibleAdvisors(beanClass, beanName);

if(advisors.isEmpty()) {

returnDO_NOT_PROXY;

}

returnadvisors.toArray();

}

查阅 findEligibleAdvisors 方法,就干了 3 件事

找所有增强器,也就是所有 @Aspect 注解的 Bean

找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。

对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。

protectedListfindEligibleAdvisors(Class<?> beanClass, String beanName){

//找所有增强器

List candidateAdvisors = findCandidateAdvisors();

//找所有匹配的增强器

List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

extendAdvisors(eligibleAdvisors);

if(!eligibleAdvisors.isEmpty()) {

//排序

eligibleAdvisors = sortAdvisors(eligibleAdvisors);

}

returneligibleAdvisors;

}

AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors,下面我们看看具体实现了什么

3.1.1findCandidateAdvisors 找所有增强器,也就是所有 @Aspect 注解的 Bean

@Override

protectedListfindCandidateAdvisors(){

// Add all the Spring advisors found according to superclass rules.

List advisors =super.findCandidateAdvisors();

// Build Advisors for all AspectJ aspects in the bean factory.

if(this.aspectJAdvisorsBuilder !=null) {

//@Aspect注解的类在这里除了

advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());

}

returnadvisors;

}

从该方法我们可以看到处理 @Aspect 注解的 bean 的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。这个方法如下:

publicListbuildAspectJAdvisors(){

List aspectNames =this.aspectBeanNames;

if(aspectNames ==null) {

synchronized(this) {

aspectNames =this.aspectBeanNames;

if(aspectNames ==null) {

List advisors =newArrayList<>();

aspectNames =newArrayList<>();

//找到所有BeanName

String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(

this.beanFactory, Object.class,true,false);

for(String beanName : beanNames) {

if(!isEligibleBean(beanName)) {

continue;

}

// 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。

Class beanType =this.beanFactory.getType(beanName);

if(beanType ==null) {

continue;

}

if(this.advisorFactory.isAspect(beanType)) {

//找到所有被@Aspect注解的类

aspectNames.add(beanName);

AspectMetadata amd =newAspectMetadata(beanType, beanName);

if(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

MetadataAwareAspectInstanceFactory factory =

newBeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

//解析封装为Advisor返回

List classAdvisors =this.advisorFactory.getAdvisors(factory);

if(this.beanFactory.isSingleton(beanName)) {

this.advisorsCache.put(beanName, classAdvisors);

}

else{

this.aspectFactoryCache.put(beanName, factory);

}

advisors.addAll(classAdvisors);

}

else{

// Per target or per this.

if(this.beanFactory.isSingleton(beanName)) {

thrownewIllegalArgumentException("Bean with name '"+ beanName +

"' is a singleton, but aspect instantiation model is not singleton");

}

MetadataAwareAspectInstanceFactory factory =

newPrototypeAspectInstanceFactory(this.beanFactory, beanName);

this.aspectFactoryCache.put(beanName, factory);

advisors.addAll(this.advisorFactory.getAdvisors(factory));

}

}

}

this.aspectBeanNames = aspectNames;

returnadvisors;

}

}

}

if(aspectNames.isEmpty()) {

returnCollections.emptyList();

}

List advisors =newArrayList<>();

for(String aspectName : aspectNames) {

List cachedAdvisors =this.advisorsCache.get(aspectName);

if(cachedAdvisors !=null) {

advisors.addAll(cachedAdvisors);

}

else{

MetadataAwareAspectInstanceFactory factory =this.aspectFactoryCache.get(aspectName);

advisors.addAll(this.advisorFactory.getAdvisors(factory));

}

}

returnadvisors;

}

这个方法可以概括为:

找到所有 BeanName

根据 BeanName 筛选出被 @Aspect 注解的类

针对类中被 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个 Advisor。

3.2 createProxy 为当前 bean 创建代理。

3.2.1 创建代理的 2 种方式

众所周知,创建代理的常用的 2 种方式是:JDK 创建和 CGLIB,下面我们就看看这 2 中创建代理的例子。

3.2.1 .1 jdk 创建代理的例子

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

publicclassJDKProxyMain{

publicstaticvoidmain(String[] args){

JDKProxyTestInterface target =newJDKProxyTestInterfaceImpl();

// 根据目标对象创建代理对象

JDKProxyTestInterface proxy =

(JDKProxyTestInterface) Proxy

.newProxyInstance(target.getClass().getClassLoader(),

target.getClass().getInterfaces(),

newJDKProxyTestInvocationHandler(target));

// 调用代理对象方法

proxy.testProxy();

}

interfaceJDKProxyTestInterface{

voidtestProxy();

}

staticclassJDKProxyTestInterfaceImpl

implementsJDKProxyTestInterface

{

@Override

publicvoidtestProxy(){

System.out.println("testProxy");

}

}

staticclassJDKProxyTestInvocationHandler

implementsInvocationHandler

{

privateObject target;

publicJDKProxyTestInvocationHandler(Object target){

this.target=target;

}

@Override

publicObjectinvoke(Object proxy, Method method,

Object[] args)

throwsThrowable{

System.out.println("执行前");

Object result= method.invoke(this.target,args);

System.out.println("执行后");

returnresult;

}

}

3.2.1 .2 cglib 创建代理的例子

importorg.springframework.cglib.proxy.Enhancer;

importorg.springframework.cglib.proxy.MethodInterceptor;

importorg.springframework.cglib.proxy.MethodProxy;

importjava.lang.reflect.Method;

publicclassCglibProxyTest{

staticclassCglibProxyService{

publicCglibProxyService(){

}

voidsayHello(){

System.out.println(" hello !");

}

}

staticclassCglibProxyInterceptorimplementsMethodInterceptor{

@Override

publicObjectintercept(Object sub, Method method,

Object[] objects, MethodProxy methodProxy)

throwsThrowable

{

System.out.println("before hello");

Object object = methodProxy.invokeSuper(sub, objects);

System.out.println("after hello");

returnobject;

}

}

publicstaticvoidmain(String[] args){

// 通过CGLIB动态代理获取代理对象的过程

Enhancer enhancer =newEnhancer();

// 设置enhancer对象的父类

enhancer.setSuperclass(CglibProxyService.class);

// 设置enhancer的回调对象

enhancer.setCallback(newCglibProxyInterceptor());

// 创建代理对象

CglibProxyService proxy= (CglibProxyService)enhancer.create();

System.out.println(CglibProxyService.class);

System.out.println(proxy.getClass());

// 通过代理对象调用目标方法

proxy.sayHello();

}

}

3.2.1 .3 jdk 创建代理与 cglib 创建代理的区别

![](https://upload-images.jianshu.io/upload_images/24533109-8547648ef7f0c575?imageMogr2/auto-orient/strip|imageView2/2/w/657/format/webp)

3.2.2 Spring 如何选择的使用哪种方式

Spring 的选择选择如何代理时在 DefaultAopProxyFactory 中。

publicclassDefaultAopProxyFactoryimplementsAopProxyFactory,

Serializable

{

@Override

publicAopProxycreateAopProxy(AdvisedSupport config)

throwsAopConfigException

{

if(config.isOptimize()

|| config.isProxyTargetClass()

|| hasNoUserSuppliedProxyInterfaces(config)) {

Class targetClass = config.getTargetClass();

if(targetClass ==null) {

thrownewAopConfigException(

"TargetSource cannot determine target class: "

+"Either an interface or a target "+

" is required for proxy creation.");

}

if(targetClass.isInterface()

|| Proxy.isProxyClass(targetClass)) {

returnnewJdkDynamicAopProxy(config);

}

returnnewObjenesisCglibAopProxy(config);

}

else{

returnnewJdkDynamicAopProxy(config);

}

}

//...

}

config.isOptimize() 查看源码注释时发现,这个是配置使用 cglib 代理时,是否使用积极策略。这个值一般不建议使用!

config.isProxyTargetClass() 就是 @EnableAspectJAutoProxy 中的 proxyTargetClass 属性。

//exposeProxy=true AopContext 可以访问,proxyTargetClass=true CGLIB 生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

总结下 Spring 如何选择创建代理的方式:

如果设置了 proxyTargetClass=true,一定是 CGLIB 代理

如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理

如果没有实现接口,走 CGLIB 代理

4. 总结

Spring 如何实现 AOP?,您可以这样说:

AnnotationAwareAspectJAutoProxyCreator 是 AOP 核心处理类

AnnotationAwareAspectJAutoProxyCreator 实现了 BeanProcessor,其中 postProcessAfterInitialization 是核心方法。

核心实现分为 2 步 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器 createProxy 为当前 bean 创建代理

getAdvicesAndAdvisorsForBean 核心逻辑如下 a. 找所有增强器,也就是所有 @Aspect 注解的 Bean b. 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。c. 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。

createProxy 有 2 种创建方法,JDK 代理或 CGLIB a. 如果设置了 proxyTargetClass=true,一定是 CGLIB 代理 b. 如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理 c. 如果没有实现接口,走 CGLIB 代理

![](https://upload-images.jianshu.io/upload_images/24533109-128926e6885b333e.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/860/format/webp)
文章分类
后端
文章标签