SpringAOP实现源码解读

1、Spring AOP样例

简单介绍怎么样基于Spring实现AOP编程(注解方式在目标对象方法中织入通知方法)

2、AOP关键注解@EnableAspectJAutoProxy

分析@EnableAspectJAutoProxy注解源,了解实现AOP需要给容器提供的配置信息

3、AOP实现的关键类AnnotationAwareAspectJAutoProxyCreator

静态分析Spring框架里面,创建AOP代理对象的类

4、AnnotationAwareAspectJAutoProxyCreator的实例化和注册

动态分析AnnotationAwareAspectJAutoProxyCreator在容器中的实例化和注册过程

5、AnnotationAwareAspectJAutoProxyCreator创建目标代理对象

动态分析Spring容器使用AnnotationAwareAspectJAutoProxyCreator创建目标代理对象过程

01

Spring AOP样例

本样例代码工程,是基于Maven的,使用的是Spring5.0.5版本,pom.xml如下:

4.0.0

cn.com.tuling.openclass.aop

explore-06-spring-aop

0.0.1-SNAPSHOT

UTF-8

UTF-8

1.8

5.0.5.RELEASE

org.springframework

spring-context

${spring.version}

org.aspectj

aspectjweaver

1.8.13

junit

junit

4.7

test

(左右滑动查看完整代码)

当前样例比较简单,直接贴代码如下:

1)IPowerService和PowerServiceImpl

目标类的接口和实现,里面就一个login方法,将用来织入AOP的通知方法

package cn.com.tuling.openclass.service;

public interface IPowerService {

public boolean login(String userName,String password);

}

package cn.com.tuling.openclass.service.impl;

import org.springframework.stereotype.Service;

import cn.com.tuling.openclass.service.IPowerService;

@Service

public class PowerServiceImpl implements IPowerService {

@Override

public boolean login(String userName, String password) {

boolean bool = false;

System.out.println(“to execute PowerServiceImpl.login() method…”);

bool = userName != null && userName.startsWith(“zhang”);

return bool;

}

}

2)LogServiceImpl

这里面定义了几个日志方法,以便封装成通知,织入到切入点中

package cn.com.tuling.openclass.service.impl;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

@Component//声明当前类为组件类

@Aspect//切面

public class LogServiceImpl{

//定义切入点

@Pointcut(“execution(* cn.com.tuling….(…))”)

public void myPointCut(){}

//将logBefore方法封装成Before通知,织入到myPointCut()切入点

@Before("myPointCut()")

public void logBefore() {

    System.out.println("....logServiceImpl.logBefore....");

}

//将logAfter方法封装成After通知,织入到myPointCut()切入点

@After("myPointCut()")

public void logAfter() {

    System.out.println("....logServiceImpl.logAfter....");

}

//将logReturnAfter方法封装成AfterReturning通知,织入到myPointCut()切入点

@AfterReturning("myPointCut()")

public void logReturnAfter() {

    System.out.println("....logServiceImpl.logReturnAfter....");

}

//将logThrowing方法封装成AfterThrowing通知,织入到myPointCut()切入点

@AfterThrowing("myPointCut()")

public void logThrowing() {

    System.out.println("....logServiceImpl.logThrowing....");

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

}

3)ConfigAOP

Spring注解式配置类

package cn.com.tuling.openclass.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration//声明当前类为Spring注解配置类

@EnableAspectJAutoProxy//支持AspectJ注解

@ComponentScan(basePackages=“cn.com.tuling.openclass”)//自动扫描组件路径

public class ConfigAOP {

}

4)TestAOP,测试类

package cn.com.tuling.openclass.service;

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import cn.com.tuling.openclass.config.ConfigAOP;

public class TestAOP {

@Test

public void test01(){

// 初始化注解式IOC容器

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);

// 从容器中获取PowerService实例

IPowerService powerService = (IPowerService)ctx.getBean(IPowerService.class);

// 调用PowerService的login方法

boolean bool = powerService.login(“zhangsan”, “123”);

// 关闭IOC容器

ctx.close();

}

}

运行TestAOP里面的test01方法,运行如下日志:

我们在TestAOP的test01方法中,只是调用了IPowerService的login方法,却在它前后输出了每个通知的打印,说明已经基于Spring的AOP,完成了通知到目标切入点的织入。

02

