一,例子準備
切面類:LogUtil.java
@Aspect
@Component
public class LogUtil {
@Pointcut("execution(public Integer com.mashibing.aop.annotation.service.MyCalculator.*(Integer,Integer))")
public void myPointCut(){}
@Around("myPointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
Object[] args = pjp.getArgs();
Object result = null;
try {
System.out.println("log---環繞通知start:"+signature.getName()+"方法開始執行,參數為:"+Arrays.asList(args));
result = pjp.proceed(args);
System.out.println("log---環繞通知stop"+signature.getName()+"方法執行結束");
} catch (Throwable throwable) {
System.out.println("log---環繞異常通知:"+signature.getName()+"出現異常");
throw throwable;
}finally {
System.out.println("log---環繞傳回通知:"+signature.getName()+"方法傳回結果是:"+result);
}
return result;
}
@Before(value = "myPointCut()")
private int start(JoinPoint joinPoint){
//擷取方法簽名
Signature signature = joinPoint.getSignature();
//擷取參數資訊
Object[] args = joinPoint.getArgs();
System.out.println("log---"+signature.getName()+"方法開始執行:參數是"+Arrays.asList(args));
return 100;
}
@After("myPointCut()")
public static void logFinally(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
System.out.println("log---"+signature.getName()+"方法執行結束。。。。。over");
}
@AfterReturning(value = "myPointCut()",returning = "result")
public static void stop(JoinPoint joinPoint,Object result){
Signature signature = joinPoint.getSignature();
System.out.println("log---"+signature.getName()+"方法執行結束,結果是:"+result);
}
@AfterThrowing(value = "myPointCut()",throwing = "e")
public static void logException(JoinPoint joinPoint,Exception e){
Signature signature = joinPoint.getSignature();
System.out.println("log---"+signature.getName()+"方法抛出異常:"+e.getMessage());
}
}
需要被代理的類:MyCalculator.java
@Service
public class MyCalculator {
public Integer add(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i+j;
return result;
}
public Integer sub(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i-j;
return result;
}
public Integer mul(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i*j;
return result;
}
public Integer div(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i/j;
return result;
}
public Integer show(Integer i){
System.out.println("show .....");
return i;
}
}
配置類:SpringConfiguration.java
@Configuration
@ComponentScan(basePackages = "com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
測試類:MyTest.java
public class MyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
}
}
二,源碼分析
1,AnnotationAwareAspectJAutoProxyCreator的注入
在
invokeBeanFactoryPostProcessors()
方法中,會去執行ConfigurationClassPostProcessor(BFPP)的postProcessBeanDefinitionRegistry()方法,用于解析
SpringConfiguration
配置類:
@Configuration
@ComponentScan(basePackages = "com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
@EnableAspectJAutoProxy
注解類:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
首先,解析
@ComponentScan
注解,把
com.bobo.aop.annotation
包名下面的被
@Component
注解修飾的
LogUtil.java
和
MyCalculator.java
注入到
BeanFactory
容器的
BeanDefinitionMap
中。
其次,解析
@Import(AspectJAutoProxyRegistrar.class)
注解,并執行個體化
AspectJAutoProxyRegistrar
類,發現其實作了
ImportBeanDefinitionRegistrar
接口,并且調用其
registerBeanDefinitions()
方法:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 注冊、更新和配置自動代理建立器依賴對應的proxyTargetClass屬性在解析@Configuration類
*/
@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);
}
}
}
}
方法中調用
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
方法把AnnotationAwareAspectJAutoProxyCreator.class包裝成BeanDefinition注入到BeanDefinitionMap中:
public abstract class AopConfigUtils {
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 注入AnnotationAwareAspectJAutoProxyCreator.class
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注入帶BeanDefinitionMap中
// AUTO_PROXY_CREATOR_BEAN_NAME=org.springframework.aop.config.internalAutoProxyCreator
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
}
2,AnnotationAwareAspectJAutoProxyCreator類介紹

