10. Spring AOP源码解析

Posted IT BOY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10. Spring AOP源码解析相关的知识,希望对你有一定的参考价值。

10 Spring AOP源码解析

目录

10 Spring AOP源码解析

Pt1 Spring AOP基础知识

Pt1.1 AOP核心概念

Pt1.2 AOP切点配置规则

(1) execution

(2) within

(3) args

Pt2 Spring AOP使用示例

Pt2.1 AOP日志(XML)

pom.xml

spring.xml配置AOP信息

加载spring.xml

定义切面

定义Controller

运行Controller

Pt2.2 JDBC(Annotation)

pom.xml

AOP配置

Controller

测试请求

Pt3 Spring AOP核心类

Pt3.1 BeanPostProcessor

Pt3.2 TargetSource

Pt3.3 Advice

Pt3.4 Advisor

Pt3.5 Advised

(1) TargetClassAware

(2) Advised

(3) ProxyConfig

(4) AdvisedSupport

(5) ProxyCreatorSupport

(6) ProxyFactory

Pt3.6 Pointcut

Pt3.7 ClassFilter

Pt3.8 MethodMatcher

Pt3.9 Aware

Pt4 Spring AOP初始化剖析

Pt4.1 寻找入口

Pt4.2 选择代理策略

Pt4.3 生成AOP代理类

Pt4.4 执行代理方法

Pt4.5 触发AOP通知

Pt4.6 流程图

参考资料


Pt1 Spring AOP基础知识

AOP是Aspect Oriented Programming的缩写,意思是面向切面编程,通过预编译和运行时的动态代理,实现在不修改源代码的情况下给程序动态添加功能。同时AOP也为服务方和调用方实现解耦提供了很有效的方式。

在日常编码中,通常分为业务代码和非业务代码,比如事务、日志等,这些代码和业务代码混在一起。举个最常见的例子,就是JDBC的事务处理,有大量的模板代码是的事务处理代码,这些大量重复的、复制粘贴的、和业务处理无关的代码,为维护带来了风险和困难。AOP通过代理机制,可以将这些非业务代码剥离,使得他们可以独立于业务代码存在,从而降低维护的难度和风险。

所以,Spring AOP是一种编程范式,主要目的是将非功能性需求从功能型需求中分离出来,达到解耦的目标。

 


Pt1.1 AOP核心概念

  • Aspect(切面)

    Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

     

  • Jointpoint(连接点)

    表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

     

  • Pointcut(切点)

    表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

     

  • Advice(增强)

    Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

    • @Before:该注解标注的方法在业务模块代码执行之前执行,其不能阻止业务模块的执行,除非抛出异常;

    • @AfterReturning:该注解标注的方法在业务模块代码执行之后执(正常返回)行;

    • @AfterThrowing:该注解标注的方法在业务模块抛出指定异常后执行;

    • @After:该注解标注的方法在所有的Advice执行完成后执行,无论业务模块是否抛出异常,类似于finally的作用;

    • @Around:该注解功能最为强大,其所标注的方法用于编写包裹业务模块执行的代码,其可以传入一个ProceedingJoinPoint用于调用业务模块的代码,无论是调用前逻辑还是调用后逻辑,都可以在该方法中编写,甚至其可以根据一定的条件而阻断业务模块的调用;

    • @DeclareParents:其是一种Introduction类型的模型,在属性声明上使用,主要用于为指定的业务模块添加新的接口和相应的实现。

    • @Aspect:严格来说,其不属于一种Advice,该注解主要用在类声明上,指明当前类是一个组织了切面逻辑的类,并且该注解中可以指定当前类是何种实例化方式,主要有三种:singleton、perthis和pertarget,具体的使用方式后面会进行讲解。

     

  • Target(目标对象)

    织入 Advice 的目标对象.。目标对象可以被一个或者多个切面织入。

     

  • Weaving(织入)

    将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程,就是执行method同时执行advice。

     

  • AOP代理(AopProxy)

    在Spring中有两种形式的代理:JDK动态代理和CGLib代理。后面会详细介绍。

 


Pt1.2 AOP切点配置规则

(1) execution

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且在Spring中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。

 

如下是execution表达式的语法:

 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

这里问号表示当前项可以有也可以没有,其中各项的语义如下:

  • modifiers-pattern:方法的可见性,如public,protected;

  • ret-type-pattern:方法的返回值类型,如int,void等;

  • declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;

  • name-pattern:方法名类型,如buisinessService();

  • param-pattern:方法的参数类型,如java.lang.String;

  • throws-pattern:方法抛出的异常类型,如java.lang.Exception;

 

