- (一)AOP获取增强方法
- 1、getAdvisors获取增强方法(核心)
- 2、canApply方法:匹配实际bean业务的增强器
序言
本文主要是对Spring源码分析三:AOP篇做一个补充,因AOP篇幅受限,一些比较具体实现逻辑不能一一罗列,故新增加AOP补充篇一继续分析Spring源码AOP的实现逻辑。 (一)AOP获取增强方法
在Spring源码分析三中已提到AnnotationAwareAspectJAutoProxyCreator->findCandidateAdvisors->buildAspectJAdvisors->getAdvisors,
getAdvisors方法是获取增强方法的具体实现,也是本文的重点。
buildAspectJAdvisors该方法是委托于BeanFactoryAspectJAdvisorsBuilder类去实现,其方法核心点是this.advisorFactory.getAdvisors(factory);getAdvisors方法是委托于ReflectiveAspectJAdvisorFactory去实现,具体代码如下:
getAdvisors核心逻辑:
1)验证切面类是否符合Spring AOP基本要求;
2)解析切面类中的所有方法,并根据PointCut注解定义的方法去匹配其他增强器,从而生成六大增强器,每种增强器处理方式各不相同;
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取被AspectJ标记的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取被AspectJ标记的beanName
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//验证被AspectJ标记的类是否符合Spring AOP的要求
validate(aspectClass);
//懒加载实例化
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//getAdvisorMethods是获取被AspectJ注解类中的方法,但是排除掉PointCut注解外的方法
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
//判断是否有增强方法和是否配置有懒加载机制,如果都满足则在首位增加同步实例器
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
//获取被DeclareParents注解的增强字段,基于该注解的字段生成增强方法
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
validate方法主要是验证被AspectJ标记的类,是否符合AOP的基本验证,包括Aspect注解、SpringAOP不支持的PerClauseKind.PERCFLOW和PerClauseKind.PERCFLOWBELOW等,代码如下:
public void validate(Class<?> aspectClass) throws AopConfigException {
//验证aspectClass的父类是否有Aspect注解和抽象类修饰符
if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
!Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
aspectClass.getSuperclass().getName() + "]");
}
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
//验证是否为Aspect注解
if (!ajType.isAspect()) {
throw new NotAnAtAspectException(aspectClass);
}
//验证aspectClass是否为PerClauseKind.PERCFLOW,不支持的类型
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
"This is not supported in Spring AOP.");
}
//验证aspectClass是否为PerClauseKind.PERCFLOWBELOW,不支持的类型
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
"This is not supported in Spring AOP.");
}
}
利用反射来获取切面类中的方法,但是又排除被PointCut注解的方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
//获取该切面类中的所有方法,除去有Pointcut注解的方法
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
先获取切点方法,然后根据切点信息去生成增强方法
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
//同理上述被验证过validate的一样
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//获取切点方法,该切点就是PointCut中定义的方法与切面中的其他方法匹配如before、after、Around、AfterReturning、AfterThrowing注解等
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//根据切点方法去生成增强方法
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
2、canApply方法:匹配实际bean业务的增强器
封装增强器匹配方法,使用重载方法对不同业务场景调用
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
封装canApply重载方法,用于给外部提供引介增强和普通增强的公用方法
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 {
//没有匹配到业务,直接通过
return true;
}
}
canApply该重载方法主要是对引介增强的方法类型处理,包括强制转化匹配器,匹配切入点等
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//获取ClassFilter即过滤器限制切入点或与给定目标类集的匹配并通过需要代理的类的类名来匹配
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//获取切点的MethodMatcher方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
return true;//代表已经匹配到
}
//如果是引介增强类型的方法匹配器则转化为引介增强的
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//将需要代理的类相关的接口转化为set集合的,跟这个类所有有关的接口都存储在classes中
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//遍历所有的class类的所有的方法,并去匹配对应的方法看是否存在对应的切点方法
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)