Spring 版本 4.3.2

在拿到 Bean 实例以后,会经历一系列的初始化工作,如:工厂回调、init 方法、后处理器在 Bean 初始化前后的处理等,在一般情况下(非 factory-method 创建的 Bean 等),AOP代理对象的创建就在后处理器的处理方法中实现。

入口

以 AbstractAutowireCapableBeanFactory 类中的 initializeBean 方法作为起始点进行跟踪

/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
*
* 初始化给定的 bean 实例,应用工厂回调方法以及 init 方法和 bean 的后处理器。
* 该方法会被传统定义 bean 的 createBean 方法所调用,也会被重载方法所引用
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) { // 后处理器的前调用
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) { // 初始化后,进行后处理器的后调用,跟踪此方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

依然在 AbstractAutowireCapableBeanFactory 类中。

拿到 BeanFactory 中所有针对 Bean 的后处理器集合,依次调用。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) { // 利用处理器的处理方法,对 bean 实例进行处理,并返回一个对象
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

注册创建器

在后处理器集合中,有一个处理器叫做 AnnotationAwareAspectJAutoProxyCreator 创建器,该处理器在解析<aop:config>标签、或者解析相关注解时被注册到工厂中,如下:

// 如果必要的话注册AspectJ自动代理创建器
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { // 传递了 AspectJAwareAdvisorAutoProxyCreator 的 Class,进入这个方法
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
} private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //工厂中是否已经注册了 org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); //如果已经有注册了 internalAutoProxyCreator,并且和入参传递的Class不是同一个Class,
//那么就根据优先级进行选择
if (!cls.getName().equals(apcDefinition.getBeanClassName())) { //类 AopConfigUtils 中有个 ArrayList 属性 APC_PRIORITY_LIST,在类静态构造中依次加入了
//几个创建器,这个方法就是查找某个创建器在 APC_PRIORITY_LIST 中的索引,如果没有找到就报错
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls); // internalAutoProxyCreator 的索引为0,入参的 AspectJAwareAdvisorAutoProxyCreator
// 索引为1,后者要大,所以重新设置下 apcDefinition 的 beanClass
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
} //直接返回null
return null;
} // 如果没有注册 internalAutoProxyCreator ,组装一个 Bean Definition,以
// AspectJAwareAdvisorAutoProxyCreator 作为 bean Class,然后注册到工厂中
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

从上面可以看见创建器 AnnotationAwareAspectJAutoProxyCreator 的注册经过,Bean Definition 是对 Bean 的描述,创建 bean 对象时,会以 Bean Definition 为依据进行实例化和初始化。

postProcessAfterInitialization

查看创建器的处理方法postProcessAfterInitialization

该方法在创建器的超类 AbstractAutoProxyCreator 中实现

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
*
* 如果 bean 被定义为子类代理,则使用已配置的拦截器创建代理
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) { // 缓存中没有的情况
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
} /**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
*
* 必要的话包装给定的 bean,即,他有资格被代理
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
} // advisedBeans 存放 bean 是否可以被代理的信息,作为缓存,避免重复判断
// Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
} if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 如果 bean 是一些特殊的类,比如 Pointcut/Advisor,又或者没有 @Aspect 注解等
// 这些 bean 不应该被代理,信息存放到 advisedBeans 集合中
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} // Create proxy if we have advice.
// 如果有通知,创建代理 // 拿到所有匹配该 bean 的通知,如果使用了切入点表达式或者 AspectJ 风格的增强,
// 还需要在通知链的开始处添加 ExposeInvocationInterceptor 拦截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) { // 通知链不为null,可以代理
this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理对象,进入跟踪
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 存放已经生成代理对象的类信息
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

创建代理

该方法在 AbstractAutoProxyCreator 中实现

/**
* Create an AOP proxy for the given bean.
*
* 为指定的 bean 创建一个 AOP 代理
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { // 在 beanFactory 中,beanName 有对应的 BeanDefinition,此方法就是为 BeanDefinition 的
// attributes 属性添加键值对,key 为 xxx.originalTargetClass , value 包含了 targetSource
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
} ProxyFactory proxyFactory = new ProxyFactory(); // 将创建器中的一些属性拷贝到新创建的代理工厂
proxyFactory.copyFrom(this); // proxyTargetClass 属性对代理方式的确定有非常大的影响
// 当从创建器中拷贝的属性 proxyFactory 为 false 时,下面的两个方法需要详细跟踪
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
} // 对拦截器或者通知进行包装,包装成Advisor对象
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 在代理工厂中添加 Advisor 通知链
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource); // 子类中如果没有覆盖,那么此方法为空实现
customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
} // 通过代理工厂获取代理
return proxyFactory.getProxy(getProxyClassLoader());
}

proxyTargetClass 布尔属性值的确定对代理方式有着非常大的影响。

当配置了<aop:aspectj-autoproxy>,使用注解方式时;又或者是使用xml配置<aop:config>时,两个标签都具有的proxy-target-class属性默认为 false

那么上述步骤创建 ProxyFactory 对象时,从创建器中拷贝的 proxyTargetClass 属性则为 false,进入条件

if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

先看第一个方法shouldProxyTargetClass

shouldProxyTargetClass

该方法在 AbstractAutoProxyCreator 中实现

/**
* Determine whether the given bean should be proxied with its target class rather than its interfaces.
* <p>Checks the {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
* of the corresponding bean definition.
*
* 确定给定的bean是否应该使用其目标类而不是其接口进行代理。
* 检查对应 bean definition 的 preserveTargetClass 属性。
*/
protected boolean shouldProxyTargetClass(Class<?> beanClass, String beanName) { return (this.beanFactory instanceof ConfigurableListableBeanFactory &&
AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName)); }