如下是一个使用execution表达式的例子:

 execution(public * com.spring.service.BusinessObject.businessService(java.lang.String,..))

上述切点表达式将会匹配使用public修饰,返回值为任意类型,并且是com.spring.BusinessObject类中名称为businessService的方法,方法可以有多个参数,但是第一个参数必须是java.lang.String类型的方法。上述示例中我们使用了..通配符,关于通配符的类型,主要有两种:

 

  • *通配符,该通配符主要用于匹配单个单词,或者是以某个词为前缀或后缀的单词。

如下示例表示返回值为任意类型,在com.spring.service.BusinessObject类中,并且参数个数为零的方法:

 execution(* com.spring.service.BusinessObject.*())

下述示例表示返回值为任意类型,在com.spring.service包中,以Business为前缀的类,并且是类中参数个数为零方法:

 execution(* com.spring.service.Business*.*())

 

  • ..通配符,该通配符表示0个或多个项,主要用于declaring-type-pattern和param-pattern中,如果用于declaring-type-pattern中,则表示匹配当前包及其子包,如果用于param-pattern中,则表示匹配0个或多个参数。

如下示例表示匹配返回值为任意类型,并且是com.spring.service包及其子包下的任意类的名称为businessService的方法,而且该方法不能有任何参数:

 execution(* com.spring.service..*.businessService())

这里需要说明的是,包路径service...businessService()中的..应该理解为延续前面的service路径,表示到service路径为止,或者继续延续service路径,从而包括其子包路径;后面的.businessService(),这里的*表示匹配一个单词,因为是在方法名前,因而表示匹配任意的类。

如下示例是使用..表示任意个数的参数的示例,需要注意,表示参数的时候可以在括号中事先指定某些类型的参数,而其余的参数则由..进行匹配:

 execution(* com.spring.service.BusinessObject.businessService(java.lang.String,..))

 

(2) within

within表达式的粒度为类,其参数为全路径的类名(可使用通配符),表示匹配当前表达式的所有类都将被当前方法环绕。如下是within表达式的语法:

 within(declaring-type-pattern)

 

within表达式只能指定到类级别,如下示例表示匹配com.spring.service.BusinessObject中的所有方法:

 within(com.spring.service.BusinessObject)

 

within表达式路径和类名都可以使用通配符进行匹配,比如如下表达式将匹配com.spring.service包下的所有类,不包括子包中的类:

within(com.spring.service.*)

 

如下表达式表示匹配com.spring.service包及子包下的所有类:

within(com.spring.service..*)

 

(3) args

args表达式的作用是匹配指定参数类型和指定参数数量的方法,无论其类路径或者是方法名是什么。这里需要注意的是,args指定的参数必须是全路径的。如下是args表达式的语法:

args(param-pattern)

 

如下示例表示匹配所有只有一个参数,并且参数类型是java.lang.String类型的方法:

args(java.lang.String)

 

也可以使用通配符,但这里通配符只能使用..,而不能使用*。如下是使用通配符的实例,该切点表达式将匹配第一个参数为java.lang.String,最后一个参数为java.lang.Integer,并且中间可以有任意个数和类型参数的方法:

args(java.lang.String,..,java.lang.Integer)

 


Pt2 Spring AOP使用示例

Pt2.1 AOP日志(XML)

  • pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

 

  • spring.xml配置AOP信息

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 自动扫描装配 -->
    <context:component-scan base-package="com.example.springdemo"/>

    <!--启用spring的一些annotation -->
    <context:annotation-config/>

    <!-- AOP配置 -->
    <bean id="logAspect" class="com.example.springdemo.aop.log.LogAspect"></bean>

    <aop:config>
        <aop:aspect id="log" ref="logAspect">
            <aop:pointcut id="logPointcut" expression="execution(* com.example.springdemo.controller.LogController.LogDemo(..))"/>
            <aop:before method="logBefore" pointcut-ref="logPointcut"/>
            <aop:after method="logAfter" pointcut-ref="logPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

 

  • 加载spring.xml

@Configuration
@ImportResource(locations = {"classpath:spring.xml"})
public class ConfigClass {
}

 

  • 定义切面

public class LogAspect {

    public LogAspect() {
        System.out.println("init");
    }

    public void logBefore() {
        System.out.println("Before execution log.");
    }

    public void logAfter() {
        System.out.println("After execution log.");
    }
}

 

  • 定义Controller

@RestController
public class LogController {

    @RequestMapping(value = "logAop", method = RequestMethod.GET)
    public String LogDemo() {
        return "Execute Log Aop test.";
    }
}

 

  • 运行Controller

Before execution log.
After execution log.

 


Pt2.2 JDBC(Annotation)

  • pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

 

  • AOP配置