AOP关键注解@EnableAspectJAutoProxy

通过调整我们前面的ConfigAOP类的代码,我们能感觉到,如果注释掉ConfigAOP类上面的@EnableAspectJAutoProxy,运行TestAOP的test01方法的时候,将看不到通知织入的效果(只会执行PowerServiceImpl中的login方法,不会执行LogServiceImpl中对应的通知方法),说明@EnableAspectJAutoProxy注解里面,定义了SpringAOP织入通知的关键信息,这信息是什么呢,我们来研究@EnableAspectJAutoProxy的源码。

package org.springframework.context.annotation;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

支持AspectJ注解,使用注解的方式实现AOP织入,效果等同xml配置文件中的aop:aspectj-autoproxy/

@author Chris Beams

@author Juergen Hoeller

@since 3.1

@see org.aspectj.lang.annotation.Aspect

/

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(AspectJAutoProxyRegistrar.class)

public @interface EnableAspectJAutoProxy {

/

*

Indicate whether subclass-based (CGLIB) proxies are to be created as opposed

to standard Java interface-based proxies. The default is {@code false}.

/

boolean proxyTargetClass() default false;

/

*

Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}

for retrieval via the {@link org.springframework.aop.framework.AopContext} class.

Off by default, i.e. no guarantees that {@code AopContext} access will work.

@since 4.3.1

*/

boolean exposeProxy() default false;

}

通过查看@EnableAspectJAutoProxy源码,我们了解到@EnableAspectJAutoProxy的作用,同xml配置文件中的aop:aspectj-autoproxy一样,告诉Spring容器,支持注解式Aspect。

@EnableAspectJAutoProxy有两个属性:

1)proxyTargetClass 指定是否使用CGLIB的方式创建实现接口的目标对象的代理。缺省值为false,使用JDK方式创建接口对象的代理

exposeProxy 标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。当一个代理对象需要调用它自己的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。

exposeProxy属性的使用案例,请查看另外一个专题(《坑、坑、坑,同一个类中的切入方法无效!》),这里就不重复了。

通观前面的代码,没有哪个地方有描述怎么样实现AOP,不过有发现红色代码行,从名字上就同咱们的目标AOP(AspectJ切面)有关系,我们跟进去,看AspectJAutoProxyRegistrar类源代码如下:

package org.springframework.context.annotation;

import org.springframework.aop.config.AopConfigUtils;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import org.springframework.core.annotation.AnnotationAttributes;

import org.springframework.core.type.AnnotationMetadata;

/**

… …

*/

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

@Override

public void registerBeanDefinitions(

AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =

AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

if (enableAspectJAutoProxy != null) {

if (enableAspectJAutoProxy.getBoolean(“proxyTargetClass”)) {

AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);

}

if (enableAspectJAutoProxy.getBoolean(“exposeProxy”)) {

AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);

}

}

}

}

在AspectJAutoProxyRegistrar.java的源码中,红色标记部分,从名称上可以猜出来,是在调用一个方法,完成注解式代理对象的创建器(Creator)行,继续这样的思路,我们进一步跟进如上红色部分的代码如下:

public abstract class AopConfigUtils {

… …

@Nullable

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {

return registerAspectJAutoProxyCreatorIfNecessary(registry, null);

}

@Nullable

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,

@Nullable Object source) {

return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);

}

… …

}

跟到AopConfigUtils源代码中,我们发现最终会调用红色标记部分的代码,该行代码的作用,是在容器中注册一个AspectJAwareAdvisorAutoProxyCreator类。

到这里,我们就找到了SpringAOP中,创建目标对象的代理对象的源(作俑者)。这个作俑者是在@EnableAspectJAutoProxy中告知Spring IOC容器的,也就是说,通过@EnableAspectJAutoProxy注解,通知Spring容器在需要的时候,使用AspectJAwareAdvisorAutoProxyCreator对象创建目标的代理对象,实现通知的织入(实现AOP)。

03

AnnotationAwareAspectJAutoProxyCreator类静态源码分析

作用:

代码层次:

AnnotationAwareAspectJAutoProxyCreator

->AspectJAwareAdvisorAutoProxyCreator

->AbstractAdvisorAutoProxyCreator

->AbstractAutoProxyCreator

->ProxyProcessorSupport

implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(自动装配Bean)

SmartInstantiationAwareBeanPostProcessor