工厂默认实现 DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口。

跟踪 AutoProxyUtils 类的 shouldProxyTargetClass 方法。

public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {

    // 工厂中有对应 beanName 的 bean definition 则进入条件
if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName); // bean definition 的 attributes 属性中是否有
// org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass
// 为 key 的属性,且 value 为 ture
return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
}
return false;
}

如果被代理 bean 对应的 bean definition 属性中,存在org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass为 key,且 值为 true 的 attributes

那么设置 proxyTargetClass 为 ture

再看第二个方法

evaluateProxyInterfaces

该方法在类 ProxyProcessorSupport 中实现,ProxyProcessorSupport 是 AbstractAutoProxyCreator 的父类

/**
* Check the interfaces on the given bean class and apply them to the {@link ProxyFactory},
* if appropriate.
* <p>Calls {@link #isConfigurationCallbackInterface} and {@link #isInternalLanguageInterface}
* to filter for reasonable proxy interfaces, falling back to a target-class proxy otherwise.
*
* 检查指定 bean class 上的接口,如果合适的话设置到 ProxyFactory 中。
* 调用 isConfigurationCallbackInterface 方法和 isInternalLanguageInterface 方法去过滤得到
* 合理的代理接口,否则回退到 target-class proxy
*/
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) { // 此方法拿到类上及其父类上,所有的接口,不会递归获取接口上的接口
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false; // 遍历所有的接口,并进行过滤
for (Class<?> ifc : targetInterfaces) { // 接口中不能有像 Aware、InitializingBean 等容器的回调接口
// 接口的 ClassName 也不能是以 .cglib.proxy.Factory 结尾或者是 groovy.lang.GroovyObject
// 这样的内部语言接口
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
ifc.getMethods().length > 0) { // 如果还有接口剩余,则存在合适的代理接口
hasReasonableProxyInterface = true;
break;
}
}
if (hasReasonableProxyInterface) { // 将代理接口一个个添加到 proxyFactory 中
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
}
else { // 否者 proxyTargetClass 属性设置为 true
proxyFactory.setProxyTargetClass(true);
}
}

总结一下两个方法

当 xml 中没有配置 proxyTargetClass 属性,默认为 false

如果被代理 bean 对应的 bean definition ,它的 attributes 属性中,存在org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass为 key,值为 true 的键值对

那么设置 proxyTargetClass 为 ture

否则过滤所有接口,接口不能为 Aware、InitializingBean 等容器的回调接口,也不能是内部语言接口

如果没有合适的接口,proxyTargetClass 还是设置为 true 。

接下来看下代理工厂获取代理的流程。

getProxy

进入 ProxyFactory 类中,跟踪 getProxy 方法

/**
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses the given class loader (if necessary for proxy creation).
*
* 根据这个 factory 的设置创建一个新的代理。
* 可以被重复调用。如果我们添加或者移除了接口,会有影响。
* 可以添加和移除拦截器。
* 使用指定的类加载器(如果需要代理创建)
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

先跟踪 createAopProxy 方法,此方法在 ProxyCreatorSupport 类中实现,ProxyFactory 是其子类。

/**
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with {@code this} as an argument.
*
* 子类应该调用这个方法去获得一个新的AOP代理。他们不应该用 this 作为参数创建一个AOP代理
*/
protected final synchronized AopProxy createAopProxy() { // 当AOP代理第一次被创建时,active会被设置为true
if (!this.active) { // 设置 active 为 true,激活代理配置
activate();
}
return getAopProxyFactory().createAopProxy(this);
}

getAopProxyFactory 方法拿到的是 DefaultAopProxyFactory 的实例,它的接口是 AopProxyFactory

ProxyFactory 类间接继承 AdvisedSupport ,AdvisedSupport 继承 ProxyConfig ,作为配置存在

ProxyFactory 类和 DefaultAopProxyFactory 并没有继承关系

以 ProxyFactory 类的实例为参数,调用 createAopProxy 方法,继续跟踪

createAopProxy

此方法在 DefaultAopProxyFactory 类中实现,采用 JDK proxy 代理还是使用 cglib 代理,在这个方法中决定

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

isOptimize 方法就是返回 ProxyFactory 的 optimize 属性,为布尔值

是否执行积极优化的含义。

优化通常意味着,在代理创建后,通知的变化不会带来影响,默认下为 false。

optimize 在此处也被作为了一个判断依据。