@Component
@Aspect
public class JdbcAspect {

    // 定义切点
    @Pointcut("execution(* com.example.springdemo.controller.JdbcController.jdbcDemo(..))")
    public void jdbcPointcut() {
    }

    @Before("JdbcAspect.jdbcPointcut()")
    public void jdbcBefore() {
        System.out.println("begin transaction");
    }

    @AfterReturning("JdbcAspect.jdbcPointcut()")
    public void jdbcAfter() {
        System.out.println("commit transaction");
    }

    @AfterThrowing("JdbcAspect.jdbcPointcut()")
    public void jdbcException() {
        System.out.println("rollback transaction");
    }
}

 

  • Controller

@RestController
public class JdbcController {

    @RequestMapping(value = "jdbcAop", method = RequestMethod.GET)
    public String jdbcDemo() {
        return "Execute jdbc Aop test.";
    }
}

 

  • 测试请求

​​​​​​​

begin transaction 
commit transaction

 

 


Pt3 Spring AOP核心类

Pt3.1 BeanPostProcessor

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口,它可以监听容器触发的Bean生命周期事件。向容器中注册BeanPostProcessor之后,容器中管理的Bean就具备了接受IoC容器回调事件的能力。

源码如下:

/**
 * BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口,它可以监听容器触发的Bean生命周期事件。
 * 向容器中注册BeanPostProcessor之后,容器中管理的Bean就具备了接受IoC容器回调事件的能力。
 *
 * 他提供的两个回调方法和容器管理的Bean生命周期事件密切相关,可以为用户提供在Spring IoC容器初始化Bean过程中,去自定义的处理操作提供钩子事件。
 */
public interface BeanPostProcessor {

	// 在Bean的初始化之前提供回调入口
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	// 在Bean的初始化之后提供回调入口
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

 


Pt3.2 TargetSource

在Spring代理目标bean的时候,其并不是直接创建一个目标bean的对象实例的,而是通过一个TargetSource类型的对象将目标bean进行封装,Spring Aop获取目标对象始终是通过TargetSource.getTarget()方法进行的。

换句话说,proxy(代理对象)代理的不是target,而是TargetSource。

 

通常情况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,可以扩展出很多高级功能,如: target pool(目标对象池)、hot swap(运行时目标对象热替换),等等。

 

源码实现:

/**
 * 在Spring代理目标bean的时候,其并不是直接创建一个目标bean的对象实例的,而是通过一个TargetSource类型的对象将目标bean进行封装,
 * Spring Aop获取目标对象始终是通过TargetSource.getTarget()方法进行的。
 * 换句话说,proxy(代理对象)代理的不是target,而是TargetSource。
 *
 * 通常情况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,
 * 可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。
 * 这种机制使得方法调用变得灵活,可以扩展出很多高级功能,如:target pool(目标对象池)、hot swap(运行时目标对象热替换),等等。
 */
public interface TargetSource extends TargetClassAware {

	// 本方法主要用于返回目标bean的Class类型
	@Override
	@Nullable
	Class<?> getTargetClass();

	// 这个方法用户返回当前bean是否为静态的,比如常见的单例bean就是静态的,而prototype就是动态的,
	// 这里这个方法的主要作用是,对于静态的bean,spring是会对其进行缓存的,在多次使用TargetSource
	// 获取目标bean对象的时候,其获取的总是同一个对象,通过这种方式提高效率
	boolean isStatic();

	// 获取目标bean对象,这里可以根据业务需要进行自行定制
	@Nullable
	Object getTarget() throws Exception;

	// Spring在用完目标bean之后会调用这个方法释放目标bean对象,对于一些需要池化的对象,这个方法是必须
	// 要实现的,这个方法默认不进行任何处理
	void releaseTarget(Object target) throws Exception;
}

 


Pt3.3 Advice

Advice表示的是在Pointcut切点上应该执行的方法,即切面Aspect中定义的方法逻辑。

这些方法可以在目标方法之前、之后、包裹、抛出异常等等任何地方执行。

 

源码:

// 标记通知方法
public interface Advice {

}

 


Pt3.4 Advisor

Advisor是 Pointcut 与 Advice 的组合,Advice 是执行的通知方法,而要知道方法何时执行,则 Advice 必需与 Pointcut 组合在一起,这就诞生了 Advisor 。

  • Advice表示通知的内容

  • Pointcut表示通知的时机

  • Advisor表示通知人(它知道通知的时机,且知道是通知的内容)

 

下图是Advisor的类图:

 

Advisor是顶层抽象接口,定义了操作Advice的行为:

// Pointcut 与 Advice 的组合
public interface Advisor {