->InstantiationAwareBeanPostProcessor

->BeanPostProcessor(后置处理器)

后置处理器:Spring中重要组件,在IOC容器初始化过程中,加入新的功能

自动装配Bean(Aware):给目标对象提供一个获取系统对象的接口

代码功能:

bstractAutoProxyCreator.setBeanFactory(BeanFactory)//Aware,获取Spring的BeanFactory对象

      AbstractAutoProxyCreator.postProcessBeforeInstantiation()//后置处理器添加初始化前置功能

            判断advisedBeans里面是否有包含当前beanName,是否是基础注解类,如果包含或是基类,返回null

            否则就创建目标对象的代理对象

      AbstractAdvisorAutoProxyCreator.setBeanFactory()

            super.setBeanFactory()

            initBeanFactory()// 模板方法

      AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()

            super.initBeanFactory()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

04

AnnotationAwareAspectJAutoProxyCreator的实例化和注册

到现在,我们根据源代码的摸索,基本上找到了实现AOP的关键类AspectJAwareAdvisorAutoProxyCreator,那这个类的对象什么时候实例化,又在什么时候创建的AOP代理对象的呢?能回答出这个问题,咱们的AOP原理是不是就搞定了。

接下来我们先研究AspectJAwareAdvisorAutoProxyCreator对象的创建过程。

我们在TestAOP的test01方法里的AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);代码上,添加一个debug,用debug的方式,跟进代码,历经如下:

AnnotationConfigApplicationContext.AnnotationConfigApplicationContext(Class … annotatedClasses)

->AbstractApplicationContext.refresh()

refresh方法的代码如下:

// 初始化容器上下文(比如容器启动时间等)

prepareRefresh();

// 创建beanFactory容器对象,以前有销毁再创建,以前没有,创一个新对象

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 初始化beanFactory.(类加载器、Application…Processor、Aware、环境对象等)

prepareBeanFactory(beanFactory);

try {

// 模板方法,在Bean定义加载完后,为子类提供一个可以修改BeanFactory的入口

postProcessBeanFactory(beanFactory);

// 调用注册在容器中的BeanFactory处理器

invokeBeanFactoryPostProcessors(beanFactory);

// 注册Bean后置处理器,这些处理器会在创建Bean对象的时候被调用

registerBeanPostProcessors(beanFactory);

// 初始化资源

initMessageSource();

// 初始化容器的事件广播器

initApplicationEventMulticaster();

// 模板方法,给子类提供一个在容器中实例化其他特殊bean的机会

onRefresh();

// 检测并注册监听器

registerListeners();

// 实例化其他的非延时加载的单例对象.

finishBeanFactoryInitialization(beanFactory);

// 发布容器事件

finishRefresh();

}

… …

通过查看AspectJAwareAdvisorAutoProxyCreator的父类和实现类,我们可以发现AspectJAwareAdvisorAutoProxyCreator实际上是一个BeanPostProcessor子类,所以在Spring中,是在refresh方法中标红语句(registerBeanPostProcessors)的方法中完成的。我们debug到registerBeanPostProcessors方法中去,路径如下:

AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 535

  ->AnnotationConfigApplicationContext(AbstractApplicationContext).registerBeanPostProcessors(ConfigurableListableBeanFactory) line: 710   

    ->PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory, AbstractApplicationContext) line: 189   

1

2

3

PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory,

AbstractApplicationContext)方法的代码如下:

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when

// a bean is created during BeanPostProcessor instantiation, i.e. when

// a bean is not eligible for getting processed by all BeanPostProcessors.

int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;

beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,

// Ordered, and the rest.

List priorityOrderedPostProcessors = new ArrayList<>();

List internalPostProcessors = new ArrayList<>();

List orderedPostProcessorNames = new ArrayList<>();

List nonOrderedPostProcessorNames = new ArrayList<>();

for (String ppName : postProcessorNames) {

if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

priorityOrderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {

orderedPostProcessorNames.add(ppName);

}

else {

nonOrderedPostProcessorNames.add(ppName);

}

}

// First, register the BeanPostProcessors that implement PriorityOrdered.

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.

List orderedPostProcessors = new ArrayList<>();

for (String ppName : orderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);①

orderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

sortPostProcessors(orderedPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, orderedPostProcessors);②

// Now, register all regular BeanPostProcessors.

