文前说明
作为码农中的一员, 需要不断的学习, 我工作之余将一些分析总结和学习笔记写成博客与大家一起交流, 也希望采用这种方式记录自己的学习之旅.
本文仅供学习交流使用, 侵权必删.
1. 概述
Pointcut(切点)解决了 where 问题, 通知 (Advice) 解决了 when 和 how 问题, Aspect(切面)整合了切点和通知两个模块, 从而解决了 何处方法 (where) 在何时 (when 前置, 后置, 环绕等) 执行如何 (how) 的横切逻辑 的问题.(概念可查看 Spring 笔记] AOP 基础相关整理)
织入是在切点的引导下, 将通知逻辑插入到方法调用上, 使得通知逻辑在方法调用时得以执行.
2. 原理
2.1 AbstractAutoProxyCreator
Spring 通过 后置处理器 BeanPostProcessor 接口 实现织入过程.
Spring AOP 抽象代理创建器(
AbstractAutoProxyCreator
)实现了 BeanPostProcessor 接口, 并在 bean 初始化后置处理过程中向 bean 中织入通知.
AbstractAutoProxyCreator 体系
- // AbstractAutoProxyCreator.java
- public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
- implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
- @Override
- // bean 初始化后置处理方法
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean != null) {
- Object cacheKey = getCacheKey(bean.getClass(), beanName);
- if (!this.earlyProxyReferences.contains(cacheKey)) {
- // 如果需要, 为 bean 生成代理对象
- return wrapIfNecessary(bean, beanName, cacheKey);
- }
- }
- return bean;
- }
- 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;
- }
- /*
- * 1. 如果是基础设施类(Pointcut,Advice,Advisor 等接口的实现类), 或是应该跳过的类,
- * 则不应该生成代理, 此时直接返回 bean
- */
- if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
- // 将 <cacheKey, FALSE> 键值对放入缓存中, 供上面的 if 分支使用
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- return bean;
- }
- // 2. 为目标 bean 查找合适的通知器
- Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
- /*
- * 3. 若 specificInterceptors != null, 即 specificInterceptors != DO_NOT_PROXY,
- * 则为 bean 生成代理对象, 否则直接返回 bean
- */
- 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());
- /*
- * 返回代理对象, 此时 IoC 容器输入 bean, 得到 proxy. 此时,
- * beanName 对应的 bean 是代理对象, 而非原始的 bean
- */
- return proxy;
- }
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- // 4. specificInterceptors = null, 直接返回 bean
- return bean;
- }
- }
执行步骤.
步骤 1, 若 bean 是 AOP 基础设施类型, 则直接返回.
步骤 2, 为 bean 查找合适的通知器.
步骤 3, 如果通知器数组不为空, 则为 bean 生成代理对象, 并返回该对象.
步骤 4, 若数组为空, 则返回原始 bean.
2.1.1 getAdvicesAndAdvisorsForBean
在向目标 bean 中织入通知之前, 先要为 bean 筛选出合适的 通知器(通知器持有通知).
筛选的方式很多, 可以通过正则表达式匹配方法名, 更多时候是使用 AspectJ 表达式 进行匹配.
- // AbstractAdvisorAutoProxyCreator.java
- 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();
- }
- protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
- // 2.1 查找所有的通知器
- List<Advisor> candidateAdvisors = findCandidateAdvisors();
- /*
- * 2.2 筛选可应用在 beanClass 上的 Advisor, 通过 ClassFilter 和 MethodMatcher
- * 对目标类和方法进行匹配
- */
- List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
- // 2.3 拓展操作
- extendAdvisors(eligibleAdvisors);
- if (!eligibleAdvisors.isEmpty()) {
- eligibleAdvisors = sortAdvisors(eligibleAdvisors);
- }
- return eligibleAdvisors;
- }
执行步骤.
步骤 2.1, 查询出所有的通知器.
步骤 2.2, 对通知器进行筛选.
步骤 2.3, 拓展操作.
2.1.1.1 findCandidateAdvisors(查询所有的通知器)
Spring 提供了两种配置 AOP 的方式, 一种是通过 xml 配置, 另一种通过 注解配置.
用例 1.
- // TestService.java
- public interface TestService {
- void save(String name);
- void update(String name);
- void delete(String name);
- String findOne(String name);
- List<String> findAll();
- }
- // TestServiceImpl.java
- public class TestServiceImpl implements TestService {
- public void save(String name) {
- }
- public void update(String name) {
- }
- public void delete(String name) {
- System.out.println("TestServiceImpl`s delete");
- }
- public String findOne(String name) {
- System.out.println("TestServiceImpl`s findOne");
- return "";
- }
- public List<String> findAll() {
- System.out.println("TestServiceImpl`s findAll");
- return new ArrayList<String>();
- }
- }
- // AopTest.java
- public class AopTest {
- public void before() {
- System.out.println("AopTest`s before");
- }
- public void after() {
- System.out.println("AopTest`s after");
- }
- }
- // AnnotationAopTest.java
- @Aspect
- public class AnnotationAopTest {
- @Pointcut("execution(* spring.test.aop.*.del*(..))")
- public void pointcut() {
- }
- @Before("pointcut()")
- public void before() {
- System.out.println("AnnotationAopTest`s before");
- }
- @After("execution(* spring.test.aop.*.del*(..))")
- public void after() {
- System.out.println("AnnotationAopTest`s after");
- }
- }
- // Test.java
- public class Test {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
- TestService testService = (TestService) context.getBean("testServiceImpl");
- testService.findAll();
- testService.delete("test");
- }
- }
- AopTest`s before
- TestServiceImpl`s findAll
- AopTest`s after
- AnnotationAopTest`s before
- TestServiceImpl`s delete
- AnnotationAopTest`s after
- */
Spring 配置文件.
- <bean id="testServiceImpl" class="spring.test.aop.TestServiceImpl"/>
- <aop:aspectj-autoproxy/>
- <!-- 普通 bean, 包含 AOP 切面逻辑 -->
- <bean id="aopTest" class="spring.test.aop.AopTest"/>
- <!-- 由 @Aspect 注解修饰的切面类 -->
- <bean id="annotationAopTest" class="spring.test.aop.AnnotationAopTest"/>
- <aop:config>
- <aop:aspect ref="aopTest">
- <!-- pointcut -->
- <aop:pointcut id="testPointcut" expression="execution(* spring.test.aop.*.find*(..))" />
- <!-- advoce -->
- <aop:before method="before" pointcut-ref="testPointcut"/>
- <aop:after method="after" pointcut-ref="testPointcut"/>
- </aop:aspect>
- </aop:config>
配置文件解析如下.
配置文件解析
蓝色部分为 切点 的定义, 类型为
- AspectJExpressionPointcut
- .
黄色部分为 通知器 的定义, 类型为
AspectJPointcutAdvisor
红色部分为普通 bean 的定义.
AopTest 是 普通 bean 包含 AOP 切面逻辑.
AnnotationAopTest 是 由 @Aspect 注解修饰的切面类.
该 bean 会在查找通知器的过程中被解析, 并被构建为一个或多个 Advisor.
AnnotationAwareAspectJAutoProxyCreator
覆写了父类方法
findCandidateAdvisors()
, 增加了解析 @Aspect 注解, 并构建成通知器的操作.
- // AnnotationAwareAspectJAutoProxyCreator.java
- protected List<Advisor> findCandidateAdvisors() {
- // 调用父类方法从容器中查找所有的通知器
- List<Advisor> advisors = super.findCandidateAdvisors();
- // 解析 @Aspect 注解, 并构建通知器
- advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
- return advisors;
- }
- // AbstractAdvisorAutoProxyCreator.java
- protected List<Advisor> findCandidateAdvisors() {
- Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
- return this.advisorRetrievalHelper.findAdvisorBeans();
- }
由
AnnotationAwareAspectJAutoProxyCreator
的
findCandidateAdvisors()
方法调用
AbstractAdvisorAutoProxyCreator
的
findCandidateAdvisors()
方法, 最终调用
BeanFactoryAdvisorRetrievalHelper
的 findAdvisorBeans() 方法.
- // BeanFactoryAdvisorRetrievalHelper.java
- public List<Advisor> findAdvisorBeans() {
- String[] advisorNames = null;
- synchronized (this) {
- // cachedAdvisorBeanNames 是 advisor 名称的缓存
- advisorNames = this.cachedAdvisorBeanNames;
- /*
- * 如果 cachedAdvisorBeanNames 为空, 这里到容器中查找,
- * 并设置缓存, 后续直接使用缓存即可
- */
- if (advisorNames == null) {
- // 2.1.1 从容器中查找 Advisor 类型 bean 的名称
- advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
- this.beanFactory, Advisor.class, true, false);
- // 设置缓存
- this.cachedAdvisorBeanNames = advisorNames;
- }
- }
- if (advisorNames.length == 0) {
- return new LinkedList<Advisor>();
- }
- List<Advisor> advisors = new LinkedList<Advisor>();
- // 2.1.2 遍历 advisorNames
- for (String name : advisorNames) {
- if (isEligibleBean(name)) {
- // 忽略正在创建中的 advisor bean
- if (this.beanFactory.isCurrentlyInCreation(name)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Skipping currently created advisor'" + name + "'");
- }
- }
- else {
- try {
- /*
- * 调用 getBean 方法从容器中获取名称为 name 的 bean,
- * 并将 bean 添加到 advisors 中
- */
- advisors.add(this.beanFactory.getBean(name, Advisor.class));
- }
- catch (BeanCreationException ex) {
- Throwable rootCause = ex.getMostSpecificCause();
- if (rootCause instanceof BeanCurrentlyInCreationException) {
- BeanCreationException bce = (BeanCreationException) rootCause;
- if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
- if (logger.isDebugEnabled()) {
- logger.debug("Skipping advisor'" + name +
- "'with dependency on currently created bean:" + ex.getMessage());
- }
- continue;
- }
- }
- throw ex;
- }
- }
- }
- }
- return advisors;
- }
执行步骤.
步骤 2.1.1, 从容器中查找所有类型为 Advisor 的 bean 对应的名称.
步骤 2.1.2, 遍历 advisorNames, 并从容器中获取对应的 bean.
执行 用例 1, 跟踪 <步骤 2.1.1> 获得 advisorNames 值为.
advisorNames
执行 用例 1, 跟踪 <步骤 2.1.2> 获得 advisors 的值为.
advisors
buildAspectJAdvisors
@Aspect 注解的解析过程.
- // BeanFactoryAspectJAdvisorsBuilder.java
- public List<Advisor> buildAspectJAdvisors() {
- List<String> aspectNames = this.aspectBeanNames;
- if (aspectNames == null) {
- synchronized (this) {
- aspectNames = this.aspectBeanNames;
- if (aspectNames == null) {
- List<Advisor> advisors = new LinkedList<Advisor>();
- aspectNames = new LinkedList<String>();
- // 2.1.3 从容器中获取所有 bean 的名称
- String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
- this.beanFactory, Object.class, true, false);
- // 2.1.4 遍历 beanNames
- for (String beanName : beanNames) {
- if (!isEligibleBean(beanName)) {
- continue;
- }
- // 2.1.4 根据 beanName 获取 bean 的类型
- Class<?> beanType = this.beanFactory.getType(beanName);
- if (beanType == null) {
- continue;
- }
- // 2.1.5 检测 beanType 是否包含 Aspect 注解
- 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);
- // 2.1.6 获取通知器
- 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 {
- 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;
- }
执行步骤.
步骤 2.1.3, 获取容器中所有 bean 的名称(beanName).
步骤 2.1.4, 遍历上一步获取到的 bean 名称数组, 并获取当前 beanName 对应的 bean 类型(beanType).
步骤 2.1.5, 根据 beanType 判断当前 bean 是否是一个的 Aspect 注解类, 若不是则不做任何处理.
步骤 2.1.6, 调用
advisorFactory.getAdvisors()
获取通知器.
执行 用例 1, 跟踪 <步骤 2.1.5> 获取到符合条件的 bean 为 AnnotationAopTest.
- getAdvisors(注解方式获取通知器过程)
- // ReflectiveAspectJAdvisorFactory.java
- public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
- // 获取 aspectClass 和 aspectName
- Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
- String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
- validate(aspectClass);
- MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
- new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
- List<Advisor> advisors = new LinkedList<Advisor>();
- // getAdvisorMethods 用于返回不包含 @Pointcut 注解的方法
- for (Method method : getAdvisorMethods(aspectClass)) {
- // 为每个方法分别调用 getAdvisor 方法
- 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;
- }
- 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;
- }
- // 创建 Advisor 实现类
- return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
- this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
- }
执行步骤.
步骤 2.1.7, 获取 AspectJ 表达式切点.
步骤 2.1.8, 创建 Advisor 实现类.
- getPointcut
- // ReflectiveAspectJAdvisorFactory.java
- private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
- // 获取方法上的 AspectJ 相关注解, 包括 @Before,@After 等
- AspectJAnnotation<?> aspectJAnnotation =
- AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
- if (aspectJAnnotation == null) {
- return null;
- }
- // 创建一个 AspectJExpressionPointcut 对象
- AspectJExpressionPointcut ajexp =
- new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
- // 设置切点表达式
- ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
- ajexp.setBeanFactory(this.beanFactory);
- return ajexp;
- }
- 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;
- }
注意, 如 用例 1 中 AnnotationAopTest 类中 before() 方法.
- // AnnotationAopTest.java
- @Aspect
- public class AnnotationAopTest {
- @Pointcut("execution(* spring.test.aop.*.del*(..))")
- public void pointcut() {
- }
- @Before("pointcut()")
- public void before() {
- System.out.println("AnnotationAopTest`s before");
- }
- @After("execution(* spring.test.aop.*.del*(..))")
- public void after() {
- System.out.println("AnnotationAopTest`s after");
- }
- }
@Before 注解中的表达式是 pointcut(), 只是一个中间值, 而不是最终值
execution(* spring.test.aop.*.del*(..))
, 所以后续还会将表达式进行转换.
InstantiationModelAwarePointcutAdvisorImpl
Advisor 实现类的创建过程.
- // InstantiationModelAwarePointcutAdvisorImpl.java
- public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
- Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
- MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
- this.declaredPointcut = declaredPointcut;
- this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
- this.methodName = aspectJAdviceMethod.getName();
- this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
- this.aspectJAdviceMethod = aspectJAdviceMethod;
- this.aspectJAdvisorFactory = aspectJAdvisorFactory;
- this.aspectInstanceFactory = aspectInstanceFactory;
- this.declarationOrder = declarationOrder;
- this.aspectName = aspectName;
- if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
- Pointcut preInstantiationPointcut = Pointcuts.union(
- aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
- this.pointcut = new PerTargetInstantiationModelPointcut(
- this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
- this.lazy = true;
- }
- else {
- this.pointcut = this.declaredPointcut;
- this.lazy = false;
- // 按照注解解析 Advice
- this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
- }
- }
- instantiateAdvice
通知器 Advisor 是通知 Advice 的持有者, 所以在 Advisor 实现类的构造方法中创建通知也是合适的.
- // InstantiationModelAwarePointcutAdvisorImpl.java
- private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
- return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
- this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
- }
- public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
- MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
- Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
- validate(candidateAspectClass);
- // 获取 Advice 注解
- AspectJAnnotation<?> aspectJAnnotation =
- AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
- if (aspectJAnnotation == null) {
- return null;
- }
- 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;
- // 按照注解类型生成相应的 Advice 实现类
- switch (aspectJAnnotation.getAnnotationType()) {
- case AtBefore: // @Before -> AspectJMethodBeforeAdvice
- springAdvice = new AspectJMethodBeforeAdvice(
- candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
- break;
- case AtAfter: // @After -> AspectJAfterAdvice
- springAdvice = new AspectJAfterAdvice(
- candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
- break;
- case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
- springAdvice = new AspectJAfterReturningAdvice(
- candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
- AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
- if (StringUtils.hasText(afterReturningAnnotation.returning())) {
- springAdvice.setReturningName(afterReturningAnnotation.returning());
- }
- break;
- case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
- springAdvice = new AspectJAfterThrowingAdvice(
- candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
- AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
- if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
- springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
- }
- break;
- case AtAround: // @Around -> AspectJAroundAdvice
- springAdvice = new AspectJAroundAdvice(
- candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
- break;
- /*
- * 直接返回 null.
- */
- case AtPointcut:
- if (logger.isDebugEnabled()) {
- logger.debug("Processing pointcut'" + candidateAdviceMethod.getName() + "'");
- }
- return null;
- default:
- throw new UnsupportedOperationException(
- "Unsupported advice type on method:" + candidateAdviceMethod);
- }
- springAdvice.setAspectName(aspectName);
- springAdvice.setDeclarationOrder(declarationOrder);
- /*
- * 获取方法的参数列表名称, 比如方法 int sum(int numX, int numY),
- * getParameterNames(sum) 得到 argNames = [numX, numY]
- */
- String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
- if (argNames != null) {
- // 设置参数名
- springAdvice.setArgumentNamesFromStringArray(argNames);
- }
- springAdvice.calculateArgumentBindings();
- return springAdvice;
- }
主要的逻辑就是根据注解类型生成与之对应的通知对象.
总结 <步骤 2.1.6> 注解获取通知器的过程, 执行步骤如下.
步骤 1, 从目标 bean 中获取不包含 Pointcut 注解的方法列表.
步骤 2, 遍历上一步获取的方法列表, 并调用 getAdvisor() 获取当前方法对应的 Advisor.
步骤 3, 创建
AspectJExpressionPointcut
对象, 并从方法的注解中获取表达式, 最后设置到切点对象中.
步骤 4, 创建 Advisor 实现类对象
- InstantiationModelAwarePointcutAdvisorImpl
- .
步骤 5, 调用 instantiateAdvice() 方法构建通知.
步骤 6, 调用 getAdvice() 方法, 并根据注解类型创建相应的通知.
不同的注解类型会创建不同的通知, 以
AspectJMethodBeforeAdvice
为例, 其他注解类似.
- AspectJMethodBeforeAdvice
- // AspectJMethodBeforeAdvice.java
- public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
- public AspectJMethodBeforeAdvice(
- Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
- super(aspectJBeforeAdviceMethod, pointcut, aif);
- }
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- // 调用通知方法
- invokeAdviceMethod(getJoinPointMatch(), null, null);
- }
- @Override
- public boolean isBeforeAdvice() {
- return true;
- }
- @Override
- public boolean isAfterAdvice() {
- return false;
- }
- }
- protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
- // 调用通知方法, 并向其传递参数
- return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
- }
- protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
- Object[] actualArgs = args;
- if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
- actualArgs = null;
- }
- try {
- ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
- // 通过反射调用通知方法
- return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
- }
- catch (IllegalArgumentException ex) {
- throw new AopInvocationException("Mismatch on arguments to advice method [" +
- this.aspectJAdviceMethod + "]; pointcut expression [" +
- this.pointcut.getPointcutExpression() + "]", ex);
- }
- catch (InvocationTargetException ex) {
- throw ex.getTargetException();
- }
- }
- 2.1.1.2 findAdvisorsThatCanApply(对通知器进行筛选)
- // AbstractAdvisorAutoProxyCreator.java
- protected List<Advisor> findAdvisorsThatCanApply(
- List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
- ProxyCreationContext.setCurrentProxiedBeanName(beanName);
- try {
- // 调用重载方法
- return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
- }
- finally {
- ProxyCreationContext.setCurrentProxiedBeanName(null);
- }
- }
- // AopUtils.java
- 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) {
- // 筛选 IntroductionAdvisor 类型的通知器
- if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
- eligibleAdvisors.add(candidate);
- }
- }
- boolean hasIntroductions = !eligibleAdvisors.isEmpty();
- for (Advisor candidate : candidateAdvisors) {
- if (candidate instanceof IntroductionAdvisor) {
- continue;
- }
- // 筛选普通类型的通知器
- if (canApply(candidate, clazz, hasIntroductions)) {
- eligibleAdvisors.add(candidate);
- }
- }
- return eligibleAdvisors;
- }
- // AopUtils.java
- public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
- if (advisor instanceof IntroductionAdvisor) {
- /*
- * 从通知器中获取类型过滤器 ClassFilter, 并调用 matchers 方法进行匹配.
- * ClassFilter 接口的实现类 AspectJExpressionPointcut 为例, 该类的
- * 匹配工作由 AspectJ 表达式解析器负责.
- */
- return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
- }
- else if (advisor instanceof PointcutAdvisor) {
- PointcutAdvisor pca = (PointcutAdvisor) advisor;
- // 对于普通类型的通知器, 这里继续调用重载方法进行筛选
- return canApply(pca.getPointcut(), targetClass, hasIntroductions);
- }
- else {
- return true;
- }
- }
- // AopUtils.java
- public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
- Assert.notNull(pc, "Pointcut must not be null");
- // 使用 ClassFilter 匹配 class
- if (!pc.getClassFilter().matches(targetClass)) {
- return false;
- }
- MethodMatcher methodMatcher = pc.getMethodMatcher();
- if (methodMatcher == MethodMatcher.TRUE) {
- return true;
- }
- IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
- if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
- introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
- }
- /*
- * 查找当前类及其父类 (以及父类的父类等等) 所实现的接口, 由于接口中的方法是 public,
- * 所以当前类可以继承其父类, 和父类的父类中所有的接口方法
- */
- Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
- classes.add(targetClass);
- for (Class<?> clazz : classes) {
- // 获取当前类的方法列表, 包括从父类中继承的方法
- Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
- for (Method method : methods) {
- // 使用 methodMatcher 匹配方法, 匹配成功即可立即返回
- if ((introductionAwareMethodMatcher != null &&
- introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
- methodMatcher.matches(method, targetClass)) {
- return true;
- }
- }
- }
- return false;
- }
筛选的工作主要由 ClassFilter 和 MethodMatcher 完成.(可以查看 [Spring 笔记] AOP 基础相关整理 了解)
- 2.1.1.3 extendAdvisors(拓展操作)
- // AbstractAdvisorAutoProxyCreator.java
- protected void extendAdvisors(List<Advisor> candidateAdvisors) {
- AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
- }
- // AspectJAwareAdvisorAutoProxyCreator.java
- public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
- // 如果通知器列表是一个空列表, 则什么都不做
- if (!advisors.isEmpty()) {
- boolean foundAspectJAdvice = false;
- /*
- * 下面的 for 循环用于检测 advisors 列表中是否存在
- * AspectJ 类型的 Advisor 或 Advice
- */
- for (Advisor advisor : advisors) {
- if (isAspectJAdvice(advisor)) {
- foundAspectJAdvice = true;
- }
- }
- /*
- * 向 advisors 列表的首部添加 DefaultPointcutAdvisor
- */
- if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
- // 向通知器列表中添加 ExposeInvocationInterceptor.ADVISOR
- advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
- return true;
- }
- }
- return false;
- }
- // AspectJProxyUtils.java
- private static boolean isAspectJAdvice(Advisor advisor) {
- return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
- advisor.getAdvice() instanceof AbstractAspectJAdvice ||
- (advisor instanceof PointcutAdvisor &&
- ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
- }
上述操作主要的目的是向通知器列表首部添加
DefaultPointcutAdvisor
类型的通知器, 也就是
- ExposeInvocationInterceptor.ADVISOR
- .
- ExposeInvocationInterceptor
拦截器相关可以查看 [Spring 笔记] AOP 拦截器链相关整理 了解.
- // ExposeInvocationInterceptor.java
- public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
- public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
- // 创建 DefaultPointcutAdvisor 匿名对象
- public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
- @Override
- public String toString() {
- return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
- }
- };
- private static final ThreadLocal<MethodInvocation> invocation =
- new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");
- public static MethodInvocation currentInvocation() throws IllegalStateException {
- MethodInvocation mi = invocation.get();
- if (mi == null)
- throw new IllegalStateException(
- "No MethodInvocation found: Check that an AOP invocation is in progress, and that the" +
- "ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that" +
- "advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
- return mi;
- }
- // 私有构造方法
- private ExposeInvocationInterceptor() {
- }
- @Override
- public Object invoke(MethodInvocation mi) throws Throwable {
- MethodInvocation oldInvocation = invocation.get();
- // 将 mi 设置到 ThreadLocal 中
- invocation.set(mi);
- try {
- // 调用下一个拦截器
- return mi.proceed();
- }
- finally {
- invocation.set(oldInvocation);
- }
- }
- //...
- }
- ExposeInvocationInterceptor.ADVISOR
经过
registry.getInterceptors()
方法处理后, 即可得到
- ExposeInvocationInterceptor
- .
- ExposeInvocationInterceptor
的作用是用于暴露 MethodInvocation 对象到 ThreadLocal 中.
如果其他地方需要当前的 MethodInvocation 对象, 直接通过调用 currentInvocation 方法取出.
Spring 为目标 bean 筛选到合适的通知器, 再通过 创建代理对象 的方式将 Advisor(通知器)所持有的 Advice(通知)织入到 bean 的某些方法前后.
来源: http://www.jianshu.com/p/21daa4f9c853