	// 空的Advice通知
	Advice EMPTY_ADVICE = new Advice() {};

	// 获取通知方法
	Advice getAdvice();

	// 判定当前Advice是否和特定目标值相关
	boolean isPerInstance();
}

 

PointcutAdvisor继承Advisor,定义了操作Pointcut行为,此时具体了可以操作Pointcut和Advice的行为:

public interface PointcutAdvisor extends Advisor {

	// 获取Advisor关联的Pointcut
	Pointcut getPointcut();
}

 

AbstractPointcutAdvisor新增了排序和序列化的能力:

// AbstractPointcutAdvisor是在PointcutAdvisor的基础上,增加Ordered和Serializable接口的能力。
// Spring就提供了Ordered这个接口,来处理相同接口实现类的优先级问题。
@SuppressWarnings("serial")
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {
	// order用于标记执行的优先级。
	@Nullable
	private Integer order;

	// 调用者可以手动来指定Order
	public void setOrder(int order) {
		this.order = order;
	}

	// 获取执行顺序
	@Override
	public int getOrder() {
		if (this.order != null) {
			return this.order;
		}

		// 若调用者没有指定Order,那就拿advice的order为准(若有),否则LOWEST_PRECEDENCE表示最后执行
		Advice advice = getAdvice();
		if (advice instanceof Ordered) {
			return ((Ordered) advice).getOrder();
		}
		return Ordered.LOWEST_PRECEDENCE;
	}

	// 该属性还没有被Spring使用,永远返回TURE
	@Override
	public boolean isPerInstance() {
		return true;
	}


	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof PointcutAdvisor)) {
			return false;
		}
		PointcutAdvisor otherAdvisor = (PointcutAdvisor) other;
		return (ObjectUtils.nullSafeEquals(getAdvice(), otherAdvisor.getAdvice()) &&
				ObjectUtils.nullSafeEquals(getPointcut(), otherAdvisor.getPointcut()));
	}

	@Override
	public int hashCode() {
		return PointcutAdvisor.class.hashCode();
	}
}

 

AbstractGenericPointcutAdvisor保存Advice对象:

public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
	// 保存Advisor关联的Advice
	private Advice advice = EMPTY_ADVICE;

	// setter and getter
	public void setAdvice(Advice advice) {
		this.advice = advice;
	}
	@Override
	public Advice getAdvice() {
		return this.advice;
	}

	@Override
	public String toString() {
		return getClass().getName() + ": advice [" + getAdvice() + "]";
	}
}

 

DefaultPointcutAdvisor是功能最强大的Advisor,保存了Advice和Pointcut对象,同时具备操作这两个对象的能力:

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
	// 保存Advisor关联的Pointcut对象
	private Pointcut pointcut = Pointcut.TRUE;

	// 获取空的Advisor,在使用前必须指定Pointcut对象和Advice对象。
	public DefaultPointcutAdvisor() {
	}

	// 根据指定Advice和默认的Pointcut生成Advisor对象,使用默认Pointcut时,Advice将匹配所有方法。
	public DefaultPointcutAdvisor(Advice advice) {
		this(Pointcut.TRUE, advice);
	}

	// 根据指定Pointcut和Advice生成Advisor对象
	public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
		this.pointcut = pointcut;
		setAdvice(advice);
	}

	// setter and getter
	public void setPointcut(@Nullable Pointcut pointcut) {
		this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
	}
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

	@Override
	public String toString() {
		return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
	}
}

 


Pt3.5 Advised

Advised是对整个代理执行的抽象,创建代理的工厂ProxyFactory,Bean工厂BeanFactory都在该接口中保存。该接口维护了一些代理必要的属性,以及对 Advice,Advisor,Interceptor 的操作,任何被 Spring 代理的对象都可以强转为 Advised。

 

从Advised类图中可以看到,实现类ProxyFactory是创建AOP代理类的工厂。

 

(1) TargetClassAware

接口TargetClassAware表明代理类拥有对目标代理类的操作权限git,具体可以看Aware接口的介绍。

 

(2) Advised

Advised是核心接口,拥有对代理工厂、目标工厂、目标类的操作能力。

// Advised 接口的实现着主要是代理生成的对象与AdvisedSupport (Advised的支持器)
public interface Advised extends TargetClassAware {

	// 这个 frozen 决定是否 AdvisedSupport 里面配置的信息是否改变
	boolean isFrozen();

	// 是否代理指定的类, 而不是一些 Interface
	boolean isProxyTargetClass();

	// 返回代理的接口
	Class<?>[] getProxiedInterfaces();

	// 判断这个接口是否是被代理的接口
	boolean isInterfaceProxied(Class<?> intf);

