一, 概述
Spring 的两大特性: IOC 和 AOP.
AOP 是面向切面编程, Spring 内置了自己实现的基于动态代理技术的 AOP, 同时还支持成熟的 AspectJ 框架, 我们这里主要讲述的还是内置的基于动态代理的 AOP 实现. 因为面对一些普通的需求, Spring 内置的 AOP 已经绰绰有余.
AOP 一般用于增强原来的代码的功能, 这种增强体现在辅助方面, 比如安全, 日志, 事务等.
二, 术语
1, 连接点(JoinPoint)
连接点就是具体的代码中的切入点, 指的是具体的一处代码位置.
2, 切点(PointCut)
切点是对一系列代表同种功能 (目的) 的切入点 (连接点) 的统称, 切点不是一个点, 而是代表某一功能的一系列连接点的集合.
3, 通知(Advice)
通知就是我们要在切点执行的操作, 就是我们要实现的目的, 是要实现的功能的代码实现. 一般通知又称为增强, 所谓增强就是对原来功能的基础上添加新功能, 进行功能增强.
4, 切面(Aspect)
切面是通知和切点的综合体, 定义好了一个切面, 那么我们就知道, 这个 AOP 要实现的功能是什么, 需要切入到程序中的那些地方. 抽象层次中, 切面是代码功能的横切面, 这个横切面的位置就是切点, 这个切面的功能就是通知.
5, 织入(Weaving)
织入就是切面作用到目标代码中的方式, Spring 内置的 AOP 采用的是动态代理的方式来织入, 还可以采用编译器织入和加载期织入, 后两者分别需要特定的编译器和类加载器来完成, 后两种方式是 AspectJ 所支持的织入方式.
6, 引介(Introduction)
引介是另一种类型的增强, 它可以为类添加一些属性和方法. 它和通知是并列的两种不同的增强.
7, 目标对象(Target)
目标对象就是我们想要织入的对象, 一般不会是一个, 通常是一批符合条件的对象.
8, 代理(Proxy)
代理就好理解了, Spring 内置的 AOP 就是通过动态代理的方式实现织入的, 创建目标对象的代理类, 在代理类中执行通知的内容, 然后在合适的位置调用目标对象的方法, 来达到织入的目的.
三, Spring AOP 概述
Spring AOP 是基于动态代理技术实现的切面编程, 代理技术包括 JDK 动态代理和 CGLIB 动态代理, 前者基于接口实现, 后者基于类实现.
1,Spring 中使用 AOP 技术的方式:
1)定义切面类, 使用 @Aspect 注解
2)在切面类中定义切点方法, 使用 @PointCut 注解
3)在切面类中定义通知方法, 使用 @Before,@After,@Around 等注解
4)在通知方法的注解中使用切点方法
5)在切面类上加设注解 @Component
6)启动 AOP 功能, 两种方式: 原始的 XML 配置方式和注解方式
XMl 方式:<aop:aspectj-autoproxy/>
注解方式:@EnableAspectJAutoProxy
配置方式: spring.auto.proxy=true
2,Spring AOP 支持的增强类型
通知增强: Advice
前置通知: MethodBeforeAdvice - 在连接点之前执行
后置通知: AfterReturningAdvice - 在连接点正常执行完后执行, 如果还未到连接点就异常, 不会执行
环绕通知: AroundAdvice - 在连接点前后执行
异常通知: AfterThrowingAdvice - 在连接点抛出异常后执行
finally 通知: AfterAdvice - 最终执行, 无论是否异常, 方法执行结束都会执行
引介增强: IntroductionInterceptor->DelegatingIntroductionInterceptor
前五种很好理解, 重点是最后一种引介增强, 这种增强并不是针对方法的增强, 而是针对类的增强, 它会为目标添加属性和方法, 比如它可以为目标类添加一个接口的实现. 目标类原本没有实现某个接口, 但是我们可以使用引介增强的方式为目标类创建一个实现该接口的代理, 在这个代理中可以使用接口的功能来作用于目标对象.
3, 原理图:(右键打开看大图)
四, 源码分析
1, 入口
1.1 入口一:<aop:aspectj-autoproxy/>
源码 1 - 来自: AopNamespaceHandler
- @Override
- public void init() {
- // In 2.0 XSD as well as in 2.1 XSD.
- registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
- registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
- registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
- // Only in 2.0 XSD: moved to context namespace as of 2.1
- registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
- }
上面源码就是针对 XML 配置中 < aop:XXX/>配置的解析, 红色部分正是针对 < aop:aspectj-autoproxy/>的解析, 如果配置了 aspectj-autoproxy, 则注册 Bean 定义解析器: AspectJAutoProxyBeanDefinitionParser.
AspectJAutoProxyBeanDefinitionParser 是一个实现了 BeanDefinitionParser 接口的类, 专门用于解析切面自动代理的 Bean 定义的解析工作, 重点在其 parse 方法.
源码 2 - 来自: AspectJAutoProxyBeanDefinitionParser
- class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
- @Override
- @Nullable
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- // 1 - 注册 AnnotationAwareAspectJAutoProxyCreator
- AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
- // 2 - 扩展 BeanDefinition
- extendBeanDefinition(element, parserContext);
- return null;
- }
- private void extendBeanDefinition(Element element, ParserContext parserContext) {
- // 获取 BeanName 为 internalAutoProxyCreator 的 BeanDefinition, 其实就是之前注册的自动代理构建器
- BeanDefinition beanDef =
- parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
- if (element.hasChildNodes()) {
- // 如果当前元素有子节点, 则给上面获取的 Bean 定义添加子节点中明确定义的类型值(填充 BeanDefinition)
- addIncludePatterns(element, parserContext, beanDef);
- }
- }
- private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
- ManagedList<TypedStringValue> includePatterns = new ManagedList<>();
- NodeList childNodes = element.getChildNodes();// 获取子节点
- for (int i = 0; i <childNodes.getLength(); i++) {
- // 遍历子节点, 获取子节点中 name 属性值, 封装到 TypeStringValue 中
- // 在上下文中提取子节点 includeElement 的元数据保存到 TypedStringValue 的 source 属性中
- // 最后封装好的 TypeStringValue 保存到 includePatterns 列表中
- Node node = childNodes.item(i);
- if (node instanceof Element) {
- Element includeElement = (Element) node;
- TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
- valueHolder.setSource(parserContext.extractSource(includeElement));
- includePatterns.add(valueHolder);
- }
- }
- if (!includePatterns.isEmpty()) {
- // 从解析上下文 parserContext 中提取指定节点 element 的元数据保存到 includePatterns 的 source 属性中,
- // 然后将 includePatterns 保存到 BeanDefinition 的 propertyValues 属性中
- includePatterns.setSource(parserContext.extractSource(element));
- beanDef.getPropertyValues().add("includePatterns", includePatterns);
- }
- }
- }
上面代码中有两个重点, 首先就是 registerAspectJAnnotationAutoProxyCreatorIfNecessary 方法调用, 用于注册 AnnotationAwareAspectJAutoProxyCreator 构建器; 另一点就是在构建器注册完成后, 为其填充一些必要内容, 这些内容为 XML 配置中子节点的配置内容, 具体内容参照源码, 这里重点看看第一步, 注册构建器的源码:
源码 3 - 来自: AopNamespaceUtils
- public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
- ParserContext parserContext, Element sourceElement) {
- // 1 - 注册或升级 AnnotationAwareAspectJAutoProxyCreator
- // parserContext.getRegistry()获取到的是 BeanDefinitionRegistry 注册器, 第二个参数是提取的指定元素的元数据
- BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
- parserContext.getRegistry(), parserContext.extractSource(sourceElement));
- // 2 - 校验并设置是否适用基于 CGLIB 的动态代理实现 AOP, 和是否要暴露代理类
- useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
- // 3 - 注册成组件
- registerComponentIfNecessary(beanDefinition, parserContext);
- }
- private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
- if (sourceElement != null) {
- boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));// 获取 XML 中设置的 proxy-target-class 属性的值, 解析为 Boolean 值
- if (proxyTargetClass) {
- // 如果为 true, 则强制自动代理构建器使用基于类的动态代理 CGLIB, 需要将属性设置到自动代理构建器的 BeanDefinition 中
- AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
- }
- boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));// 获取 XML 中配置的 expose-proxy 属性的值, 同样解析为 Boolean 值
- if (exposeProxy) {
- // 如果为 true, 强制自动代理构建器暴露代理类, 需要将属性设置到自动代理构建器的 BeanDefinition 中
- AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
- }
- }
- }
- private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
- if (beanDefinition != null) {
- // 将自动代理构建器包装成为一个 Bean 组件定义.
- // Bean 组件定义是将一个 BeanDefinition 中包含的所有的属性的值 (可能为一个 BeanDefinition 或者 BeanReference) 全部封装起来成为一个组件包, 然后将其注册到解析上下文中
- BeanComponentDefinition componentDefinition =
- new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
- parserContext.registerComponent(componentDefinition);
- }
- }
registerAspectJAnnotationAutoProxyCreatorIfNecessary 方法中主要做了三件事情:
1 - 注册构建器
2 - 配置属性
3 - 组件注册
针对第 2 和第 3, 在源码注释中解释的很清楚啦, 主要看看第一步, 继续进行构建器的注册:
源码 4 - 来自: AopConfigUtils
- public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
- if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
- // 如果构建器已经加载, 获取其 BeanDefinition, 添加属性 proxyTargetClass, 值为 true
- BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
- definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
- }
- }
- public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
- if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
- // 如果构建器已经加载, 获取其 BeanDefinition, 添加属性 exposeProxy, 值为 true
- BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
- definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
- }
- }
- @Nullable
- private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
- @Nullable Object source) {
- Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
- if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
- // 1 - 如果 internalAutoProxyCreator 已经被注册那么比较新旧自动代理构建器类在列表中的优先级, 如果已注册的构建器优先级低, 则替换为给定的新构建器
- BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
- if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
- int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
- int requiredPriority = findPriorityForClass(cls);
- if (currentPriority <requiredPriority) {
- apcDefinition.setBeanClassName(cls.getName());
- }
- }
- return null;
- }
- // 尚未注册 internalAutoProxyCreator 的情况下, 将给定的构建器包装成 RootBeanDefinition, 然后注册这个 BeanDefinition
- RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
- // 把元数据保存到 BeanDefinition 中
- beanDefinition.setSource(source);
- // 设置为最高优先值
- beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
- // 设置为基础角色
- beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- // 2 - 以 internalAutoProxyCreator 为 beanName 注册当前 BeanDefinition(AnnotationAwareAspectJAutoProxyCreator 类)
- registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
- return beanDefinition;
- }
源码 4 中前两个方法时源码 3 中第二步里面配置属性时调用的方法, 在此给出.
源码 4 的 1 - 中是在已存在一个自动代理构建器的情况下, 将其与新的给定的 AnnotationAwareAspectJAutoProxyCreator 构建器的优先级进行比对, 取优先极高的.
最后的 registerBeanDefinition 方法用于注册 BeanDefinition. 至此, 自动代理构建器加载完毕.
1.2 入口二:@EnableAspectJAutoProxy
源码 5 - 来自: EnableAspectJAutoProxy
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Import(AspectJAutoProxyRegistrar.class)
- public @interface EnableAspectJAutoProxy {
- /**
- * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
- * to standard Java interface-based proxies. The default is {@code false}.
- */
- boolean proxyTargetClass() default false;
- /**
- * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
- * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
- * Off by default, i.e. no guarantees that {@code AopContext} access will work.
- * @since 4.3.1
- */
- boolean exposeProxy() default false;
- }
源码中重点关注 @Import(AspectJAutoProxyRegistrar.class), 很明显这个注解导入了一个新类: AspectJAutoProxyRegistrar.
使用 @Import 注解导入的方式可以将一个类注册到 BeanFactory 中.
源码 6 - 来自 AspectJAutoProxyRegistrar
- class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
- @Override
- public void registerBeanDefinitions(
- AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- // 1 - 注册或升级自动代理构建器
- AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
- // 2 - 封装注解属性, 并根据属性进行配置
- AnnotationAttributes enableAspectJAutoProxy =
- AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
- if (enableAspectJAutoProxy != null) {
- if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
- AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
- }
- if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
- AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
- }
- }
- }
- }
我们可以从源码 5 中看到注解 @EnableAspectJAutoProxy 内部有两个属性设置 proxyTargetClass 和 exposeProxy, 这个之前的入口一中源码 3 里面的 2 - 中的设置是一样的, 即我们在 XML 启动 AOP 的时候也可以设置这两个值.
proxyTargetClass 属性表示是否适用基于类的的动态代理 CGLIB 来创建代理类. true 表示使用, false 表示不使用, 默认是 false.
exposeProxy 属性表示是否暴露生成的代理类, 暴露就是可手动调用, 最常见的情况如, 在一个类中使用 this 调用带有 @Transactional 注解的方法, 你会发现事务是不生效的, 这时候我们就可以将生成的代理暴露出来手动调用代理类来保证事务生效:
如下例子中:
- public interface TestService {
- void testMethod1();
- void testMethod2();
- }
- public class TestServiceImpl {
- @Transactional
- public void testMethod1(){
- //some transaction operate
- }
- public void testMethod2(){
- this.testMethod1();
- }
- }
在 testMethod2 中以 this.testMethod1()方式调用带事务注解的 testMethod1 方法时, 其事务是不生效的. 修改方式就是将 exposeProxy 设置为 true, 然后修改调用方式为:
1 ((TestService)AopContext.currnetProxy()).testMethod1();
源码 6 中 1 - 调用的是 AopConfigUtils 中的方法:
源码 7 - 来自: AopConfigUtils
- @Nullable
- public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
- return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
- }
然后它再调用的就是源码 4 中的源码了, 到这里调用的就是公共部分啦. 那么这一部分也就到此为止了, 其余见源码 4 之后的部分.
到此两个主要的入口都分析完毕, 入口的主要作用就是注册或者升级自动代理构建器, 因为之后 AOP 的操作基本都要依靠这个构建器来完成.
2, 创建 AOP 代理
我们的重点就是构建器 AnnotationAwareAspectJAutoProxyCreator, 分析下其继承结构, 你会发现它实现了 BeanPostProcessor 接口.
BeanPostProcessor 接口有两个方法:
postProcessBeforeInitialization:Bean 实例初始化前调用
postProcessAfterInitialization:Bean 实例初始化之后调用
然后我们在其继承体系中寻找实现这两个方法的类, 一番寻找后发现: AbstractAutoProxyCreator
源码 8 - 来自: AbstractAutoProxyCreator
- @Override
- public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
- if (bean != null) {
- // 1 - 生成缓存 key
- Object cacheKey = getCacheKey(bean.getClass(), beanName);
- // 校验该 key 是否已存在于 earlyProxyReferences 缓存
- if (!this.earlyProxyReferences.contains(cacheKey)) {
- // 2 - 执行创建代理对象
- return wrapIfNecessary(bean, beanName, cacheKey);
- }
- }
- return bean;
- }
我们发现了这个方法的实现, 这个方法会在构建器 Bean 初始化之后被调用. 我们看看它做了啥?
重点就是 wrapIfNecessary 方法, 这个方法用于代理对象的生成.
源码 9 - 来自: AbstractAutoProxyCreator
- protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
- if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
- // 已经处理过, 直接返回
- return bean;
- }
- if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
- // 如果不需要增强, 直接返回
- return bean;
- }
- if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
- // 检测目标类是否是 AOP 的基础设施类, 基础设施类包括 Advice,Pointcut,Advisor,AopInfrastructureBean, 或者是否需要跳过代理, 如果是则将其设置为无需增强
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- return bean;
- }
- // Create proxy if we have advice.
- // 1 - 获取针对当前 Bean 的增强
- Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
- if (specificInterceptors != DO_NOT_PROXY) {
- // 如果获取到增强则执行下面的创建代理
- this.advisedBeans.put(cacheKey, Boolean.TRUE);
- // 2 - 创建代理
- 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;
- }
上面的源码中除了进行一些必要的校验之外, 主要的逻辑是获取针对当前 Bean 的增强和创建代理这两步.
首先来看下如何获取增强
源码 10 - 来自: AbstractAdvisorAutoProxyCreator
- // 获取通知(增强)
- @Override
- @Nullable
- protected Object[] getAdvicesAndAdvisorsForBean(
- Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
- List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
- if (advisors.isEmpty()) {
- return DO_NOT_PROXY;
- }
- return advisors.toArray();
- }
源码 11 - 来自: AbstractAdvisorAutoProxyCreator
- protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
- // 1 - 先获取所有的增强器列表
- List<Advisor> candidateAdvisors = findCandidateAdvisors();
- // 2 - 获取应用到当前目标类的增强器列表
- List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
- // 这个方法是一个钩子方法, 用于子类重写扩展
- extendAdvisors(eligibleAdvisors);
- if (!eligibleAdvisors.isEmpty()) {
- eligibleAdvisors = sortAdvisors(eligibleAdvisors);// 排序
- }
- return eligibleAdvisors;
- }
上面的源码我们重点关注 findCandidateAdvisors 方法和 findAdvisorsThatCanApply 方法, 分别用于找出 BeanFactory 中所有的可用的增强器, 和从可用增强器中找出作用于目标类的增强器.
源码 12 - 来自: AbstractAdvisorAutoProxyCreator
- protected List<Advisor> findCandidateAdvisors() {
- Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
- return this.advisorRetrievalHelper.findAdvisorBeans();
- }
源码 13 - 来自: BeanFactoryAdvisorRetrievalHelper
- public List<Advisor> findAdvisorBeans() {
- // Determine list of advisor bean names, if not cached already.
- String[] advisorNames = null;
- synchronized (this) {
- advisorNames = this.cachedAdvisorBeanNames;
- if (advisorNames == null) {
- // Do not initialize FactoryBeans here: We need to leave all regular beans
- // uninitialized to let the auto-proxy creator apply to them!
- // 1 - 获取当前 BeanFactory 及其继承体系中的容器中所有的 Advisor 类型的 Bean 的 BeanName 数组, 排除掉 FactoryBeans
- advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
- this.beanFactory, Advisor.class, true, false);
- this.cachedAdvisorBeanNames = advisorNames;
- }
- }
- if (advisorNames.length == 0) {
- return new LinkedList<>();
- }
- List<Advisor> advisors = new LinkedList<>();
- for (String name : advisorNames) {
- if (isEligibleBean(name)) {
- // 2 - 再排除创建中的 Bean
- if (this.beanFactory.isCurrentlyInCreation(name)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Skipping currently created advisor'" + name + "'");
- }
- }
- else {
- try {
- // 3 - 把剩下的 Bean 添加到通知 (增强器) 列表中
- advisors.add(this.beanFactory.getBean(name, Advisor.class));
- }
- catch (BeanCreationException ex) {
- Throwable rootCause = ex.getMostSpecificCause();
- if (rootCause instanceof BeanCurrentlyInCreationException) {
- BeanCreationException bce = (BeanCreationException) rootCause;
- String bceBeanName = bce.getBeanName();
- if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Skipping advisor'" + name +
- "'with dependency on currently created bean:" + ex.getMessage());
- }
- // Ignore: indicates a reference back to the bean we're trying to advise.
- // We want to find advisors other than the currently created bean itself.
- continue;
- }
- }
- throw ex;
- }
- }
- }
- }
- return advisors;
- }
这段源码看起来挺复杂, 我们去掉一些不必要的内容, 总结起来, 总共三件事:
1 - 获取容器中所有的 Advisor, 排除 FactoryBeans
2 - 再排除创建中的 Bean
3 - 将剩余的 Advisor 通过 getBean 创建 Bean 实例并添加到列表中返回
至于再下一步的逻辑就不再探寻啦.
然后是源码 11 中的 2-findAdvisorsThatCanApply 方法
源码 14 - 来自: AbstractAdvisorAutoProxyCreator
- protected List<Advisor> findAdvisorsThatCanApply(
- List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
- // 将代理的目标 Bean 的 beanName 设置到 ThreadLocal 中
- ProxyCreationContext.setCurrentProxiedBeanName(beanName);
- try {
- // 1 - 在候选增强器中找出可作用于目标 Bean 的增强器
- return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
- }
- finally {
- ProxyCreationContext.setCurrentProxiedBeanName(null);
- }
- }
重点操作就是 AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 用于找出能作用于目标 Bean 的增强器列表
源码 15 - 来自: AopUtils
- public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
- if (candidateAdvisors.isEmpty()) {
- return candidateAdvisors;
- }
- List<Advisor> eligibleAdvisors = new LinkedList<>();
- for (Advisor candidate : candidateAdvisors) {
- if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
- // 1 - 首先添加引介增强
- eligibleAdvisors.add(candidate);
- }
- }
- boolean hasIntroductions = !eligibleAdvisors.isEmpty();
- for (Advisor candidate : candidateAdvisors) {
- if (candidate instanceof IntroductionAdvisor) {
- // already processed
- // 跳过引介增强
- continue;
- }
- // 校验其余增强器是否能应用到目标 Bean
- if (canApply(candidate, clazz, hasIntroductions)) {
- // 2 - 添加通知增强
- eligibleAdvisors.add(candidate);
- }
- }
- return eligibleAdvisors;
- }
源码中可以看出来, 这里针对了两种类型的增强器 (引介增强和通知增强) 分别进行了处理, 首先处理了引介增强, 然后是通知增强.
这里有两个 canApply 方法, 第一个用于判断引介增强是否能作用到目标类, 第二个用于判断通知增强是否能作用到目标类.
其实第一个是通过调用第二个实现的.
我觉得我们可以简单看看其实现逻辑:
- // 用于校验引介增强
- 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;
- }
- }
- // 针对通知增强的匹配校验
- 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();// 获取方法匹配器
- if (methodMatcher == MethodMatcher.TRUE) {// 获取方法匹配器匹配的是所有方法, 这里直接返回 true, 不必要做校验
- // No need to iterate the methods if we're matching any method anyway...
- return true;
- }
- IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
- if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
- introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
- }
- Set<Class<?>> classes = new LinkedHashSet<>();
- if (!Proxy.isProxyClass(targetClass)) {
- classes.add(ClassUtils.getUserClass(targetClass));
- }
- classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
- 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;
- }
- protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
- @Nullable Object[] specificInterceptors, TargetSource targetSource) {
- if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
- // 暴露目标类, 将其保存到 BeanDefinition 中
- AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
- }
- // 创建一个新的代理工厂, 并为其拷贝当前类中的相关配置属性
- ProxyFactory proxyFactory = new ProxyFactory();
- proxyFactory.copyFrom(this);
- if (!proxyFactory.isProxyTargetClass()) {
- // 校验 proxyTargetClass 设置, 如果设置不是直接代理目标类, 则采用默认的 JDK 动态代理指定接口
- if (shouldProxyTargetClass(beanClass, beanName)) {
- // 校验该 Bean 的 BeanDefinition 中的 preserveTargetClass 属性, 是否被代理工厂设置为 true, 如果设置为 true, 则表示代理工厂希望代理类可以强转为目标类
- proxyFactory.setProxyTargetClass(true);
- }
- else {
- // 否则表示基于接口创建代理
- evaluateProxyInterfaces(beanClass, proxyFactory);
- }
- }
- // 将拦截器封装成通知
- Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
- proxyFactory.addAdvisors(advisors);// 加入增强器
- proxyFactory.setTargetSource(targetSource);// 设置要代理的类
- customizeProxyFactory(proxyFactory);// 子类定制代理
- // 用于控制代理工厂被配置之后, 是否还允许修改通知, 默认为 false(表示不允许修改)
- proxyFactory.setFrozen(this.freezeProxy);
- if (advisorsPreFiltered()) {
- proxyFactory.setPreFiltered(true);
- }
- // 创建代理
- return proxyFactory.getProxy(getProxyClassLoader());
- }
- public Object getProxy(@Nullable ClassLoader classLoader) {
- // 创建 AOP 代理, 并获取代理对象
- return createAopProxy().getProxy(classLoader);
- }
- protected final synchronized AopProxy createAopProxy() {
- if (!this.active) {
- activate();// 激活开关
- }
- // 获取 AOP 代理工厂, 使用 AOP 代理工厂创建 AOP 代理
- return getAopProxyFactory().createAopProxy(this);
- }
- private void activate() {
- this.active = true;
- // 回调监听器的 activated 方法
- for (AdvisedSupportListener listener : this.listeners) {
- listener.activated(this);
- }
- }
- public AopProxyFactory getAopProxyFactory() {
- return this.aopProxyFactory;
- }
- @Override
- public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
- if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
- // 如果代理需要执行优化或者 proxyTargetClass=true 或者不存在代理接口
- 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.");
- }
- if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
- // 如果目标类是接口或者是动态生成的代理类, 则使用 JDK 动态代理
- return new JdkDynamicAopProxy(config);
- }
- // 创建 CGLIB 动态 AOP 代理对象
- return new ObjenesisCglibAopProxy(config);
- }
- else {
- // 创建 JDK 动态 AOP 代理对象
- return new JdkDynamicAopProxy(config);
- }
- }
- @Override
- public Object getProxy(@Nullable ClassLoader classLoader) {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating JDK dynamic proxy: target source is" + this.advised.getTargetSource());
- }
- // 1 - 获取用于代理的全部接口的集合(数组)
- Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
- // 2 - 查找接口集合中可能定义的 equals 方法获取 hashCode 方法
- findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
- // 3 - 创建指定接口的代理实例
- return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
- }
- // 获取用于代理的接口的集合
- static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
- // 获取配置中所有的接口
- Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
- if (specifiedInterfaces.length == 0) {
- // No user-specified interfaces: check whether target class is an interface.
- Class<?> targetClass = advised.getTargetClass();
- if (targetClass != null) {
- if (targetClass.isInterface()) {
- advised.setInterfaces(targetClass);
- }
- else if (Proxy.isProxyClass(targetClass)) {
- advised.setInterfaces(targetClass.getInterfaces());
- }
- specifiedInterfaces = advised.getProxiedInterfaces();
- }
- }
- // 将 SpringProxy,Advised,DecoratingProxy 三个接口添加到接口集中
- boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
- boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
- boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
- int nonUserIfcCount = 0;
- if (addSpringProxy) {
- nonUserIfcCount++;
- }
- if (addAdvised) {
- nonUserIfcCount++;
- }
- if (addDecoratingProxy) {
- nonUserIfcCount++;
- }
- Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
- System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
- int index = specifiedInterfaces.length;
- if (addSpringProxy) {
- proxiedInterfaces[index] = SpringProxy.class;
- index++;
- }
- if (addAdvised) {
- proxiedInterfaces[index] = Advised.class;
- index++;
- }
- if (addDecoratingProxy) {
- proxiedInterfaces[index] = DecoratingProxy.class;
- }
- return proxiedInterfaces;
- }
- private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
- for (Class<?> proxiedInterface : proxiedInterfaces) {
- Method[] methods = proxiedInterface.getDeclaredMethods();
- for (Method method : methods) {
- // 遍历每一个接口, 再获取其中的方法进行遍历, 逐个校验其是否是 equals 方法, 或者 hashCode 方法, 只有当二者都被定义之后校验才会结束, 否则一直进行下去
- if (AopUtils.isEqualsMethod(method)) {
- this.equalsDefined = true;
- }
- if (AopUtils.isHashCodeMethod(method)) {
- this.hashCodeDefined = true;
- }
- if (this.equalsDefined && this.hashCodeDefined) {
- return;
- }
- }
- }
- }
- final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
- ...
- }
- @Override
- @Nullable
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- MethodInvocation invocation;
- Object oldProxy = null;
- boolean setProxyContext = false;
- TargetSource targetSource = this.advised.targetSource;
- Object target = null;
- try {
- if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
- // The target does not implement the equals(Object) method itself.
- // 目标类体系中未实现 equals 方法, 但是代理的目标方法却是 equals 方法
- return equals(args[0]);
- }
- else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
- // The target does not implement the hashCode() method itself.
- // 目标类体系中未实现 hashCode 方法, 但是代理的目标方法却是 hashCode 方法
- return hashCode();
- }
- else if (method.getDeclaringClass() == DecoratingProxy.class) {
- // There is only getDecoratedClass() declared -> dispatch to proxy config.
- return AopProxyUtils.ultimateTargetClass(this.advised);
- }
- // isAssignableFrom 方法的意义: 调用方如果是参数方的同类 (接口) 或者父类(接口), 则返回 true
- else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
- method.getDeclaringClass().isAssignableFrom(Advised.class)) {
- // Service invocations on ProxyConfig with the proxy config...
- // 直接反射调用目标方法
- return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
- }
- Object retVal;
- if (this.advised.exposeProxy) {
- // Make invocation available if necessary.
- // 如果设置了 exposeProxy=true, 那么就代理保存起来备用
- oldProxy = AopContext.setCurrentProxy(proxy);
- setProxyContext = true;
- }
- // Get as late as possible to minimize the time we "own" the target,
- // in case it comes from a pool.
- target = targetSource.getTarget();
- Class<?> targetClass = (target != null ? target.getClass() : null);
- // Get the interception chain for this method.
- // 1 - 获取目标方法的拦截链
- List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- // Check whether we have any advice. If we don't, we can fallback on direct
- // reflective invocation of the target, and avoid creating a MethodInvocation.
- if (chain.isEmpty()) {
- // We can skip creating a MethodInvocation: just invoke the target directly
- // Note that the final invoker must be an InvokerInterceptor so we know it does
- // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
- // 如果目标类没有拦截器链, 则直接反射调用目标方法
- Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
- retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
- }
- else {
- // We need to create a method invocation...
- // 2 - 创建一个方法调用, 并执行, ReflectiveMethodInvocation 是 Spring 封装的
- invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
- // Proceed to the joinpoint through the interceptor chain.
- // 3 - 执行拦截器链, 在 ReflectiveMethodInvocation 中维护了拦截器调用的计数器, 保证拦截器的逐个调用, 完成所有拦截器调用之后会反射调用目标方法.
- retVal = invocation.proceed();
- }
- // Massage return value if necessary.
- Class<?> returnType = method.getReturnType();
- if (retVal != null && retVal == target &&
- returnType != Object.class && returnType.isInstance(proxy) &&
- !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
- // Special case: it returned "this" and the return type of the method
- // is type-compatible. Note that we can't help if the target sets
- // a reference to itself in another returned object.
- retVal = proxy;
- }
- else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
- throw new AopInvocationException(
- "Null return value from advice does not match primitive return type for:" + method);
- }
- return retVal;
- }
- finally {
- if (target != null && !targetSource.isStatic()) {
- // Must have come from TargetSource.
- targetSource.releaseTarget(target);
- }
- if (setProxyContext) {
- // Restore old proxy.
- AopContext.setCurrentProxy(oldProxy);
- }
- }
- }
- @Override
- @Nullable
- public Object proceed() throws Throwable {
- // We start with an index of -1 and increment early.
- // 完成所有增强之后执行目标切点方法
- if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
- // 直接调用目标方法
- return invokeJoinpoint();
- }
- // 获取下一个要执行的拦截器
- Object interceptorOrInterceptionAdvice =
- this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
- if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
- // Evaluate dynamic method matcher here: static part will already have
- // been evaluated and found to match.
- InterceptorAndDynamicMethodMatcher dm =
- (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
- if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
- // 动态匹配成功, 则执行拦截器逻辑
- return dm.interceptor.invoke(this);
- }
- else {
- // Dynamic matching failed.
- // Skip this interceptor and invoke the next in the chain.
- // 动态匹配失败, 跳过当前拦截器, 递归执行下一个拦截器
- return proceed();
- }
- }
- else {
- // It's an interceptor, so we just invoke it: The pointcut will have
- // been evaluated statically before this object was constructed.
- // 普通的拦截器, 直接调用即可
- return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
- }
- }
- // AspectJAfterReturningAdvice: 后置通知
- @Override
- public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
- if (shouldInvokeOnReturnValueOf(method, returnValue)) {
- invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
- }
- }
- // AspectJAfterAdvice: 后置终点通知
- @Override
- public Object invoke(MethodInvocation mi) throws Throwable {
- try {
- return mi.proceed();
- }
- finally {
- invokeAdviceMethod(getJoinPointMatch(), null, null);
- }
- }
- // AspectJAroundAdvice: 环绕通知
- @Override
- public Object invoke(MethodInvocation mi) throws Throwable {
- if (!(mi instanceof ProxyMethodInvocation)) {
- throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation:" + mi);
- }
- ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
- ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
- JoinPointMatch jpm = getJoinPointMatch(pmi);
- return invokeAdviceMethod(pjp, jpm, null, null);
- }
- // AspectJMethodBeforeAdvice: 前置通知
- @Override
- public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
- invokeAdviceMethod(getJoinPointMatch(), null, null);
- }
- // AspectJAfterThrowingAdvice: 异常通知
- @Override
- public Object invoke(MethodInvocation mi) throws Throwable {
- try {
- return mi.proceed();
- }
- catch (Throwable ex) {
- if (shouldInvokeOnThrowing(ex)) {
- invokeAdviceMethod(getJoinPointMatch(), null, ex);
- }
- throw ex;
- }
- }
- protected Object invokeAdviceMethod(
- @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
- throws Throwable {
- // 执行参数绑定, 然后使用参数调用通知方法
- return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
- }
- protected JoinPoint getJoinPoint() {
- // 获取当前的连接点实例
- return currentJoinPoint();
- }
- public static JoinPoint currentJoinPoint() {
- // 首先尝试从 ExposeInvocationInterceptor 拦截器中获取当前的方法调用
- MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
- if (!(mi instanceof ProxyMethodInvocation)) {
- throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation:" + mi);
- }
- ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
- // 然后从方法调用之中获取连接点实例 jp
- JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);
- if (jp == null) {
- // 如果未获取到连接点实例, 并设置到方法调用之中
- jp = new MethodInvocationProceedingJoinPoint(pmi);
- pmi.setUserAttribute(JOIN_POINT_KEY, jp);
- }
- return jp;
- }
- protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
- @Nullable Object returnValue, @Nullable Throwable ex) {
- // 提前估测参数绑定
- // 最后就是将所有通知中候选的参数的名称和类型保存到了切点对应属性之中备用
- calculateArgumentBindings();
- // AMC start
- Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
- int numBound = 0;
- if (this.joinPointArgumentIndex != -1) {
- adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
- numBound++;
- }
- else if (this.joinPointStaticPartArgumentIndex != -1) {
- adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
- numBound++;
- }
- if (!CollectionUtils.isEmpty(this.argumentBindings)) {
- // binding from pointcut match
- // 1 - 通过切点匹配进行参数绑定
- if (jpMatch != null) {
- PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
- for (PointcutParameter parameter : parameterBindings) {
- String name = parameter.getName();
- Integer index = this.argumentBindings.get(name);
- adviceInvocationArgs[index] = parameter.getBinding();
- numBound++;
- }
- }
- // binding from returning clause
- // 2 - 通过返回名称进行参数绑定
- if (this.returningName != null) {
- Integer index = this.argumentBindings.get(this.returningName);
- adviceInvocationArgs[index] = returnValue;
- numBound++;
- }
- // binding from thrown exception
- // 3 - 通过异常返回进行参数绑定
- if (this.throwingName != null) {
- Integer index = this.argumentBindings.get(this.throwingName);
- adviceInvocationArgs[index] = ex;
- numBound++;
- }
- }
- if (numBound != this.parameterTypes.length) {
- throw new IllegalStateException("Required to bind" + this.parameterTypes.length +
- "arguments, but only bound" + numBound + "(JoinPointMatch" +
- (jpMatch == null ? "was NOT" : "WAS") + "bound in invocation)");
- }
- // 这里会将通知方法中的所有参数进行绑定, 因为他们都是候选者, 除了一些特殊的不需绑定的之外(只三种切点类型)
- return adviceInvocationArgs;
- }
- public final synchronized void calculateArgumentBindings() {
- // The simple case... nothing to bind.
- if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
- // 无参可绑的情况, 直接返回
- return;
- }
- // 获取参数类型的数量 numUnboundArgs(未绑参数数量)
- int numUnboundArgs = this.parameterTypes.length;
- Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
- // 排除 parameterTypes 中 JoinPoint 类型, ProceedingJoinPoint 类型, JoinPoint.StaticPart 类型的参数
- // JoinPoint 类型的参数可作为非环绕通知的首个参数
- // ProceedingJoinPoint 类型的参数可作为环绕通知的首个参数
- // JoinPoint.StaticPart 类型的参数也可以作为某些通知的首个参数
- // 谨记, 以上三种类型的参数只能作为对应通知的首个参数, 当然也可以和其他参数共存, 但位置必须位于首个, 原因也很简单, 因为此处判断的时候完全就是在拿首个参数类型来完成的.
- // 这三个参数是可以直接使用的, 无需进行参数绑定操作, 所以在这里排除掉
- if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
- maybeBindJoinPointStaticPart(parameterTypes[0])) {
- // 上述三种参数不需要绑定
- numUnboundArgs--;
- }
- if (numUnboundArgs> 0) {
- // need to bind arguments by name as returned from the pointcut match
- // 排除以上类型之后, 如果还有剩余, 则需要根据从切入点匹配返回的名称绑定参数
- // 我们要明白: 切点表达式完全就是用来匹配用的, 哪怕其中有参数, 也是为了匹配指定参数用的, 他不带有任何传参功能, 传参功能只有通知方法才有
- // 所以这里的剩余参数个数, 其实就是通知方法剩余参数, 这里是依据参数名称来进行参数绑定
- bindArgumentsByName(numUnboundArgs);
- }
- this.argumentsIntrospected = true;
- }
- // 通过 name 来绑定参数
- private void bindArgumentsByName(int numArgumentsExpectingToBind) {
- if (this.argumentNames == null) {
- // 创建参数名称发现器, 并获取指定通知方法的参数名称
- this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
- }
- if (this.argumentNames != null) {
- // We have been able to determine the arg names.
- // 只要确认通知使用有参数的就行
- bindExplicitArguments(numArgumentsExpectingToBind);
- }
- else {
- throw new IllegalStateException("Advice method [" + this.aspectJAdviceMethod.getName() + "]" +
- "requires" + numArgumentsExpectingToBind + "arguments to be bound by name, but" +
- "the argument names were not specified and could not be discovered.");
- }
- }
- protected ParameterNameDiscoverer createParameterNameDiscoverer() {
- // We need to discover them, or if that fails, guess,
- // and if we can't guess with 100% accuracy, fail.
- // DefaultParameterNameDiscoverer 是参数名称发现器的默认实现, 他其实是一个
- DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
- AspectJAdviceParameterNameDiscoverer adviceParameterNameDiscoverer =
- new AspectJAdviceParameterNameDiscoverer(this.pointcut.getExpression());// 切点的表达式
- // 如果返回通知后绑定返回值, 则 returningName 为非 null
- adviceParameterNameDiscoverer.setReturningName(this.returningName);
- // 如果在抛出通知后绑定了抛出的值, 则 throwingName 为非 null
- adviceParameterNameDiscoverer.setThrowingName(this.throwingName);
- // Last in chain, so if we're called and we fail, that's bad...
- // 设置在未能推导出通知参数名称的情况下是否抛出 IllegalArgumentException 和 AmbiguousBindingException 异常
- adviceParameterNameDiscoverer.setRaiseExceptions(true);
- // 将配置好的发现器添加到 DefaultParameterNameDiscoverer 中并返回
- discoverer.addDiscoverer(adviceParameterNameDiscoverer);
- return discoverer;
- }
- @Override
- @Nullable
- public String[] getParameterNames(Method method) {
- // 参数类型
- this.argumentTypes = method.getParameterTypes();
- // 初始化未绑定参数个数
- this.numberOfRemainingUnboundArguments = this.argumentTypes.length;
- // 初始化已绑定参数名称数组
- this.parameterNameBindings = new String[this.numberOfRemainingUnboundArguments];
- int minimumNumberUnboundArgs = 0;// 初始化最少未绑参数个数
- // 针对后置通知和异常通知进行特殊处理, 需要将返回值进行绑定
- if (this.returningName != null) {
- // 如果通知类型为后置通知
- minimumNumberUnboundArgs++;
- }
- if (this.throwingName != null) {
- // 如果通知类型为异常通知
- minimumNumberUnboundArgs++;
- }
- if (this.numberOfRemainingUnboundArguments <minimumNumberUnboundArgs) {
- throw new IllegalStateException(
- "Not enough arguments in method to satisfy binding of returning and throwing variables");
- }
- try {
- // 分成八步进行操作
- int algorithmicStep = STEP_JOIN_POINT_BINDING;
- while ((this.numberOfRemainingUnboundArguments> 0) && algorithmicStep <STEP_FINISHED) {
- switch (algorithmicStep++) {
- case STEP_JOIN_POINT_BINDING:
- // 1 - 连接点参数绑定
- // 连接点参数绑定格式为: thisJoinPoint -> 0
- if (!maybeBindThisJoinPoint()) {
- // 连接点参数绑定格式为: thisJoinPointStaticPart -> 0
- maybeBindThisJoinPointStaticPart();
- }
- break;
- case STEP_THROWING_BINDING:
- // 2 - 异常返回参数绑定
- // 异常参数绑定格式为: throwingName -> throwableIndex
- // throwableIndex 为通知参数列表中接收异常的参数的位置
- maybeBindThrowingVariable();
- break;
- case STEP_ANNOTATION_BINDING:
- // 3 - 注解参数绑定
- // 格式: varName -> annotationIndex
- maybeBindAnnotationsFromPointcutExpression();
- break;
- case STEP_RETURNING_BINDING:
- // 4 - 返回参数绑定
- // 绑定返回值时, 只有在未绑定参数只剩余 1 个的情况下才能绑定, 否则不予绑定
- // 当只剩余一个未绑定的情况下, 将返回值与剩余的那个位置的下标进行绑定即可
- maybeBindReturningVariable();
- break;
- case STEP_PRIMITIVE_ARGS_BINDING:
- // 5 - 原始类型参数绑定
- // 只有在有 1 个原始类型参数, 且只有一个候选位置时才执行绑定操作
- maybeBindPrimitiveArgsFromPointcutExpression();
- break;
- case STEP_THIS_TARGET_ARGS_BINDING:
- // 6 - 切点表达式参数绑定
- // 只有只存在一个变量名称的时候才能执行绑定
- maybeBindThisOrTargetOrArgsFromPointcutExpression();
- break;
- case STEP_REFERENCE_PCUT_BINDING:
- // 7 - 引用切点绑定
- // 只有只存在一个变量名称的时候才能执行绑定
- maybeBindReferencePointcutParameter();
- break;
- default:
- throw new IllegalStateException("Unknown algorithmic step:" + (algorithmicStep - 1));
- }
- }
- }
- catch (AmbiguousBindingException ambigEx) {
- if (this.raiseExceptions) {
- throw ambigEx;
- }
- else {
- return null;
- }
- }
- catch (IllegalArgumentException ex) {
- if (this.raiseExceptions) {
- throw ex;
- }
- else {
- return null;
- }
- }
- if (this.numberOfRemainingUnboundArguments == 0) {
- return this.parameterNameBindings;
- }
- else {
- if (this.raiseExceptions) {
- throw new IllegalStateException("Failed to bind all argument names:" +
- this.numberOfRemainingUnboundArguments + "argument(s) could not be bound");
- }
- else {
- // convention for failing is to return null, allowing participation in a chain of responsibility
- return null;
- }
- }
- }
- private void bindExplicitArguments(int numArgumentsLeftToBind) {
- Assert.state(this.argumentNames != null, "No argument names available");
- this.argumentBindings = new HashMap<>();
- // 获取通知方法的参数个数
- int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
- if (this.argumentNames.length != numExpectedArgumentNames) {
- // 参数个数不匹配
- throw new IllegalStateException("Expecting to find" + numExpectedArgumentNames +
- "arguments to bind by name in advice, but actually found" +
- this.argumentNames.length + "arguments.");
- }
- // So we match in number...
- // 获取 parameterTypes 中剩余的参数偏移量, 将其绑定到 argumentBindings 中, numArgumentsLeftToBind 正是之前排除三大首位切点参数之后的剩余参数量
- int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
- for (int i = argumentIndexOffset; i <this.argumentNames.length; i++) {
- // 参数绑定的格式: name-> index
- this.argumentBindings.put(this.argumentNames[i], i);
- }
- // Check that returning and throwing were in the argument names list if
- // specified, and find the discovered argument types.
- if (this.returningName != null) {
- if (!this.argumentBindings.containsKey(this.returningName)) {
- throw new IllegalStateException("Returning argument name'" + this.returningName +
- "'was not bound in advice arguments");
- }
- else {
- // 获取其对应的 index 值, 将其另外绑定到 discoveredReturningType 和 discoveredReturningGenericType 中
- Integer index = this.argumentBindings.get(this.returningName);
- this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
- this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
- }
- }
- if (this.throwingName != null) {
- if (!this.argumentBindings.containsKey(this.throwingName)) {
- throw new IllegalStateException("Throwing argument name'" + this.throwingName +
- "'was not bound in advice arguments");
- }
- else {
- // 获取其对应的 index 值, 并将其另外绑定到 discoveredThrowingType 中
- Integer index = this.argumentBindings.get(this.throwingName);
- this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
- }
- }
- // configure the pointcut expression accordingly.
- // 相应地配置切入点表达式.
- configurePointcutParameters(this.argumentNames, argumentIndexOffset);
- }
- private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {
- int numParametersToRemove = argumentIndexOffset;
- if (this.returningName != null) {
- numParametersToRemove++;
- }
- if (this.throwingName != null) {
- numParametersToRemove++;
- }
- // 之前将所有要移除的参数数量累加出来, 需要移除首位的三种切点参数, returningName 参数和 throwingName 参数
- // 剩余的参数就是切点表达式中可以出现的候选参数, 这里初始化一个切点参数名数组 pointcutParameterNames, 将这些参数囊括进来
- // 另外再初始化两个数组, 分别用于存放这些剩余参数的参数类型 (pointcutParameterTypes) 和通知方法所有参数类型(methodParameterTypes)
- String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove];
- Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length];
- Class<?>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
- int index = 0;
- for (int i = 0; i < argumentNames.length; i++) {
- if (i < argumentIndexOffset) {
- // 小于偏移量的参数为移除的三大切点类型参数
- continue;
- }
- if (argumentNames[i].equals(this.returningName) ||
- argumentNames[i].equals(this.throwingName)) {
- // 这里在对 returningName 和 throwingName 参数进行排除
- continue;
- }
- // 剩余的就是通知中的切点表达式候选参数, 将这些参数的参数名逐个保存到切点参数名数组中
- // 将这些参数的参数类型逐个保存到切点参数类型数组中
- pointcutParameterNames[index] = argumentNames[i];
- pointcutParameterTypes[index] = methodParameterTypes[i];
- index++;
- }
- // 然后, 分别将两个数组设置到切点的对应属性中
- this.pointcut.setParameterNames(pointcutParameterNames);// 設置参数名称
- this.pointcut.setParameterTypes(pointcutParameterTypes);// 设置参数类型
- }
- protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
- Object[] actualArgs = args;
- if (this.aspectJAdviceMethod.getParameterCount() == 0) {
- actualArgs = null;
- }
- try {
- ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
- // TODO AopUtils.invokeJoinpointUsingReflection
- 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();
- }
- }
来源: https://www.cnblogs.com/V1haoge/p/9560803.html