通過上一篇文章Spring Bean的創(chuàng)建過程及相關(guān)擴展點的介紹豫领,我們知道getBean()創(chuàng)建Bean實例的過程赞枕,有以下幾個擴展點:
- Bean實例創(chuàng)建之前實現(xiàn)InstantiationAwareBeanPostProcessor接口
- Bean實例創(chuàng)建成功后,未設置屬性時怎憋,立馬創(chuàng)建一個工廠方法姨丈。可通過實現(xiàn)SmartInstantiationAwareBeanPostProcessor接口對Bean增強
- Bean初始化的生命周期中埃难,實現(xiàn)BeanPostProcessor接口對Bean增強
SpringBoot如何實現(xiàn)Aop:
1.先從spring-boot-autoconfigure包下面的/META-INF/spring.factories開始莹弊,可以發(fā)現(xiàn)AopAutoConfiguration這個類涤久,說明在引入spring-boot-autoconfigure這個jar包后,就會自動加載AopAutoConfiguration忍弛。
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
主要是看EnableAspectJAutoProxy這個注解响迂,無論如何,這個注解都會生效
@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;
}
進一步看一下
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 這是重點------這是重點------這是重點------
// 這里就是注入AnnotationAwareAspectJAutoProxyCreator對象入口
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);
}
}
}
}
AnnotationAwareAspectJAutoProxyCreator類的UML圖可以看到细疚,AnnotationAwareAspectJAutoProxyCreator這個類是實現(xiàn)了InstantiationAwareBeanPostProcessor蔗彤、SamrtInstantiationAwareBeanPostProcessor、BeanPostProcessor接口的惠昔,那么說明這個類是可以在Bean實例創(chuàng)建過程中幕与,對Bean創(chuàng)建過程進行攔截和增強的。
同樣的镇防,AspectJAwareAdvisorAutoProxyCreator這個類其實就是基于XML配置來對Bean進行攔截和增強的啦鸣。
1.在Bean實例化之前:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 這是重點----這是重點-----這是重點
// 從這里可以看出,這又是一種創(chuàng)建Bean實例的方式
// 通過自定義的TargetSource來創(chuàng)建Bean實例来氧。屬于非常規(guī)用法诫给。
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 收集所有的Advisor后,通過MethodInterceptor創(chuàng)建代理啦扬。具體的實現(xiàn)可以是JDK或者CGLIB
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
在此基礎上中狂,我們可以自定義一個BeanPostProcessor,針對AnnotationAwareAspectJAutoProxyCreator進行攔截扑毡,在AnnotationAwareAspectJAutoProxyCreator初始化生命周期中胃榕,給它創(chuàng)建一個TargetSource對象設置進去,這樣就可以促使getCustomTargetSource()方法生效了瞄摊。
2.另一個就是在Bean實例化后勋又,把Bean對象放進第三級緩存中
// AbstractAutowireCapableBeanFactory類中587行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// ********這是關(guān)鍵點********這是關(guān)鍵點********這是關(guān)鍵點********這是關(guān)鍵點********
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
// AbstractAutoProxyCreator類中237行,AbstractAutoProxyCreator是SmartInstantiationAwareBeanPostProcessor子類换帜,是實現(xiàn)AOP的入口
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// ********這是關(guān)鍵點********這是關(guān)鍵點********這是關(guān)鍵點********這是關(guān)鍵點********
return wrapIfNecessary(bean, beanName, cacheKey);
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 獲取所有的Advisor實例楔壤,并篩選出匹配的Advisor實例
// 獲取Advisor的方式也是通過getBean()的方式,根據(jù)指定目標為Advisor.class查找
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根據(jù)篩選出來的Advisor實例惯驼,創(chuàng)建代理對象
// 如何創(chuàng)建的代理蹲嚣,其實就是使用了JDK動態(tài)代理或者CGLIB動態(tài)代理實現(xiàn)
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回增強后的Bean對象
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
3.Bean初始化后
// AbstractAutoProxyCreator類中295行
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// ********這是關(guān)鍵點********同上********同上********這是關(guān)鍵點********
// 和上面的wrapIfNecessary()一樣
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
根據(jù)AbstractAutoProxyCreator來看,AOP切入的點有三個地方:
1.postProcessBeforeInstantiation():就是在Bean還沒有創(chuàng)建出來之前祟牲,這個點是留給開發(fā)者自己擴展的隙畜。針對自定義TargetSource,檢查是否有匹配的Advisor说贝,如果有的話禾蚕,那么就創(chuàng)建對應的代理對象。
2.postProcessAfterInitialization():這個就是Bean已經(jīng)完成了初始化了狂丝,這個時候的Bean已經(jīng)準備發(fā)布了换淆,那么針對這個Bean對象,檢查是否有匹配的Advisor几颜,有的話倍试,就創(chuàng)建對應的代理對象。
3.getEarlyBeanReference():這個就是Bean剛剛創(chuàng)建出來蛋哭,還沒有設置屬性值县习,還不能發(fā)布,但是為了解決循環(huán)依賴的問題谆趾,需要先把這個Bean的引用發(fā)布出去躁愿。那么針對這個Bean就要檢查是否有匹配的Advisor,有的話沪蓬,創(chuàng)建代理對象彤钟。
在這三個擴展點,分別會做以下幾件事情:
1.findCandidateAdvisors()方法獲取所有的Advisor實例跷叉,并存放到一個數(shù)組里面逸雹;原理還是getBean()方式查找Advisor.class所有實例
2.findAdvisorsThatCanApply()方法從數(shù)組中篩選出攔截這個Bean的Advisor,有攔截class的云挟,也有method梆砸;主要區(qū)分出IntroductionAdvisor、PointcutAdvisor园欣;
- 2.1:IntroductionAdvisor只能攔截class帖世,PointcutAdvisor可以攔截method和class。
3.針對篩選出來的Advisor排序
4.根據(jù)篩選出來的Advisor對象沸枯,通過ProxyFactory.getProxy()創(chuàng)建代理日矫。
另外,再介紹兩個手動編程創(chuàng)建代理對象的類:
- AspectJProxyFactory
- 這個類包含兩個功能:創(chuàng)建代理的功能辉饱;處理Advisor搬男、Advice的功能
- ProxyFactory
- 這個類只能創(chuàng)建代理,Advisor彭沼、Advice需要自己手動創(chuàng)建
以上兩個類的區(qū)別在于缔逛,AspectJProxyFactory這個類里面有一個ReflectiveAspectJAdvisorFactory對象屬性專門用來處理并生成Advisor、Advice姓惑。
共同點就是都能創(chuàng)建代理對象褐奴,主要是因為這兩個類都繼承自ProxyCreatorSupport。