	// 设置代理的目标对象
	void setTargetSource(TargetSource targetSource);

	// 获取代理的对象
	TargetSource getTargetSource();

	// 判断是否需要将 代理的对象暴露到 ThreadLocal中, 而获取对应的代理对象则通过 AopContext 获取
	void setExposeProxy(boolean exposeProxy);

	// 返回是否应该暴露 代理对象
	boolean isExposeProxy();

	// 设置 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到)
	void setPreFiltered(boolean preFiltered);

	// 获取 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到)
	boolean isPreFiltered();

	// 获取所有的 Advisor
	Advisor[] getAdvisors();

	// 增加 Advisor 到链表的最后
	void addAdvisor(Advisor advisor) throws AopConfigException;

	// 在指定位置增加 Advisor
	void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

	// 删除指定的 Advisor
	boolean removeAdvisor(Advisor advisor);

	// 删除指定位置的 Advisor
	void removeAdvisor(int index) throws AopConfigException;

	// 返回 Advisor 所在位置de index
	int indexOf(Advisor advisor);

	// 将指定的两个 Advisor 进行替换
	boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

	// 增加 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor
	void addAdvice(Advice advice) throws AopConfigException;

	// 在指定 index 增加 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor
	void addAdvice(int pos, Advice advice) throws AopConfigException;

	// 删除给定的 Advice
	boolean removeAdvice(Advice advice);

	// 获取 Advice 的索引位置
	int indexOf(Advice advice);

	// 将 ProxyConfig 通过 String 形式返回
	String toProxyConfigString();
}

 

(3) ProxyConfig

保存了创建代理类的配置属性。

// 创建AOP代理类的配置
public class ProxyConfig implements Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = -8409359707199703185L;

	// 标记是否直接对目标类进行代理,而不是通过接口产生代理
	// 或者说,标记是否使用CGLIB动态代理,true,表示使用CGLIB的方式产生代理对象,false,表示使用JDK动态代理
	private boolean proxyTargetClass = false;

	// 标记是否进行优化。启动优化通常意味着在代理对象被创建后,增强的修改将不会生效,因此默认值为false。
	// 如果exposeProxy设置为true,即使optimize为true也会被忽略。
	private boolean optimize = false;

	// 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
	boolean opaque = false;

	// 标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
	// 当一个代理对象需要调用它自己的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
	boolean exposeProxy = false;

	// 标记该配置是否需要被冻结,如果被冻结,将不可以修改增强的配置。
	// 当我们不希望调用方修改转换成Advised对象之后的代理对象时,这个配置将非常有用。
	private boolean frozen = false;

	// setter and getter
	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}
	public boolean isProxyTargetClass() {
		return this.proxyTargetClass;
	}

	public void setOptimize(boolean optimize) {
		this.optimize = optimize;
	}
	public boolean isOptimize() {
		return this.optimize;
	}

	public void setOpaque(boolean opaque) {
		this.opaque = opaque;
	}
	public boolean isOpaque() {
		return this.opaque;
	}

	public void setExposeProxy(boolean exposeProxy) {
		this.exposeProxy = exposeProxy;
	}
	public boolean isExposeProxy() {
		return this.exposeProxy;
	}

	public void setFrozen(boolean frozen) {
		this.frozen = frozen;
	}
	public boolean isFrozen() {
		return this.frozen;
	}

	// 浅拷贝
	public void copyFrom(ProxyConfig other) {
		Assert.notNull(other, "Other ProxyConfig object must not be null");
		this.proxyTargetClass = other.proxyTargetClass;
		this.optimize = other.optimize;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.opaque = other.opaque;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("proxyTargetClass=").append(this.proxyTargetClass).append("; ");
		sb.append("optimize=").append(this.optimize).append("; ");
		sb.append("opaque=").append(this.opaque).append("; ");
		sb.append("exposeProxy=").append(this.exposeProxy).append("; ");
		sb.append("frozen=").append(this.frozen);
		return sb.toString();
	}
}

 

(4) AdvisedSupport

AdvisedSupport是用于生成Aop代理类的辅助类,保存了目标类、Advisor和method之间的关系。

public class AdvisedSupport extends ProxyConfig implements Advised {

	/** use serialVersionUID from Spring 2.0 for interoperability. */
	private static final long serialVersionUID = 2651364800145442165L;

	// 默认空的TargetSource
	public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;
	TargetSource targetSource = EMPTY_TARGET_SOURCE;

	/** Whether the Advisors are already filtered for the specific target class. */
	// 当前Advisor是否已经过滤了目标类
	private boolean preFiltered = false;

