注释:
在上一篇,咱们对 IOC 外围局部流程曾经剖析结束,置信小伙伴们有所播种,从这一篇开始,咱们将会踏上新的旅程,即 Spring 的另一外围:AOP!
首先,为了让大家能更无效的了解 AOP,先带大家过一下 AOP 中的术语:
- 切面(Aspect):指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级 Java 利用中无关横切关注点的例子。在 Spring AOP 中,切面能够应用在一般类中以@Aspect 注解来实现。
- 连接点(Join point):在 Spring AOP 中,一个连接点总是代表一个办法的执行,其实就代表加强的办法。
- 告诉(Advice):在切面的某个特定的连接点上执行的动作。告诉有多种类型,包含
around
,before
和after
等等。许多 AOP 框架,包含 Spring 在内,都是以拦截器做告诉模型的,并保护着一个以连接点为核心的拦截器链。 - 指标对象(Target):指标对象指将要被加强的对象。即蕴含主业务逻辑的类的对象。
- 切点(Pointcut):匹配连接点的断言。告诉和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的办法时)。切点表达式如何和连接点匹配是 AOP 的外围:Spring 默认应用 AspectJ 切点语义。
- 参谋(Advisor):参谋是 Advice 的一种包装体现,Advisor 是 Pointcut 以及 Advice 的一个联合,用来治理 Advice 和 Pointcut。
- 织入(Weaving):将告诉切入连接点的过程叫织入
- 引入(Introductions):能够将其余接口和实现动静引入到 targetClass 中
一个栗子
术语看完了,咱们先上个 Demo 回顾一下吧~
-
首先,应用
EnableAspectJAutoProxy
注解开启咱们的 AOP@ComponentScan(basePackages = {"com.my.spring.test.aop"}) @Configuration @EnableAspectJAutoProxy public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class); IService service = context.getBean("service", IService.class); service.doService();} }
-
写一个接口
public interface IService {void doService(); }
-
写一个实现类
@Service("service") public class ServiceImpl implements IService{ @Override public void doService() {System.out.println("do service ..."); } }
-
写一个切面
@Aspect @Component public class ServiceAspect {@Pointcut(value = "execution(* com.my.spring.test.aop.*.*(..))") public void pointCut() {} @Before(value = "pointCut()") public void methodBefore(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法【" + methodName + "】的【前置告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @After(value = "pointCut()") public void methodAfter(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法【" + methodName + "】的【后置告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(value = "pointCut()") public void methodReturn(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法【" + methodName + "】的【返回告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } @AfterThrowing(value = "pointCut()") public void methodThrow(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName(); System.out.println("执行指标办法【" + methodName + "】的【异样告诉】,入参:" + Arrays.toString(joinPoint.getArgs())); } }
-
测试运行
执行指标办法【doService】的【前置告诉】,入参:[] do service ... 执行指标办法【doService】的【返回告诉】,入参:[] 执行指标办法【doService】的【后置告诉】,入参:[]
以上
Demo 看完了,运行成果也进去了,AOP 已失效,但如何失效的呢?相比于咱们一般应用 Bean 的 Demo,在这里,咱们只不过加上了一个 @EnableAspectJAutoProxy
注解以及一个标识了 @Aspectj
的类,那么咱们先看看 @EnableAspectJAutoProxy
这个注解做了什么吧~
开启 AOP
以下是笔者所画的大抵流程图
其中 AspectJAutoProxyRegistrar
实现了 ImportBeanDefinitionRegistrar
,所以在解决BeanFactoryPostProcessor
逻辑时将会调用 registerBeanDefinitions
办法,此时就会把 AnnotationAwareAspectJAutoProxyCreator
注册到容器中,其中 BeanFactoryPostProcessor
的逻辑就不再说了,往期文章有过详细分析。而 AnnotationAwareAspectJAutoProxyCreator
的类图如下:
咱们发现 AnnotationAwareAspectJAutoProxyCreator
是实现了 BeanPostProcessor
接口的类,所以它其实是一个后置处理器,那么,还记得在创立 Bean 过程中的 BeanPostProcessor
九次调用机会吗?不记得也没关系,AnnotationAwareAspectJAutoProxyCreator
起作用的中央是在 bean 的实例化前以及初始化后,别离对应着解析切面和创立动静代理的过程,当初,就让咱们先来看看解析切面的过程吧~
解析切面
解析切面的流程如下图所示:
咱们曾经理解到切面解析的过程是由 AnnotationAwareAspectJAutoProxyCreator
实现的,而 AnnotationAwareAspectJAutoProxyCreator
又继承了AbstractAutoProxyCreator
,所以首先,咱们先会来到AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {// class 类型是否为(Advice, Pointcut, Advisor, AopInfrastructureBean)
// shouldSkip 中将会解析切面
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
调用到子类的AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 寻找 advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}
}
return super.shouldSkip(beanClass, beanName);
}
findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
// 寻找实现了 Advisor 接口的类, 因为咱们个别不会以接口的形式实现切面,这里返回 null
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
// 这里将解析出所有的切面
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
// aspectBeanNames 有值则阐明切面已解析结束
List<String> aspectNames = this.aspectBeanNames;
// Double Check
if (aspectNames == null) {synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 取出是 Object 子类的 bean,其实就是所有的 bean
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 取得该 bean 的 class
Class<?> beanType = this.beanFactory.getType(beanName);
// 判断是否有标识 @AspectJ 注解
if (this.advisorFactory.isAspect(beanType)) {
// 将 beanName 放入汇合中
aspectNames.add(beanName);
// 将 beanType 和 beanName 封装到 AspectMetadata 中
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// Kind 默认为 SINGLETON
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 这里会通过 @Before @After 等标识的办法获取到所有的 advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 将获取到的所有 advisor 放入缓存
this.advisorsCache.put(beanName, classAdvisors);
}
advisors.addAll(classAdvisors);
}
}
}
// 将所有解析过的 beanName 赋值
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// aspectNames 不为空,象征有 advisor,取出之前解析好的所有 advisor
List<Advisor> advisors = new ArrayList<>();
// 获取到所有解析好的 advisor
for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
}
return advisors;
}
advisorFactory.getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取到标识了 @AspectJ 的 class,其实就是刚刚封装的 class
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取 className
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
List<Advisor> advisors = new ArrayList<>();
// 拿出该类除了标识 @PointCut 的所有办法进行遍历 getAdvisorMethods 时会对 method 进行一次排序
// 排序程序 Around, Before, After, AfterReturning, AfterThrowing
for (Method method : getAdvisorMethods(aspectClass)) {
// 获取到 advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
// 退出到汇合中
advisors.add(advisor);
}
}
}
咱们先看下 getAdvisorMethods
办法
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) {
// 以 Around, Before, After, AfterReturning, AfterThrowing 的程序自定义排序
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
不晓得小伙伴们对 ReflectionUtils.doWithMethods 这个工具类熟不相熟呢,这个工具类在之前剖析 Bean 创立过程时可是呈现了好屡次呢,并且咱们也是能够应用的
当初,曾经获取到切面中的所有办法了,那么接下来就该对这些办法解析并进行封装成 advisor 了~
getAdvisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 获取办法上的切点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 封装成对象返回,创建对象时将会解析办法创立 advice
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
获取切点表达式的过程其实非常简单,即是解析办法上的注解,取出注解上的 value 即可
getPointcut
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 查找办法上和 AspectJ 相干注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 设置切点表达式
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// PointcutExpression 为注解上 value 属性的值
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
new InstantiationModelAwarePointcutAdvisorImpl,在这里,才会真正创立出 advice
public InstantiationModelAwarePointcutAdvisorImpl(){
//... 省略赋值过程...
// 实例化出 advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
// 获取 advice,aspectJAdviceMethod 为办法,aspectName 为切面类
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
public Advice getAdvice(){
// 依据办法获取到注解信息
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
AbstractAspectJAdvice springAdvice;
// 依据注解类型返回对象,创建对象的过程都是一样的,都是调用父类的构造方法
// candidateAdviceMethod 为切面的办法,expressionPointcut 是切点
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
//... 省略其余的 advice
default:
throw new UnsupportedOperationException("Unsupported advice type on method:" + candidateAdviceMethod);
}
return springAdvice;
}
springAdvice 已创立结束,意味着切面中的某个办法曾经解析结束了,其余的办法解析过程大抵也是类似的
小结
其实解析切面自身并不简单,只是 Spring 中将切面类封装来封装去容易使人凌乱,如 buildAspectJAdvisors
办法中,封装了一个 AspectMetadata amd = new AspectMetadata(beanType, beanName);
,又立刻发动断定amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON
,其实这里齐全能够变为AjTypeSystem.getAjType(currClass).getPerClause().getKind() == PerClauseKind.SINGLETON
,AjTypeSystem.getAjType(currClass)
为new AspectMetadata
的一部分逻辑,笔者这里给大家总结一下吧。
首先,循环所有的 beanName,找到带有 @Aspectj 注解的 class, 获取到 class 中的所有办法进行遍历解析,取出办法注解上的值(切点:pointcut),而后把办法,切点表达式,封装了 BeanFactory,BeanName 的 factory 封装成相应的 SpringAdvice, 由 SpringAdvice 和 pointcut 组合成一个 advisor。
创立代理对象
切面曾经解析结束,接下来,咱们就来看看如何把解析出的切面织入到指标办法中吧
但,在这之前,还有必要给小伙伴们补充一点前置常识。
咱们晓得,一个 bean 是否可能被 aop 代理,取决于它是否满足代理条件,即为是否可能被切点表达式所命中,而在 Spring AOP 中,bean 与切点表达式进行匹配的是 AspectJ 实现的,并非 Spring 所实现的,所以咱们先来看看 AspectJ 如何匹配出适合的 bean 的吧
栗子
首先须要引入 org.aspectj:aspectjweaver
依赖
一个 Service,包名为com.my.spring.test.aop
package com.my.spring.test.aop;
/**
* 切点表达式能够匹配的类
*
*/
public class ServiceImpl{
/**
* 切点表达式能够匹配的办法
*/
public void doService() {System.out.println("do service ...");
}
public void matchMethod() {System.out.println("ServiceImpl.notMatchMethod");
}
}
而后,咱们本人封装一个用于匹配的工具类,具体性能大家看正文哈哈
package com.my.spring.test.aspectj;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;
import java.lang.reflect.Method;
/**
* aop 工具
*/
public class AOPUtils {
// AspectJ 的固定写法,获取一个切点解析器
static PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(PointcutParser.getAllSupportedPointcutPrimitives(), ClassLoader.getSystemClassLoader());
// 切点表达式
private static PointcutExpression pointcutExpression;
/**
* 初始化工具类,咱们须要先获取一个切点表达式
*
* @param expression 表达式
*/
public static void init(String expression){
// 解析出一个切点表达式
pointcutExpression = parser.parsePointcutExpression(expression);
}
/**
* 第一次筛选,依据类筛选,也叫做粗筛
*
* @param targetClass 指标类
* @return 是否匹配
*/
public static boolean firstMatch(Class<?> targetClass){
// 依据类筛选
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
/**
* 第二次筛选,依据办法筛选,也叫做精筛,精筛通过则阐明齐全匹配
* ps: 也能够应用该办法进行精筛,粗筛的目标是进步性能,第一次间接过滤掉不适合的类再缓缓精筛
*
* @param method 办法
* @return 是否匹配
*/
public static boolean lastMatch(Method method){
// 依据办法筛选
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
return shadowMatch.alwaysMatches();}
}
测试
public class AOPUtilsTest {public static void main(String[] args) throws NoSuchMethodException {
// 定义表达式
String expression = "execution(* com.my.spring.test.aop.*.*(..))";
// 初始化工具类
AOPUtils.init(expression);
// 粗筛
boolean firstMatch = AOPUtils.firstMatch(ServiceImpl.class);
if(firstMatch){System.out.println("第一次筛选通过");
// 失常状况应该是获取所有办法进行遍历,我这里偷懒了~
Method doService = ServiceImpl.class.getDeclaredMethod("doService");
// 精筛
boolean lastMatch = AOPUtils.lastMatch(doService);
if(lastMatch){System.out.println("第二次筛选通过");
}
else{System.out.println("第二次筛选未通过");
}
}
else {System.out.println("第一次筛选未通过");
}
}
}
后果(就不截图了,狐疑的小伙伴能够本人试试~)
第一次筛选通过
第二次筛选通过
当咱们新建一个类Test
, 把切点表达式换成
execution(* com.my.spring.test.aop.Test.*(..))
测试后果为
第一次筛选未通过
再把切点表达式换成指定的办法
execution(* com.my.spring.test.aop.*.matchMethod(..))
后果
第一次筛选通过
第二次筛选未通过
到这里,小伙伴们应该明确了 AspectJ 的应用办法吧
代理对象创立过程
接下来,咱们就来看看 Spring 是如何应用 AspectJ 匹配出相应的 advisor 并创立代理对象的吧,以下为创立代理对象的大抵途程图
创立代理对象是在 bean 初始化后实现的,所以对应的 beanPostProcessor
调用机会为postProcessAfterInitialization
AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {
// 获取缓存 key 值,其实就是 beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 判断缓存中是否有该对象,有则阐明该对象已被动静代理,跳过
if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 依据 bean 获取到匹配的 advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 创立代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
return bean;
}
getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取适合的 advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
return advisors.toArray();}
findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 先获取到所有的 advisor, 这里和解析过程雷同,因为曾经解析好,所以会间接从缓存中取出
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选出匹配的 advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 减少一个默认的 advisor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 查找匹配的 advisor
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz){List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// 判断是否匹配
if (canApply(candidate, clazz, hasIntroductions)) {
// 退出到适合的 advisors 汇合中
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
canApply
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {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;
}
}
canApply
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// 第一次筛选,对 class 筛选判断是否满足匹配条件
// 这里将会初始化切点表达式
if (!pc.getClassFilter().matches(targetClass)) {return false;}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
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;
}
pc.getClassFilter()
public ClassFilter getClassFilter() {obtainPointcutExpression();
return this;
}
obtainPointcutExpression
private PointcutExpression obtainPointcutExpression() {if (this.pointcutExpression == null) {
// 确认类加载器
this.pointcutClassLoader = determinePointcutClassLoader();
// 创立切点表达式
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
buildPointcutExpression
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
// 初始化切点解析器
PointcutParser parser = initializePointcutParser(classLoader);
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
// 应用切点解析器进行解析表达式获取切点表达式
return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
initializePointcutParser
private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
// 取得切点解析器
PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler());
return parser;
}
pc.getClassFilter 便是实现了以上事件,此时再进行调用 matchs 办法
public boolean matches(Class<?> targetClass) {PointcutExpression pointcutExpression = obtainPointcutExpression();
// 应用切点表达式进行粗筛
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
introductionAwareMethodMatcher.matches 同样如此
以上便是寻找适合的 advisor 的过程,上面,就是通过这些 advisor 进行创立动静代理了
createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 将 specificInterceptors(当初是 Object)转化为 Advisor 返回
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 赋值到 proxyFactory 的 advisors 属性中
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 创立动静代理
return proxyFactory.getProxy(getProxyClassLoader());
}
proxyFactory.getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
// 创立代理对象
return createAopProxy().getProxy(classLoader);
}
createAopProxy
protected final synchronized AopProxy createAopProxy() {
// 创立 AOP 代理对象
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// @EnableAspectJAutoProxy 的 proxyTargetClass 是否配置为 true
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.");
}
// 如何是接口则创立 jdk 动静代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);
}
// cglib 动静代理
return new ObjenesisCglibAopProxy(config);
}
// 默认是 jdk 动静代理
else {return new JdkDynamicAopProxy(config);
}
}
public Object getProxy(@Nullable ClassLoader classLoader) {
// 获取到代理的接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 创立 jdk 代理,传入的为 JdkDynamicAopProxy 对象,外面蕴含了被代理的 bean 以及匹配的 advisor
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
动静代理创立实现~
代理对象调用过程
对象都给你创立好了,接下当然是开.. 发动调用咯
以下是调用的大抵流程图
代理对象被调用的是 invoke 办法,咱们所创立的代理对象为JdkDynamicAopProxy
,所以
JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 取出包装了被代理 bean 的对象 -> 创立代理对象时的 SingletonTargetSource, advised 为 ProxyFactory
TargetSource targetSource = this.advised.targetSource;
Object target = null;
// 拿到 bean
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 将所有 advisor 中的 advice 取出,并转化为对应的 interceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 创立一个最外层的 MethodInvocation 用于发动调用
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 发动链式调用
Object retVal = invocation.proceed();
return retVal;
}
咱们先看获取 interceptor 的过程
getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
// 将所有 advisor 中的 advice 取出并封装成 intercept
return this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
// 创立一个 advisor 适配器的注册器用于转化 advice,创立时将默认注册三个适配器
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
// 循环遍历所有 advisor
for (Advisor advisor : advisors) {
// 将 advisor 中的 advice 转化为 interceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
return interceptorList;
}
}
GlobalAdvisorAdapterRegistry.getInstance() 类初始化时调用静态方法
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry()
public static AdvisorAdapterRegistry getInstance() {return instance;}
public DefaultAdvisorAdapterRegistry() {
// 注册三个适配器
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
// 将适配器退出汇合
this.adapters.add(adapter);
}
registry.getInterceptors 这外面蕴含了 advice 转化成 interceptor 的过程
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// advice 自身是否就是 MethodInterceptor
if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {// 判断 advice 是哪个 advice 如:(advice instanceof MethodBeforeAdvice)
if (adapter.supportsAdvice(advice)) {
// 将 advice 封装到对应的 interceptor
interceptors.add(adapter.getInterceptor(advisor));
}
}
return interceptors.toArray(new MethodInterceptor[0]);
}
若 adapter 为MethodBeforeAdviceAdapter
,则
public MethodInterceptor getInterceptor(Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
其余 advice 转化过程雷同
以上,便将所有的 advice 转化成了 interceptor,接下来,则是经典的链式递归调用过程
以下过程小伙伴们能够对照流程图浏览,毕竟递归还是有些简单,须要肯定的功底
ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
// currentInterceptorIndex 初始值为 -1
// 当 currentInterceptorIndex 等于 advice 的数量减一时,则调用指标办法
// 因为 advice 已排好序,所以调用程序为 before, after, afterReturn, afterThrowing
// 留神,并非调用到相应的 advice 就会执行 advice 办法,这里是相似递归调用的形式,会存在一个归过程
// 有些是递的时候发动调用,如 beforeAdvice, 但有些则是归的时候发动调用,如 afterAdvice
// 递归的终止条件则是这上面这个 return invokeJoinpoint();
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();
}
// currentInterceptorIndex 自增并获取到 interceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 将 interceptro 强转为 MethodInterceptor 发动调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
此时 currentInterceptorIndex 值为 0,而咱们的 advice 为 4 个(去除了默认的),所以当 currentInterceptorIndex 为 3 时便会调用咱们的理论办法
首先调用的是 MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
// 调用前置告诉
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();}
mi 为传入的 this,所有 mi.proceed()将会回到最开始的办法
再次循环,此时 currentInterceptorIndex 值为 1
调用的是 AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {return mi.proceed();
}
finally {
// finally 意味着不管怎样都会被调用
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
持续,此时 currentInterceptorIndex 值为 2
调用的是 AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
持续,此时 currentInterceptorIndex 值为 3
调用的是 AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {return mi.proceed();
}
catch (Throwable ex) {if (shouldInvokeOnThrowing(ex)) {
// 调用异样告诉
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
// 往外抛出异样
throw ex;
}
}
所以如果咱们的业务办法产生了异样,会调用到异样告诉,而这里又把异样往外抛,所以 afterReturn 就会被跳过间接到 after 的 finally 办法
当初 currentInterceptorIndex 值为 3 了,再回调最后的办法中时,就会调用到咱们的业务办法了。调用结束则进行归的过程,调用过程便完结了。
以上,便是整个 AOP 的过程了
本篇文章中波及到图片的矢量图地址为:https://www.processon.com/vie…,有须要的小伙伴可自取
下文预报:Spring 源码剖析之事务管理(上)
Spring 源码系列
- Spring 源码剖析之 IOC 容器预启动流程(已完结)
- Spring 源码剖析之 BeanFactory 体系结构(已完结)
- Spring 源码剖析之 BeanFactoryPostProcessor 调用过程(已完结)
- Spring 源码剖析之 Bean 的创立过程(已完结)
- Spring 源码剖析之什么是循环依赖及解决方案(已完结)
- Spring 源码剖析之 AOP 从解析到调用(已完结)
- Spring 源码剖析之事务管理(上),事物治理是 spring 作为容器的一个特点,总结一下他的根本实现与原理吧
- Spring 源码剖析之事务管理(下),对于他的底层事物隔离与事物流传原理,重点剖析一下
Spring Mvc 源码系列
- SpringMvc 体系结构
- SpringMvc 源码剖析之 Handler 解析过程
- SpringMvc 源码剖析之申请链过程
另外笔者公众号:奇客工夫,有更多精彩的文章,有趣味的同学,能够关注