目录
本系列主要分析基于注解形式的SpringAOP实现流程,大致可以分为以下几个核心步骤:
- 解析配置aspectj-autoproxy
- 加载Aspect切面和Advisor增强器
- 创建代理
- 调用代理对象中的方法
对于注解形式的SpringAOP实现流程,首先需要获取到针对于目标Bean的Advisor增强器。
在解析xml配置时,我们配置了<aop:aspectj-autoproxy/>,将会注册一个postProcessor。
在Bean的初始化之后,进行两个操作:
1.通过遍历全部注册的带@Aspect注解的Bean,解析相关信息,创建Advisor;
2.找到用于当前Bean的Advisor:根据ClassFilter和MethodMatcher过滤
第一步:解析配置aspectj-autoproxy
在使用基于注解形式的AOP时,我们需要在xml文件中增加一项配置:
<aop:aspectj-autoproxy/>
代表了框架将会自动识别并处理@Aspect等注解。
此标签使用AspectJAutoProxyBeanDefinitionParser来解析,有两个步骤:
- 注册 AnnotationAwareAspectJAutoProxyCreator,这个类负责了切面类的解析、代理对象的创建,是AOP的核心类。
- 解析<aop:aspectj-autoproxy /> 的两个属性:
- expose-proxy是否暴露当前代理对象为ThreadLocal模式
Spring文档中指明:对于方法的拦截只限于public,而不会拦截protected和private方法(如果有需求,可以使用AspectJ框架);另外对于public方法内部调用的其他方法也不会进行拦截,如果有这个需求,则可以配置expose-proxy参数来实现。 - proxy-target-class
该属性默认为false,当我们配置为true时,代表指定使用CGLib动态代理方式实现增强。
- expose-proxy是否暴露当前代理对象为ThreadLocal模式
第二步:加载Aspect切面和Advisor
postProcessBeforeInstantiation
AnnotationAwareAspectJAutoProxyCreator虽然是以Creater结尾的,但它其实实现了PostProcessor的接口。
BeanPostProcessor
|
├── InstantiationAwareBeanPostProcessor
| |
| ├── SmartInstantiationAwareBeanPostProcessor
| | |
| | ├── AbstractAutoProxyCreator
| | | |
| | | ├── BeanNameAutoProxyCreator
| | | ├── AbstractAdvisorAutoProxyCreator
| | | | |
| | | | ├── DefaultAdvisorAutoProxyCreator
| | | | ├── InfrastructureAdvisorAutoProxyCreator
| | | | ├── AspectJAwareAdvisorAutoProxyCreator
| | | | | |
| | | | | ├── AnnotationAwareAspectJAutoProxyCreator
在Ioc分析的过程中,我们知道PostProcessor会在Bean的实例化之前,调用postProcessBeforeInstantiation方法,作用是当有AOP的需要时提前短路返回一个代理对象,替代原本的正常实例化流程。
(Spring IOC(三)createBean方法源码分析
中第2-3步:applyBeanPostProcessorsBeforeInstantiation)
那么就从postProcessBeforeInstantiation的实现看起,AnnotationAwareAspectJAutoProxyCreator中此接口是在其父类AbstractAutoProxyCreator中被实现:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (beanName == null || !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;
}
}
// 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.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
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;
}
在这个方法中会进行一个getCustomTargetSource的判断,即自定义的TargetSource,如果存在,则在此处创建代理而代替正常的实例化流程,TargetSource将以自定义方式处理目标实例。有关TargetSource见附1.
postProcessAfterInitialization
上述postProcessBeforeInstantiation方法会返回null,即进行正常的实例化流程。
在Ioc分析的过程中,我们知道PostProcessor会在Bean的初始化之后,调用postProcessAfterInitialization方法
(Spring IOC(四)doCreateBean方法源码分析
中第5-4步:applyBeanPostProcessorsAfterInitialization)
那么就从postProcessAfterInitialization的实现看起:
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
进入到wrapIfNecessary方法:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && 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.
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;
}
在这个方法中可见关键步骤有两个:
- getAdvicesAndAdvisorsForBean,也就是本节重点:加载Aspect切面Advice通知。
- createProxy创建代理
本节重点分析getAdvicesAndAdvisorsForBean方法:
关键方法:getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
在这个方法中关键步骤有:
- findCandidateAdvisors:获取所有Advisors
- findAdvisorsThatCanApply:找可以应用到当前BeanName的Advisors
- sortAdvisors:给Advisors排序
1.findCandidateAdvisors获取所有Advisors
这个方法在AnnotationAwareAspectJAutoProxyCreator类中有实现
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
- 调用父类方法super.findCandidateAdvisors(),意义为 加载xml配置文件 中的Advisor
- aspectJAdvisorsBuilder.buildAspectJAdvisors(),才是获取 注解形式 的Advisor
xml形式的获取步骤可以概括为:
- 从容器中查找 Advisor类型的BeanName
- 通过getBean()获取对应的Bean,并添加到Advisors中
我们主要来看注解形式Advisor的获取:
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this
// case they would be cached by the Spring container but would not
// have been weaved
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(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.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
方法核心步骤:
- 获取在工厂中注册的所有BeanName
- 遍历找到带有@Aspect的Bean
- 通过有@Aspect的Bean获取Advisors
1.1.获取在工厂中注册的所有BeanName
1.2.遍历找到带有@Aspect的Bean
1.3.在Aspect注解的Bean中获取Advisors
即上段中的:
List classAdvisors = this.advisorFactory.getAdvisors(factory);
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
其中 getAdvisorMethods(aspectClass)方法:
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new LinkedList<Method>();
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}
});
Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}
可知在这里做了处理:声明为pointcuts的方法不做处理。
获取到此aspectClass的其他所有方法后,再提取Advisor:
getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName)
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
有两个步骤:
- getPointcut:获取切点注解信息
- 根据切点注解信息生成Advisor
1.3.1. getPointcut获取切点Pointcut中的注解信息
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
return ajexp;
}
其中findAspectJAnnotationOnMethod:
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
表示获取标记为Before、Around、After、 AfterReturning、AfterThrowing、Pointcut的注解信息aspectJAnnotation;
然后看这一步:
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
意义为在得到的aspectJAnnotation中,解析PointCut标记的注解表达式。
举个例子,Spring AOP(一)Spring AOP实现原理简介中Demo的切面类AopAspect,getPointcutExpression这里得到的就是@Pointcut(“execution(* example.aop..(…))”)中的:execution(* example.aop..(…));
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
最后将传来参数candidateAspectClass:Aspect切面中除PointCut之外的注解,与此PointcutExpression进行一个包装。
举个栗子就是上述Demo中 @Before(“aopPointcut()”)被解析为 @Before("*example.aop…(…))")的信息。
1.3.2.根据切点注解信息生成Advisor
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
此方法的前半部分是单纯的赋值,重点在于instantiateAdvice(this.declaredPointcut)这一行:
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
getAdvice的实现:
@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
因为获取到的注解信息有Before、After等不同的增强方式,所以也需要不同的Advisor来完成不同的逻辑,这个方法正是实现了这个功能。方法逻辑很清晰,分为了5种Advisor的创建:
- AspectJMethodBeforeAdvice
- AspectJAfterAdvice
- AspectJAfterReturningAdvice
- AspectJAfterThrowingAdvice
- AspectJAroundAdvice
//常用的Advisor内部实现后续再详细分析
2.findAdvisorsThatCanApply找匹配当前Bean的Advisors
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
方法中的入参candidateAdvisors即为上一步获取的全部Advisor,beanClass为当前Bean类型,然后对Advisors进行选择。
AopUtils.findAdvisorsThatCanApply:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
如Spring AOP(二)AOPAlliance与SpringAOP核心接口介绍中的(5. Spring新增接口:Advisor 通知器)中所描述,Spring AOP新增了一个接口Advisor,用来包装 Advice通知 和 Pointcut切点 两个对象。而Advisor的实现分为了两种:PointcutAdvisor和IntroductionAdvisor。
在这个方法中,对于Advisor分为了两种:
- IntroductionAdvisor
是类级别增强,因此只需要直接持有ClassFilter即可.见附2. - PointcutAdvisor,方法级别增强
是方法级别增强,因此需要同时使用ClassFilter和MethodMatcher(方法匹配器)。PointcutAdvisor内部持有一个Pointcut ,而Pointcut就是由ClassFilter和MethodMatcher组成的。
最终,我们在工厂所有的Advisors中,获取到可应用于当前Bean的一组Advisors。
下面是两种Advisor对于当前Bean是否匹配的代码,逻辑清晰不做叙述。
2.1. Introduction类型的Advisor的选择
- 获取Advisor中的ClassFilter,匹配当前targetClass
canApply(candidate, clazz)
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
2.2. Pointcut类型的Advisor的选择
- 获取advisor中持有的Pointcut
- 获取Pointcut中的ClassFilter,匹配当前targetClass
- 获取Pointcut中的MethodMatcher,遍历匹配当前targetClass中所有的method
canApply(candidate, clazz, hasIntroductions)
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
*流程图总结
附1.TargetSource
其实,SpringAOP代理的不是Target,而是TargetSource。
TargetSource接口:
public interface TargetSource extends TargetClassAware {
@Override
Class<?> getTargetClass();
boolean isStatic();
Object getTarget() throws Exception;
void releaseTarget(Object target) throws Exception;
}
通常情况下,一个Proxy只能代理一个Target,但如果让Proxy通过TargetSource来获取目标Bean,可以通过TargetSource的内部逻辑来实现每次获取的Target都不同。
- 如果是static的TargetSource,则每次都返回相同的Target;
- 如果是dynamic的TargetSource,则可以支持pooling(目标对象池), hot swapping(运行时目标对象热替换)等功能。
我们不必在编码中直接去实现TargetSource接口,Spring AOP框架为我们提供了一个默认的实现类:SingletonTargetSource ,这个目标源取得的目标对象是单例的。
附2.PointcutAdvisor与IntroductionAdvisor
两者都是对Spring中Advisor接口的继承:
Advisor
|
├── PointcutAdvisor
├── IntroductionAdvisor
- PointcutAdvisor
和切点有关的Advisor,主要为了拦截方法,这种增强属于方法级别的增强。 - IntroductionAdvisor
和切点无关,IntroductionAdvisor主要为了给targetClass 追加接口 (或者说追加更多的方法),这种增强属于类级别的增强。
IntroductionAdvisor类型是什么时候获取的?
上文(1.3.在Aspect注解的Bean中获取Advisors)中,可以看到有段代码:
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
在这个部分,将IntroductionAdvisor与PointcutAdvisor一起加入到了候选Advisors中。
IntroductionAdvisor的使用并不多见,使用 IntroductionAdvisor的Demo:
<context:component-scan base-package="example.aop"/>
<aop:aspectj-autoproxy/>
被代理类
public interface TestAop {
void process();
}
@Component
public class TestAopImpl implements TestAop {
@Override
public void process() {
System.out.println("testAop.process()");
}
}
引介代理类:
public interface Introduction {
void introductionMethod();
}
@Component
public class IntroductionImpl implements Introduction {
@Override
public void introductionMethod() {
System.out.println("引入方法");
}
}
切面类:
@Component
@Aspect
public class AopAspect {
@DeclareParents(value = "example.aop.TestAop+",
defaultImpl = IntroductionImpl.class)
private Introduction introduction;
}
测试类:
public static void main(final String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
TestAop testAop = ac.getBean(TestAop.class);
testAop.process();
Introduction introduction = (Introduction) testAop;
introduction.introductionMethod();
}
输出结果:
testAop.process()
引入方法