	/** The AdvisorChainFactory to use. */
	AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

	/** Cache with Method as key and advisor chain List as value. */
	// 缓存method和Advisor之间关系
	private transient Map<MethodCacheKey, List<Object>> methodCache;

	// 目标代理类继承的接口
	private List<Class<?>> interfaces = new ArrayList<>();

	// 关联的Advisor
	private List<Advisor> advisors = new ArrayList<>();
	private Advisor[] advisorArray = new Advisor[0];

    // 方法基本都是对于属性的操作
    // ......
}

 

(5) ProxyCreatorSupport

生成代理类的辅助类ProxyCreatorSupport。

public class ProxyCreatorSupport extends AdvisedSupport {

	// AOP代理类生成工厂,用于创建代理类。
	private AopProxyFactory aopProxyFactory;

	// 监听Advisor的变化
	private final List<AdvisedSupportListener> listeners = new ArrayList<>();

	// 第一个AopProxyu对象生成时置为True
	private boolean active = false;

	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}
	public ProxyCreatorSupport(AopProxyFactory aopProxyFactory) {
		Assert.notNull(aopProxyFactory, "AopProxyFactory must not be null");
		this.aopProxyFactory = aopProxyFactory;
	}

	// aopProxyFactory的setter/getter
	public void setAopProxyFactory(AopProxyFactory aopProxyFactory) {
		Assert.notNull(aopProxyFactory, "AopProxyFactory must not be null");
		this.aopProxyFactory = aopProxyFactory;
	}
	public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}

	// 操作AdvisedSupportListener
	public void addListener(AdvisedSupportListener listener) {
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.add(listener);
	}
	public void removeListener(AdvisedSupportListener listener) {
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.remove(listener);
	}


	// 获取AopProxy,用于生成Bean的代理类
	protected final synchronized AopProxy createAopProxy() {
		// 第一个AopProxy被创建时,执行以下激活操作。
		if (!this.active) {
			activate();
		}

		// 获取AopProxy,用于生成Bean的代理类
		return getAopProxyFactory().createAopProxy(this);
	}

	// 激活AopProxy配置。
	private void activate() {
		this.active = true;
		for (AdvisedSupportListener listener : this.listeners) {
			listener.activated(this);
		}
	}

	// 监听advice变更事件
	@Override
	protected void adviceChanged() {
		super.adviceChanged();
		synchronized (this) {
			if (this.active) {
				for (AdvisedSupportListener listener : this.listeners) {
					listener.adviceChanged(this);
				}
			}
		}
	}

	protected final synchronized boolean isActive() {
		return this.active;
	}
}

 

(6) ProxyFactory

ProxyFactory是生成目标AOP代理类的工厂类。

public class ProxyFactory extends ProxyCreatorSupport {

	public ProxyFactory() {
	}

	// 根据目标类生成代理类
	public ProxyFactory(Object target) {
		setTarget(target);
		setInterfaces(ClassUtils.getAllInterfaces(target));
	}

	// 根据目标接口生成代理类
	public ProxyFactory(Class<?>... proxyInterfaces) {
		setInterfaces(proxyInterfaces);
	}

	public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
		addInterface(proxyInterface);
		addAdvice(interceptor);
	}

	public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
		addInterface(proxyInterface);
		setTargetSource(targetSource);
	}

	// 生成代理类
	public Object getProxy() {
		return createAopProxy().getProxy();
	}

	// 基于指定的ClassLoader和Factory设置,创建AOP代理类。
	public Object getProxy(@Nullable ClassLoader classLoader) {
		// createAopProxy():获取AOP代理类,有JdkDynamicAopProxy和CglibAopProxy两种。
		// getProxy:使用AOP代理类,生成目标Bean的代理类。
		// 这里假定使用JdkDynamicAopProxy的方式执行getProxy方法
		return createAopProxy().getProxy(classLoader);
	}

	// 生成代理类
	public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
		return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();
	}

	// 生成代理类
	@SuppressWarnings("unchecked")
	public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
		return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();
	}

	// 生成代理类
	public static Object getProxy(TargetSource targetSource) {
		if (targetSource.getTargetClass() == null) {
			throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setTargetSource(targetSource);
		proxyFactory.setProxyTargetClass(true);
		return proxyFactory.getProxy();
	}
}

 


Pt3.6 Pointcut

Pointcut是AOP中非常重要的一个类,它定义了AOP切点逻辑,约定了Advice通知的时机。

 

我们先来看看其中一个实现类AspectJExpressionPointcut类的相关类图。

 