List nonOrderedPostProcessors = new ArrayList<>();

for (String ppName : nonOrderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

nonOrderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.

sortPostProcessors(internalPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,

// moving it to the end of the processor chain (for picking up proxies etc).

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

上面的代码,大概思路是这样的:

1)获取容器中的所有BeanPostProcessor的beanName,也就是咱们在Spring容器中注册bean时的id或name

2)根据BeanPostProcessor是否实现了PriorityOrdered、Ordered、普通BeanPostProcessor对Processor进行分类

3)按PriorityOrdered、Ordered、普通种类的顺序,初始化并注册对应的BeanPostProcessor

我们可以查看一下AnnotationAwareAspectJAutoProxyCreator的父类,会发现它是实现了Ordered接口的(实际上ProiorityOrdered也是Ordered的子类),所以AnnotationAwareAspectJAutoProxyCreator对象是在上面红色标记的①代码实例化的,在②代码注册到beanFactory中的。其中beanFactory.getBean(…)方法,是Spring获取对象的统一方式,详细过程,我们在后面进行代码跟踪,这里咱们暂时记住getBean方法里面,完成了AnnotationAwareAspectJAutoProxyCreator对象的创建,并通过②代码完成了AnnotationAwareAspectJAutoProxyCreator的注册(在容器中创建了对象,并且保存下来,beanName是org.springframework.aop.config.internalAutoProxyCreator)

05

AnnotationAwareAspectJAutoProxyCreator创建目标代理对象

前面我们了解了Spring创建和注册AnnotationAwareAspectJAutoProxyCreator对象的过程,在这小节,我们将研究Spring是怎样使用注册好的AnnotationAwareAspectJAutoProxyCreator对象创建AOP代理对象的。

在我们的案例中,PowerServiceImpl对象是要织入通知的目标对象,接下来我们跟踪PowerServiceImpl对象的实例化和创建AOP代理对象的过程。

跟踪第4小节,AbstractApplicationContext.refresh()方法中的finishBeanFactoryInitialization(beanFactory);代码(PowerServiceImpl属于非延时加载的代理对象,所以在这行代码里面完成实例化)

因为AOP的代理创建,是在SpringIOC容器初始化的时候实现的,为了方便找到PowerServiceImpl的AOP代理对象的创建代码,我们在TestAOP的test01方法里的AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);代码上,添加一个debug,用debug的方式,跟进代码,历经如下:

AnnotationConfigApplicationContext.<init>(Class<?>...) line: 88   

  ->AbstractApplicationContext.refresh() line: 550   

    ->AbstractApplicationContext.finishBeanFactoryInitialization(ConfigurableListableBeanFactory) line: 869   

      ->DefaultListableBeanFactory.preInstantiateSingletons() line: 728   

1

2

3

4

5

6

7

DefaultListableBeanFactory.

preInstantiateSingletons()方法的代码块如下:

if (this.logger.isDebugEnabled()) {

this.logger.debug("Pre-instantiating singletons in " + this);

}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.

// While this may not be part of the regular factory bootstrap, it does otherwise work fine.

List beanNames = new ArrayList<>(this.beanDefinitionNames);

// 触发所有非延时加载的单例对象的实例化

for (String beanName : beanNames) {

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

if (isFactoryBean(beanName)) {

Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);

if (bean instanceof FactoryBean) {

final FactoryBean factory = (FactoryBean) bean;

boolean isEagerInit;

if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

isEagerInit = AccessController.doPrivileged((PrivilegedAction)

((SmartFactoryBean) factory)::isEagerInit,

getAccessControlContext());

}

else {

isEagerInit = (factory instanceof SmartFactoryBean &&

((SmartFactoryBean) factory).isEagerInit());

}

if (isEagerInit) {

getBean(beanName);①

}

}

}

else {

getBean(beanName);

}

}

}

// 触发所有对应bean初始化后的回调方法

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged((PrivilegedAction) () -> {

smartSingleton.afterSingletonsInstantiated();

return null;

}, getAccessControlContext());

}

else {

smartSingleton.afterSingletonsInstantiated();

}

}

}

上面代码主要做两个事情:一个是实例化所有非延时加载的单例对象;一个是调用实例化对象后的回调方法。所有对象的实例化过程,都是在如上代码,红色标记语句①getBean(beanName)完成的。