optimize 可以参考文章:https://blog.csdn.net/zh199609/article/details/79710846

isProxyTargetClass 方法拿的则是 ProxyFactory 的 proxyTargetClass 属性,前面已经跟踪过。

hasNoUserSuppliedProxyInterfaces 方法在代理接口不存在,或者只有一个且是 SpringProxy 接口的子接口情况下,才返回 true 。

当上述三个方法都返回 false 时,代理才走的 JDK proxy 代理,也就是接口代理。

当满足其中一个条件,进入方法后,还有一层筛选,要么 target Class 是一个接口,要么是 Proxy 类的子类,否则其余情况都使用 cglib 代理,也就是类代理。

最后调用代理的 getProxy 方法。不同代理的实现,其实就是spring对 JDK 的 Proxy,或者 cglib 的 Enhancer 的封装。最终完成AOP的实现。

SpringAOP源码跟踪及学习的更多相关文章

  1. SpringAop源码情操陶冶-JdkDynamicAopProxy

    承接前文SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator,本文在前文的基础上稍微简单的分析默认情况下的AOP代理,即JDK静态代理 JdkDyna ...

  2. Java关于ReentrantLock获取锁和释放锁源码跟踪

    通过对ReentrantLock获取锁和释放锁源码跟踪主要想进一步深入学习AQS. 备注:AQS中的waitStatus状态码含义:

  3. [源码解析] 深度学习分布式训练框架 horovod (12) --- 弹性训练总体架构

    [源码解析] 深度学习分布式训练框架 horovod (12) --- 弹性训练总体架构 目录 [源码解析] 深度学习分布式训练框架 horovod (12) --- 弹性训练总体架构 0x00 摘要 ...

  4. [源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练发现节点 & State

    [源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练发现节点 & State 目录 [源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练 ...

  5. [源码解析] 深度学习流水线并行 GPipe(3) ----重计算

    [源码解析] 深度学习流水线并行 GPipe(3) ----重计算 目录 [源码解析] 深度学习流水线并行 GPipe(3) ----重计算 0x00 摘要 0x01 概述 1.1 前文回顾 1.2 ...

  6. [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段

    [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段 目录 [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段 0x00 摘要 0x0 ...

  7. spring security 授权方式(自定义)及源码跟踪

    spring security 授权方式(自定义)及源码跟踪 ​ 这节我们来看看spring security的几种授权方式,及简要的源码跟踪.在初步接触spring security时,为了实现它的 ...

  8. DICOM医学图形处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求(续)

    转载:http://blog.csdn.net/zssureqh/article/details/39237649 背景: 上一篇博文中,在对storescp工具源文件storescp.cc和DcmS ...

  9. DICOM医学图像处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求

    转载:http://blog.csdn.net/zssureqh/article/details/39213817 背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间w ...

随机推荐

  1. color转成image对象

    .h //颜色转换成图片 + (UIImage *)imageFromColor:(UIColor *)color; .m //颜色转换成图片 + (UIImage *)imageFromColor: ...

  2. Airless Pump Bottle For The Rise Of Cosmetic Packaging Solutions

    Airless Pump Bottle    are used in the rise of cosmetic packaging solutions. According to the suppli ...

  3. Solr搜索引擎服务器学习笔记

    Solr简介 采用Java5开发,基于Lucene的全文搜索服务器.同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置.可扩展并对查询性能进行了优化,并且提供了一个完善的功能 ...

  4. Hibernate框架:org.hibernate.exception.SQLGrammarException: Cannot open connection at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java92)

    报错信息 org.hibernate.exception.SQLGrammarException: Cannot open connection at org.hibernate.exception. ...

  5. 夯实Java基础(十九)——集合

    1.前言 集合在Java中的地位想必大家都知道,不用多BB了.无论是在我们现在的学习中还是在今后的工作中,集合这样一个大家族都无处不在,无处不用.在前面讲到的数组也是一个小的容器,但是数组不是面向对象 ...

  6. 02-06Android学习进度报告六

    今天学习了关于Android开发中常用的两个知识,即对话框和悬浮框. 首先我学习了对话框的基本使用流程 Step 1:创建AlertDialog.Builder对象: Step 2:调用setIcon ...

  7. MySQL : INSERT INTO SELECT

    INSERT INTO wx_announcement_push ( title, content, STATUS, del_flag, user_login_name ) SELECT '大家好', ...

  8. C/C++ - CallBack

    这是实验楼上一个callback debug例子,我没有提交结果,但在本地上运行没有任何问题,也无警告: #include <stdio.h> #define MAX 3 typedef ...

  9. A easy and simple way to establish Oracle ADG

    Yes, thanks to Then, I can give simple and reasy way to make it. Suppose hosts and IPs like that: 15 ...

  10. 设计模式课程 设计模式精讲 22-2 备忘录模式coding

    1 代码演练 1.1 代码演练1 1 代码演练 1.1 代码演练1 需求: 网站笔记需要存储快照,能实现回退的功能. 注意: a 设计的时候,可以分为笔记类,笔记快照类和 笔记快照管理类  三个类. ...