从类图上可以看出,AspectJExpressionPointcut主要有4个顶层接口:

  • Pointcut:定义和切点相关的能力。

  • Aware:标记当前类具备某种行为的感知能力。

  • MethodMatcher:用来匹配mehtod是否匹配切点的规则,从而决定是否需要通知Advice。

  • ClassFilter:用来匹配Class是否匹配切点规则。

ClassFilter限定在类级别上,MethodMatcher限定在方法级别上。

 

首先来看Pointcut顶层接口的能力:

// 切点的顶层抽象接口
public interface Pointcut {

	// 返回当前Pointcut的ClassFilter,用于匹配Class是否符合切点逻辑。
	ClassFilter getClassFilter();

	// 返回当前Pointcut的MethodMatcher对象,用于匹配method规则。
	MethodMatcher getMethodMatcher();

	// 默认值,如果返回此结果表明所有method都会被匹配成功。
	Pointcut TRUE = TruePointcut.INSTANCE;
}

 

// 匹配规则使用String表达式的Pointcut
public interface ExpressionPointcut extends Pointcut {

	// 返回切点规则表达式
	@Nullable
	String getExpression();
}

 

public abstract class AbstractExpressionPointcut implements ExpressionPointcut, Serializable {

	// 切点位置
	@Nullable
	private String location;

	// 切点匹配规则表达式
	@Nullable
	private String expression;


	// setter and getter
	public void setLocation(@Nullable String location) {
		this.location = location;
	}
	@Nullable
	public String getLocation() {
		return this.location;
	}

	public void setExpression(@Nullable String expression) {
		this.expression = expression;
		try {
			onSetExpression(expression);
		}
		catch (IllegalArgumentException ex) {
			// Fill in location information if possible.
			if (this.location != null) {
				throw new IllegalArgumentException("Invalid expression at location [" + this.location + "]: " + ex);
			}
			else {
				throw ex;
			}
		}
	}
	protected void onSetExpression(@Nullable String expression) throws IllegalArgumentException {
	}
	@Override
	@Nullable
	public String getExpression() {
		return this.expression;
	}
}

 

最终实现类是AspectJExpressionPointcut类:

// Pointcut实现类。
@SuppressWarnings("serial")
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
		implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {

	private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
    
    ......
        
}

 


Pt3.7 ClassFilter

比较简单,直接看源码:

// ClassFilter限定在类级别上,判断是否符合Pointcut规则。
@FunctionalInterface
public interface ClassFilter {

	// true表示能够匹配。那就会进行织入的操作
	boolean matches(Class<?> clazz);

	// 默认值。会匹配所有的类,TrueClassFilter不是public得class,所以只是Spring内部自己使用的。
	ClassFilter TRUE = TrueClassFilter.INSTANCE;
}

 


Pt3.8 MethodMatcher

MethodMatcher用于定义Pointcut匹配method的逻辑:

// Pointcut匹配逻辑:判断方法是否符合Pointcut规则,执行Advice通知。
public interface MethodMatcher {

	// 这个称为静态匹配:在匹配条件不是太严格时使用,可以满足大部分场景的使用
	boolean matches(Method method, Class<?> targetClass);

	// 这个称为动态匹配(运行时匹配): 它是严格的匹配。在运行时动态的对参数的类型进行匹配
	boolean matches(Method method, Class<?> targetClass, Object... args);

	// 两个方法的分界线就是boolean isRuntime()方法,步骤如下
	// 1、先调用静态匹配,若返回true。此时就会继续去检查isRuntime()的返回值
	// 2、若isRuntime()还返回true,那就继续调用动态匹配
	// (若静态匹配都匹配上,动态匹配那铁定更匹配不上得~~~~)
	boolean isRuntime();

	// 默认值
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

 

实现接口:

// 校验方法是否匹配Pointcut规则
public interface IntroductionAwareMethodMatcher extends MethodMatcher {
   boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
}

 


Pt3.9 Aware

我们在介绍下Aware接口。

打开Aware接口可以看到,他是一个空接口,没有任何实现。他标识的其实是一种能力,Spring容器中的Bean能够具备感知某一对象的能力。

// Aware是顶层超类,用于标识是否具备一种能力。
public interface Aware {

}

 

比如,BeanFactoryAware是继承了Aware的接口,它就代表Bean对归属Spring IoC容器的感知能力。

// 实现了BeanFactoryAware接口的类,能够感知到他所属的BeanFactory。直白点,就是Bean能够获得他所属的BeanFactory对象。
// 这就是Aware接口的能力,他使得继承类能够具备某一种感知的能力。
public interface BeanFactoryAware extends Aware {