为了了解AOP代理对象的创建过程,我们需要在getBean(beanName)①;上加上一个debug断点。同时考虑到每个对象都会进入这个断点,进行对象的创建,而我们只关心PowerServiceImpl对象和对应AOP代理对象的创建过程,所以我们可以在getBean()方法的断点上面,加上条件。这样只有符合条件的时候,才会在该断点停下来,方便我们debug进去。

添加条件断点的方式如下:

1)在getBean()行代码前面,双击添加一个断点(位置很重要,注意如下图所示)

2)在断点上点击鼠标右键,选择菜单中的 Breakpoint Properties… 选项

3)点击Breakpoint Properties…选项,进入属性设置页面,选择conditional选项,同事在条件输入框中输入条件语句。如下图:

4)点击OK按钮,清除其他断点()只留当前加上的条件断点),重新debug运行TestAOP的test01方法

从前面加上的条件断点开始,逐步debug进去,debug的线路如下(第一次debug不妨按如下的参考进行,先确定AOP对象创建的位置,回过来再了解每个过程中涉及方法的逻辑流程):

DefaultListableBeanFactory.preInstantiateSingletons() line: 760

->AbstractBeanFactory.getBean(String) line: 199   

    ->AbstractBeanFactory.doGetBean(String, Class<T>, Object[], boolean) line: 315   

        ->DefaultSingletonBeanRegistry.getSingleton(String, ObjectFactory<?>) line: 228   

            ->AbstractBeanFactory.lambda$doGetBean$0(String, RootBeanDefinition, Object[]) line: 317 

                ->AbstractAutowireCapableBeanFactory.createBean(String, RootBeanDefinition, Object[]) line: 501 

                    ->AbstractAutowireCapableBeanFactory.doCreateBean(...) line: 579   

                        ->AbstractAutowireCapableBeanFactory.initializeBean(...) line: 1706   

                            ->AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.) line: 436

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

到这一步,就进入了Spring容器中,给PowerServiceImpl创建AOP代理对象的过程,前面分析@EnableAspectJAutoProxy源码的时候,咱们知道在AspectJAutoProxyRegistrar类中,有注册了一个AnnotationAwareAspectJAutoProxyCreator类,并且也初步告诉大家,Spring在初始化容器的时候,会根据需要,使用该类的对象,创建AOP代理对象,完成通知到目标切入点方法的织入。该动作就在AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.)方法中完成的。

我们查看AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.)方法里面的源代码如下:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)

throws BeansException {

Object result = existingBean;

for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { ①

Object current = beanProcessor.postProcessAfterInitialization(result, beanName);②

if (current == null) {

return result;

}

result = current;

}

return result;

}

通过阅读上面的源代码,我们可以了解到,该代码是获取容器中所有有注册的BeanPostProcessor(Bean后置处理器),循环的调用每个BeanPostProcessor(Bean后置处理器)的postProcessAfterInitialization方法,对当前的目标对象进行处理(beanName对应的对象)。选择上面代码①行的getBeanPostProcessors()部分代码,点击鼠标右键,选择Wath选项,如图:

点击Watch选项,进入Debug窗口的Expression视图,可以看到getBeanPostProcessors()方法能获取到的,将要遍历调用的所有Bean后置处理器,其中第四个,就是AnnotationAwareAspectJAutoProxyCreator,如下图:

我们循环到第四个后置处理器,继续debug进去,如:

AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(Object, String) line: 437

->AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator).postProcessAfterInitialization(…) line: 304

->AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator).wrapIfNecessary(... ...) line: 340   

1

在wrapIfNecessary(…)方法中,有如下关键代码:

// 获取要织入到beanName目标对象的切入点的所有通知

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, new SingletonTargetSource(bean)); ②

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

return proxy;

}

其中①代码是获取要织入到目标切入点中的所有通知(拦截器对象),我们用Debug中查看变量值的方式,查看specificInterceptors中的所有拦截器对象,如图:

一共有5个通知对象,除了第一个默认通知对象外,剩下4个,都是我们再LogServiceImpl类中,有用通知注解标记后的通知对象,分别是@Before,@After,@AfterReturning和@AfterThrowing,在上图中,标记了@AfterThrowing的关键信息。

真正创建AOP代理对象,完成通知织入动作,是在②行代码,接下来我们继续从②开始Debug进去,过程如:

AbstractAutoProxyCreator.wrapIfNecessary(Object, String, Object) line: 356

->AbstractAutoProxyCreator.createProxy(Class<?>, String, Object[], TargetSource) line: 473

->ProxyFactory.getProxy(ClassLoader) line: 110   

    ->ProxyFactory(ProxyCreatorSupport).createAopProxy() line: 105     

1

2

3

在ProxyCreatorSupport.createAopProxy()方法中,有对ProxyFactory中对AOP创建条件进行了判断(比如在@EnableAspectJAutoProxy注解中,是否有设置proxyTargetClass属性为true等),决定使用CGLIB还是JDK创建AOP代理对象。具体流程,请查看createAopProxy()方法中的源代码和中午注释,如:

if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { ①

Class targetClass = config.getTargetClass();

if (targetClass == null) {

throw new AopConfigException("TargetSource cannot determine target class: " +

“Either an interface or a target is required for proxy creation.”);

}

if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { ①

// 返回基于JDK产生的动态代理对象

return new JdkDynamicAopProxy(config); ②

}

// 返回基于CGLIB产生的动态代理对象

return new ObjenesisCglibAopProxy(config); ③

}

else {

// 返回基于JDK产生的动态代理对象

return new JdkDynamicAopProxy(config); ④

}

我们当前的PowerServiceImpl对象,是面向接口编程的,而且也没有在@EnableAspectJAutoProxy注解中声明属性,当前代码会执行④行代码,我们继续Debug进去,路线如:

DefaultAopProxyFactory.createAopProxy(AdvisedSupport) line: 63

->ProxyFactory(ProxyCreatorSupport).createAopProxy() line: 105

->ProxyFactory.getProxy(ClassLoader) line: 110   

    ->JdkDynamicAopProxy.getProxy(ClassLoader) line: 123       

1

2

3

这时候就进入了JDK里面的java.lang.reflect.Proxy类,进行SpringAOP的动态对象的创建(AOP代理对象),我们就找到了Spring中使用AnnotationAwareAspectJAutoProxyCreator组件,完成AOP代理对象的创建过程。

06

总结

通过前面的源代码的风险和跟踪,可以得出如下结论

1)通过在配置类上面添加@EnableAspectJAutoProxy注解,通知Spring容器支持注解AspectJ,实现面向AOP编程。

2)使用@Aspect、@Pointcut、@Before、@After、@AfterReturning、@AfterThrowing和@Arount注解,完成切面的声明,切入点的声明和各种通知的声明。

3)Spring容器中,是通过AnnotationAwareAspectJAutoProxyCreator对象,在目标对象初始化完后,利用BeanPostProcessor后置通知的机制,完成对目标对象的AOP对象创建。

4)AnnotationAwareAspectJAutoProxyCreator对象内部,是封装JDK和CGlib两个技术,实现动态代理对象创建的。

5)Spring里面,使用JDK还是CGLIB,可以在@EnableAspectJAutoProxy中设置proxyTargetClass属性指定,也可以通过Spring自己判断,目标对象类是否实现了接口,有实现接口,就使用JDK,否则就使用CGLIB。

喜欢这篇文章的可以给笔者点个赞,关注一下,每天都会分享Java相关文章!还有不定时的福利赠送,包括整理的学习资料,面试题,源码等~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • Spring 知识点提炼 2018/1/16 | 分类: 基础技术 | 0 条评论 | 标签: SPRING 分享...
    有你就行阅读 438评论 0 0
  • IOC和DI是什么? Spring IOC 的理解,其初始化过程? BeanFactory 和 FactoryBe...
    justlpf阅读 3,377评论 1 21
  • 告别了漫长而暴躁的考试周,总归不用一天好几包巧克力的度过,日子过的啊,说充实也充实,说空虚,也不算过分。 回家了之...
    西有葳蕤阅读 227评论 0 0
  • 现在我大三,在大学期间读过的书我也不知道有几本,肯定不算多,因为我并不是个热爱阅读的人。让我去翻开书页的驱动力只是...
    自牧襄荑阅读 181评论 0 0
  • ――微韵 楼底春烟高处飞,绿梅红杏出宫闱。 风中摇曳千般好,只待花间燕子归。 ――鱼韵 二月新晴出太虚,烟光城内照...
    闲人四季阅读 287评论 4 15