AnnotationAwareAspectJAutoProxyCreator繼承于AspectJAwareAdvisorAutoProxyCreator,主要負責對使用注解定義的@Aspect進行查找和解析。
- AspectJAwareAdvisorAutoProxyCreator:當我們使用xml進行定義切面時會注入此類
- AnnotationAwareAspectJAutoProxyCreator:當我們使用
注解方式來定義切面時會注入此類@EnableAspectJAutoProxy
AbstractAdvisorAutoProxyCreator
的
findCandidateAdvisors()
方法定義的是從BeanDefinitionMap中查找
Advisor
類,是以
AspectJAwareAdvisorAutoProxyCreator
繼承了此方法,符合xml方式的定義查找
Advisor
類。
但是注解方式是對XMl的擴充,AnnotationAwareAspectJAutoProxyCreator繼承于
AspectJAwareAdvisorAutoProxyCreator
并且重寫了
findCandidateAdvisors()
,加入了注解的方式去掃描Advisor。例如去掃描我們本例子所定義的
LogUtil
切面類。
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
/**
* 查找Advisor
*/
@Override
protected List<Advisor> findCandidateAdvisors() {
// 調用父類方法從BeanDefinitionMap中查找Advisor接口的BeanDefinition,并執行個體化
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
// 注解方式的擴充,查找使用注解定義的@Aspect
// 找到系統中使用@Aspect标注的bean,并且找到該bean中使用@Before,@After等标注的方法,
// 将這些方法封裝為一個個Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
}
3,代理類的建立
本例子中依然是
MyCalculator.java
需要建立代理類,當然,配置類
SpringConfiguration.java
也是需要被建立代理的,我們前面文章已經對配置類做了分析,不了解的請移步吃透Spring源碼(十六):ConfigurationClassPostProcessor詳細介紹
這裡以執行個體化MyCalculator來分析:
源碼還是在getBean()—>doGetBean()—>createBean()—>doCreateBean()—>initializeBean()—>applyBeanPostProcessorsAfterInitialization()執行Bean的後置處理器
AnnotationAwareAspectJAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 擷取目前bean的key:如果beanName不為空,則以beanName為key,如果為FactoryBean類型,
// 前面還會添加&符号,如果beanName為空,則以目前bean對應的class為key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 判斷目前bean是否正在被代理,如果正在被代理則不進行封裝
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果它需要被代理,則需要封裝指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 擷取目前bean的Advices和Advisors
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 對目前bean的代理狀态進行緩存
if (specificInterceptors != DO_NOT_PROXY) {
// 對目前bean的代理狀态進行緩存
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根據擷取到的Advices和Advisors為目前bean生成代理對象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 緩存生成的代理bean的類型,并且傳回生成的代理bean
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
調到父類的postProcessAfterInitialization()方法中,然後在wrapIfNecessary()方法中查找Advisor并建立代理類!
在wrapIfNecessary中查找Advisor會調用到子類
AnnotationAwareAspectJAutoProxyCreator
來查找注解定義的Advisor并執行個體化。
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
/**
* 查找Advisor
*/
@Override
protected List<Advisor> findCandidateAdvisors() {
// 調用父類方法從BeanDefinitionMap中查找Advisor接口的BeanDefinition,并執行個體化
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
// 注解方式的擴充,查找使用注解定義的@Aspect
// 找到系統中使用@Aspect标注的bean,并且找到該bean中使用@Before,@After等标注的方法,
// 将這些方法封裝為一個個Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
}
其中
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors()
是對注解定義的Advisor進行查找和初始化:
public class BeanFactoryAspectJAdvisorsBuilder {
/**
* 尋找Aspect注解的切面,然後解析他的方法,通過注解來生成對應的通知器Advisor
*/
public List<Advisor> buildAspectJAdvisors() {
// 擷取切面名字清單
List<String> aspectNames = this.aspectBeanNames;
// 緩存字段aspectNames沒有值,注意執行個體化第一個單執行個體bean的時候就會觸發解析切面
if (aspectNames == null) {
// 雙重檢查
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 用于儲存所有解析出來的Advisors集合對象
List<Advisor> advisors = new ArrayList<>();
// 用于儲存切面的名稱的集合
aspectNames = new ArrayList<>();
/**
* AOP功能中在這裡傳入的是Object對象,代表去容器中擷取到所有的元件的名稱,然後再
* 進行周遊,這個過程是十分的消耗性能的,是以說Spring會再這裡加入了儲存切面資訊的緩存。
* 但是事務功能不一樣,事務子產品的功能是直接去容器中擷取Advisor類型的,選擇範圍小,且不消耗性能。
* 是以Spring在事務子產品中沒有加入緩存來儲存我們的事務相關的advisor
*/
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 周遊我們從IOC容器中擷取處的所有Bean的名稱
for (String beanName : beanNames) {
// 判斷目前bean是否為子類定制的需要過濾的bean
if (!isEligibleBean(beanName)) {
continue;
}
// 通過beanName去容器中擷取到對應class對象
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判斷目前bean是否使用了@Aspect注解進行标注
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// 對于使用了@Aspect注解标注的bean,将其封裝為一個AspectMetadata類型。
// 這裡在封裝的過程中會解析@Aspect注解上的參數指定的切面類型,如perthis
// 和pertarget等。這些被解析的注解都會被封裝到其perClausePointcut屬性中
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 判斷@Aspect注解中标注的是否為singleton類型,預設的切面類都是singleton類型
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 将BeanFactory和目前bean封裝為MetadataAwareAspect-
// InstanceFactory對象,這裡會再次将@Aspect注解中的參數都封裝
// 為一個AspectMetadata,并且儲存在該factory中
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 通過封裝的bean擷取其Advice,如@Before,@After等等,并且将這些
// Advice都解析并且封裝為一個個的Advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 如果切面類是singleton類型,則将解析得到的Advisor進行緩存,
// 否則将目前的factory進行緩存,以便再次擷取時可以通過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.
// 如果@Aspect注解标注的是perthis和pertarget類型,說明目前切面
// 不可能是單例的,因而這裡判斷其如果是單例的則抛出異常
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
// 将目前BeanFactory和切面bean封裝為一個多例類型的Factory
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 對目前bean和factory進行緩存
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 通過所有的aspectNames在緩存中擷取切面對應的Advisor,這裡如果是單例的,則直接從advisorsCache
// 擷取,如果是多例類型的,則通過MetadataAwareAspectInstanceFactory立即生成一個
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
// 如果是單例的Advisor bean,則直接添加到傳回值清單中
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
// 如果是多例的Advisor bean,則通過MetadataAwareAspectInstanceFactory生成
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
}
具體Advisor類的建立,和代理類的建立和上一篇xml定義方式的建立過程是一樣的,這裡就不再介紹了,請直接移步到上一篇文章即可:吃透Spring源碼(十七):AOP建立過程之XML配置方式
三,總結
- 注解方式的Advisor掃描是通過
類來完成的,掃描Advisor的時機與xml方式不同,注解的掃描時機是在建立代理類的時候(在BPP的後置處理器裡面),而XML方式的Advisor掃描是在執行個體化第一個對象之前的AnnotationAwareAspectJAutoProxyCreator
方法中AbstractAutoProxyCreator#applyBeanPostProcessorsBeforeInstantiation()
-
繼承于AnnotationAwareAspectJAutoProxyCreator
在AspectJAwareAdvisorAutoProxyCreator
的基礎上做了注解的擴充。AspectJAwareAdvisorAutoProxyCreator