	// 设置当前Bean所属的BeanFactory实例
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

 

还有TargetClassAware接口:

// 该接口使得,对应的代理类拥有感知TargetClass的能力,就是能够操作目标代理类。
public interface TargetClassAware {
	// 获得目标代理类。
	@Nullable
	Class<?> getTargetClass();
}

 


Pt4 Spring AOP初始化剖析

Pt4.1 寻找入口

在AOP基础部分中,介绍过AOP的原理是生成原始Bean对象的代理类,从而在执行过程中通过动态代理完成逻辑横切。

所以AOP的初始化是在Bean初始化完成之后发生的。在DI部分,通过调用BeanFactory.getBean()触发Bean的初始化和依赖注入,当整个Bean初始化逻辑之心完成后,会继续执行AOP初始化处理,为Bean创建AOP代理类。

 

DI操作是通过调用#getBean()触发的,其核心逻辑是在AbstractAutowireCapableBeanFactory#doCreateBean()执行。我们跳过IoC、DI和MVC部分的详细逻辑介绍,直接从doCreateBean()来找AOP的入口。

先来看#doCreateBean()实例化逻辑:

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
    String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    throws BeansException {

    // ......
    
	// 跳过DI前后其他逻辑,这部分在DI部分已经详细介绍过。
    // 不管Bean的Scope是那种,最终都是通过#createBean()·。
    return createBean(beanName, mbd, args);
    
    // ......
}

 

还没到AOP的地方,继续往下:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// 真正完成指定Bean对象创建的方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {

    // ......
    
    // 跳过DI前后其他逻辑,这部分在DI部分已经详细介绍过。
    // Bean的处理只要分为三个步骤:
    //    1. 实例化,执行构造器;
    //    2. 依赖注入;
    //    3. 调用init-method;
    // 到这里,DI已经完成Bean的实例化操作,这是第一步,我们继续往下看。
    
    // 2、对Bean进行依赖注入
    populateBean(beanName, mbd, instanceWrapper);

    // 3、Bean实例对象依赖注入完成后,开始对Bean实例对象进行初始化,为Bean实例对象应用BeanPostProcessor后置回调处理
    // AOP的逻辑在这里执行
    exposedObject = initializeBean(beanName, exposedObject, mbd);
       
    // ......
}

 

找到#initializeBean,这里才是真正开始的地方:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
// 初始化容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // JDK安全机制验证权限
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // 为Bean实例对象包装相关属性:类名称、类加载器、所属容器等。
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 1、调用BeanPostProcessor的回调方法,执行Bean初始化之前的操作。
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 2、调用Bean的Init-Method方法,完成Bean的初始化操作。
        // 这个Bean的初始化方法是在Spring Bean定义配置文件中通过init-method属性指定的。
        // 这里不是新建Bean的实例操作,此时的Bean已经完成实例化处理,生成了Bean的实例对象,也完成了属性的设置。
        // 如果Bean定义中配置了init-method,这里将执行该方法完成Bean配置中所有init动作。
        invokeInitMethods(beanName, wrappedBean, mbd);
        // 到此为止,Bean实例的初始化操作已经完成,创建了Bean对象,完成了属性的依赖注入,执行了自定义的init-method方法。
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 3、调用BeanPostProcessor的回调方法,执行Bean初始化之后的操作。
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

代码里分为三步:

  1. 调用BeanPostProcessor的回调方法,执行Bean初始化之前的操作。

  2. 调用Bean的Init-Method方法,完成Bean的初始化操作。

  3. 调用BeanPostProcessor的回调方法,执行Bean初始化之后的操作。

 

AOP是在Bean完成初始化之后触发的,前两部Bean还没有完成初始化,所以真正跟AOP相关的操作,是在第3步开始的:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
// 调用BeanPostProcessor的回调方法,执行Bean初始化之后的操作。
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {

    Object result = existingBean;
    // 遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器。
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 调用Bean实例所有定义的BeanPostProcessor初始化之后回调操作,完成初始化后的自定义操作。
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

 


Pt4.2 选择代理策略

执行BeanPostProcessor的后置回调方法,AOP的BeanPostProcessor实现类很多,其中AbstractAutoProxyCreator是非常重要的一个。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

 

wrapIfNecessary()是非常核心的方法,负责处理AOP代理。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
/**
 * 如果给定的Bean符合AOP条件,则生成代理类。
 * 
 * @param bean         原始Bean实例对象
 * @param beanName     Bean的名称
 * @param cacheKey     从Bean信息得到的唯一缓存Key
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }

    // 判断是否应该代理这个Bean
    if (Boolean

以上是关于10. Spring AOP源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP源码解析:Spring事务实现原理

三:Spring-AOP源码

Spring源码分析AOP源码解析(下篇)

做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析

Spring AOP源码解析

spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)