Spring的兩大核心功能是IOC和AOP。當我們使用Spring的AOP功能時是很方便的。只需要進行下面的配置即可。
Copy@Component @Aspect public class MyAspect { //PointCut匹配的方法必須是Spring中bean的方法 //Pointcut可以有下列方式來定義或者通過&& || 和!的方式進行組合. //下面定義的這些切入點就可以通過&& ||組合 private static Logger logger = LoggerFactory.getLogger(MyAspect.class); //*:代表方法的返回值可以是任何類型 //整個表達式匹配controller包下面任何的的echo方法,方法入參樂意是任意 @Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(..))") public void pointCut1(){} @Before("pointCut1()") public void befor(){ logger.info("前置通知vvvv..."); logger.info("我要做些事情..."); } }
然後再開啓註解
Copy//自動選擇合適的AOP代理 //傳統xml這樣配置:<aop:aspectj-autoproxy/> //exposeProxy = true屬性設置成true,意思是將動態生成的代理類expose到AopContext的ThreadLocal線程 //可以通過AopContext.currentProxy();獲取到生成的動態代理類。 //proxyTargetClass屬性設置動態代理使用JDK動態代理還是使用CGlib代理,設置成true是使用CGlib代理,false的話是使用JDK動態代理 //注意:如果使用Spring Boot的話,下面的配置可以不需要。AopAutoConfiguration這個自動配置類中已經自動開啓了AOP //默認使用CGLIB動態代理,Spring Boot配置的優先級高於下面的配置 @Configuration @EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = false) public class AopConfig { }
通上面的配置,當我們調用controller包下面的任何類的echo方法時就會觸發前置通知。其實這個說法不是很準確。因爲我們調用的類已經不是我們自己寫的類了。而是Spring框架通過動態代理生成的類。
稍微瞭解一點Spring AOP的同學都會知道Spring的AOP是通過動態代理實現的。那Spring是怎麼生成動態代理類,並將Advice織入代理類的呢?整個流程是怎樣的呢?下面就分析下Spring生成動態代理類的過程。
需要說明下的是,本博客旨在梳理整個AOP動態代理的過程,細節方面需要大家自己去看。
@EnableAspectJAutoProxy幹了些啥
如果讓你從頭開始研究下AOP的原理,你是不是一頭霧水,根本不知道從何入手。但其實看Spring的代碼有個小技巧:如果你要研究一個功能,可以從開啓這個功能的Enable註解開始看。Spring的很多功能都是通過Enable註解開啓的,所以這些註解肯定和這些功能相關。
那麼這邊我們可以從@EnableAspectJAutoProxy這個註解開始着手,看下這個註解做了些什麼操作。
Copy@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { //設置爲true的話就一直使用cglib動態代理 //設置爲false的話,對於接口使用jdk動態代理,對於類使用cglib代理 boolean proxyTargetClass() default false; boolean exposeProxy() default false; }
看到上面的@Impoer註解,我們很自然就會想到去看AspectJAutoProxyRegistrar這個類。
Copy//AspectJAutoProxyRegistrar源代碼 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * 主要作用也就是註冊AnnotationAwareAspectJAutoProxyCreator */ @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //註冊AnnotationAwareAspectJAutoProxyCreator的BeanDefinition AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { //給上面註冊的BeanDefinition中添加兩個屬相proxyTargetClass和exposeProxy if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
我們可以看到上面的類中也沒幹什麼特別的事情,就註冊了一個BeanDefinition。如果我們點進去看下
AnnotationAwareAspectJAutoProxyCreator這個類的源代碼會發現這個類竟然實現了
InstantiationAwareBeanPostProcessor這個接口。熟悉Spring尿性的朋友會敏銳的感覺到Spring可能是在
postProcessBeforeInstantiation或者
postProcessAfterInstantiation這些方法中對Bean進行動態代理的。
“大膽假設,小心求證”,讓我們帶着這個猜想去看看
AnnotationAwareAspectJAutoProxyCreator到底幹了些什麼?
AnnotationAwareAspectJAutoProxyCreator生成動態代理類
Copy@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; } } // 一般不指定CustomTargetSource,所以不會進入這段代碼,所以關鍵代碼在 // postProcessAfterInitialization中 // 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); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
下面是創建動態代理類的關鍵代碼。
Copy@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { //這邊是創建代碼類的關鍵代碼 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
Copyprotected 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; } // Create proxy if we have advice. //獲取當前Bean配置的advice,這步是關鍵 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; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
層層dedug進去我們能看到下面這段代碼,我們口中常說的JDK動態代理和Cglib動態代理就是在這邊生成的。
Copypublic class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override 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)) { //生成JDK動態代理 return new JdkDynamicAopProxy(config); } //生成Cglib動態代理 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } /** * Determine whether the supplied {@link AdvisedSupport} has only the * {@link org.springframework.aop.SpringProxy} interface specified * (or no proxy interfaces specified at all). */ private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); }
到此,我們已經簡單分析了Spring動態代理類的生成流程。
PS:關於
InstantiationAwareBeanPostProcessor接口和BeanPostProcessor接口大家可以自行了解下,這兩個接口是Spring中非常重要的接口。看懂了這兩個接口,Spring很多“神祕”的功能你就能理解了。
簡單總結
通過上面分析,其實我們發現如果不去看AOP動態代理類生成的細節的話,整個Spring AOP的流程還是挺簡單的:
- @EnableAspectJAutoProxy註解通過AopConfigUtils這個工具類註冊AnnotationAwareAspectJAutoProxyCreator這個類,這個類實現了InstantiationAwareBeanPostProcessor接口,所以會在Bean實例化前後對Bean做一系列額外的操作;
- AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization中會找出所有和當前Bean相關的Advice,如果找到就創建相應的動態代理類,如果找不到就不生成,返回原始類。
所以整個大流程就這麼簡單。
一些重要類:
- @EnableAspectJAutoProxy;
- AspectJAutoProxyRegistrar:註冊AnnotationAwareAspectJAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator:AOP動態代理自動生成的處理類,其他類似的類有AspectJAwareAdvisorAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator等;
- AopConfigUtils:AOP配置工具類
- ProxyFactory:代理工廠
- AopProxy接口:常見實現類ObjenesisCglibAopProxy、JdkDynamicAopProxy
而這些的學習當然不是隻看源碼就能整明白,肯定有輔助的呀
書籍
除了spring之外,我還整理了一些其他的資料,一併送給大家
需要這些文檔資料,關注+轉發後,私信“資料”即可查看獲取方式
視頻:
Spring一百集出於篇幅原因,只展示一部分
需要這些資料,關注+轉發後,私信“資料”查看獲取方式