Spring05-AOP源码

AOP是什么

​ AOP(Aspect Oriented Programming),可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

​ 它利用一种称为”横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

​ 使用”横切”技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来

AOP核心概念

横切关注点(对哪些方法进行切入)

对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

切面

​ (aspect,把原来糅杂在业务逻辑代码中的非业务代码抽取出来,把功能相同的放在一个类中形成一个切面)

类是对物体特征的抽象,切面就是对横切关注点的抽象

连接点(joinpoint)(需要切入的点)

​ 被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

切入点(pointcut)

​ 对连接点进行拦截的定义

通知(advice)

​ 所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类

目标对象

​ 代理的目标对象

织入(weave)

​ 将切面应用到目标对象并导致代理对象创建的过程

引入(introduction)

​ 在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

基本案例

1
2
3
4
5
6
7
8
9
10
11
12
13
@Slf4j
@Component
public class Calculator {
public int div(int x,int y){
log.info("Mycaculator...div");
return x / y;
}

public int add(int x,int y){
log.info("Mycaculator...add");
return x + y;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Aspect
@Slf4j
@Component
public class CalculateAspect {
@Pointcut("execution(public int com.study.aop.Calculator.*(..))")
private void pointcut(){};

@Before("pointcut()")
public void before(){
log.info("前置通知。。。");
}

@After("pointcut()")
public void after(){
log.info("后置通知。。。");
}

@AfterReturning("pointcut()")
public void afterReturn(){
log.info("返回通知。。。");
}

@AfterThrowing("pointcut()")
public void afterThrowing(){
log.info("异常通知。。。");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.study.aop"})
public class AopConfig {
}

@Slf4j
public class AopMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
Calculator calculator = context.getBean(Calculator.class);
int add = calculator.add(1, 2);
log.info(add+"");
int div = calculator.div(10, 0);
log.info(div+"");

}
}

-- 结果
2022-09-0822:23:55 INFO CalculateAspect:17 - 前置通知。。。
2022-09-0822:23:55 INFO Calculator:35 - Mycaculator...add
2022-09-0822:23:55 INFO Calculator:39 - add result:3
2022-09-0822:23:55 INFO CalculateAspect:22 - 后置通知。。。
2022-09-0822:23:55 INFO CalculateAspect:27 - 返回通知。。。
2022-09-0822:23:55 INFO AopMain:13 - 3
2022-09-0822:23:55 INFO CalculateAspect:17 - 前置通知。。。
2022-09-0822:23:55 INFO Calculator:28 - Mycaculator...div
2022-09-0822:23:55 INFO CalculateAspect:22 - 后置通知。。。
2022-09-0822:23:55 INFO CalculateAspect:32 - 异常通知。。。
Exception in thread "main" java.lang.ArithmeticException: / by zero

从@EnableAspectJAutoProxy说起

​ 不难看出该注解为我们注入了AnnotationAwareAspectJAutoProxyCreator这个类,分析这个类的继承结构

image-20210701223116469

不难发现这个类觉有BeanFactoryAware、BeanPostProcessor、InstantiationAwareBeanPostProcessor的特性,因此可以得出下图

aopAnnotationAwareAspectJAutoProxyCreator类关系图

image-20210701230423945

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}


@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);

if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}

// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

return null;
}


@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

InstantiationAwareBeanPostProcessor的作用

简述:postProcessBeforeInstantiation()加载事务和AOP的切面并放到缓存中 ,加载事务Advisors和AOP的切面转化为Advisors并放到缓存中

aop源码之InstantiationAwareBeanPostProcessor的作用

BeanPostProcessor的作用

简述:postProcessAfterInitialization() 判断可以之前缓存的切面是否可以应用到类中,代理目标类

aop流程三BeanPostProceesor创建代理对象流程

注解参数

1
@EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = true)

proxyTargetClass

image-20210704164725796

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

//判断容器的类型ConfigurableListableBeanFactory
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

//创建代理工程
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);


/*
* 默认配置下,或用户显式配置 proxy-target-class = "false" 时,
* 这里的 proxyFactory.isProxyTargetClass() 也为 false
*/
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}

else {
/*
* 检测 beanClass 是否实现了接口,若未实现,则将
* proxyFactory 的成员变量 proxyTargetClass 设为 true
*/
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

//获取容器中的方法增强器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

//创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}

public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/**
* 判断使用哪种方式生成代理类
* optimize 控制通过cglib创建的代理是否使用激进的优化策略(仅适用于CGLIB,对JDK动态代理无效)
* proxyTargetClass 是否直接代理目标类
* hasNoUserSuppliedProxyInterfaces 判断有没有用户自定义的代理接口
*/

if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//本类是否接口 注意,一般而言不会进入这个分支
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//jdk代理
return new JdkDynamicAopProxy(config);
}
//cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
jdk代理
return new JdkDynamicAopProxy(config);
}
}

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//创建jdk代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

exposeProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Slf4j
@Component
public class Calculator{

public int div(int x,int y){
log.info("Mycaculator...div");
log.info("div result:{}",x / y);
return x / y;
}

public int add(int x,int y){
log.info("Mycaculator...add");
Calculator proxy =(Calculator) AopContext.currentProxy();
proxy.div(x,y);

log.info("add result:{}",x+y);
return x + y;
}
}

​ @EnableAspectJAutoProxy(exposeProxy = true) 这个东东是用来干什么的?没有配置exposeProxy 暴露代理对象的时候我们方法调用,我们在add方法中 通过this来调用本类的方法div()方法的时候,发现div()的方法不会被拦截,而我们配置了后exposeProxy的属性,我们发现可以通过

int retVal = ((Calculate) AopContext.currentProxy()).div(numA,numB);

​ 调用的时候,发现了div()方法可以被拦截

1
2
3
4
5
6
7
8
9
10
11
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
}
}

原理:把这个exposeProxy设置为true,会把代理对象存放在线程变量中,

AopContext.currentProxy())是从线程变量中获取代理对象(源码中分析)

AOP代理对象的执行流程

调用过程简述:实际调用 Calculator.add 时,实际上调用的是代理对象的对应方法,以JDK代理为例。运用了责任链模式、代理模式、模板方法

JdkDynamicAopProxy#invoke

  1. 进行一些列判断
  2. 判断是否暴露代理对象
    1. 是则把本代理对象设置进入上下文
  3. 获取调用方法上的拦截器链chain = getInterceptorsAndDynamicInterceptionAdvice
    1. 缓存获取
    2. 获取代理类Advised 保存的所有advisors,遍历根据pointcut匹配该方法的advisor
  4. chain为空,则反射调用目标方法
  5. chain不为空 new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain).proceed();
    1. ExposeInvocationInterceptor.invoke(this)
    2. AspectJAfterThrowingAdvice.invoke(this)
    3. AfterReturnAdvice.invoke(this)
    4. AspectJAfterAdvice.invoke(this)
    5. AspectJmethodBeforeAdvice.invoke(this)
    6. 执行before方法
    7. mi.proceed() 目标方法
    8. 执行finally,执行后置通知(after)
    9. 返回通知/异常通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;

try {

Object retVal;

//是否暴露代理对象
if (this.advised.exposeProxy) {
//把代理对象添加到TheadLocal中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

//获取被代理对象
target = targetSource.getTarget();
if (target != null) {
//设置被代理对象的class
targetClass = target.getClass();
}

//把增强器转为方法拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

//若方法拦截器链为空
if (chain.isEmpty()) {
//通过反射直接调用目标方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//创建方法拦截器调用链条
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//执行拦截器链
retVal = invocation.proceed();
}

//获取方法的返回值类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
//如果方法返回值为 this,即 return this; 则将代理对象 proxy 赋值给 retVal
retVal = proxy;
}
//如果返回值类型为基础类型,比如 int,long 等,当返回值为 null,抛出异常
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);
}
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
=====================org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice===========
把增强器中转为方法拦截器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
//从缓存中获取缓存key 第一次肯定获取不到
MethodCacheKey cacheKey = new MethodCacheKey(method);
//通过cacheKey获取缓存值
List<Object> cached = this.methodCache.get(cacheKey);

//从缓存中没有获取到
if (cached == null) {
//获取所有的拦截器
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
//放入缓存.....
this.methodCache.put(cacheKey, cached);
}
return cached;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
=====================org.springframework.aop.framework.AdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice====
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {

//创建拦截器集合长度是增强器的长度
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);

Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

//遍历所有的增强器集合
for (Advisor advisor : config.getAdvisors()) {
//判断增强器是不是PointcutAdvisor
if (advisor instanceof PointcutAdvisor) {
//把增强器转为PointcutAdvisor
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//通过方法匹配器对增强器进行匹配
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
//能够匹配
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
//把增强器转为拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}

return interceptorList;
}

image-20210710173303233

AOP切面如何工作

第一步:(AOP的概念和如何启用)

第一点:先跟他说 aop 是什么东西 vs oop
第二点:跟他把aop 的基本概念说清楚 ?
第三点:@EnableAspectJAutoProxy=====> 导入了AnnotationAwareAspectJAutoProxyCreator组件
我们分析出AnnotationAwareAspectJAutoProxyCreator 的继承关系图发现了他具有
BeanPostProcessor接口特性和InstantiationAwareBeanPostProcessor的特性.
我们发现InstantiationAwareBeanPostProcessor 在实例化之前(调用构造方法之前)执行的.
创建第一个bean,根据Bean的生命周期中的createBean的环节
resolveBeforeInstantiation连触发我的InstantiationAwareBeanPostProcessor的的before方法.
此事在这个环节就会去把我们的切面信息(@Aspectj)的信息找出来 然后进行缓存.

第二步:(创建代理对象的过程)

BeanPostProcessor .afterinItialize方法中
创建要切的对象的时候,根据方法进行匹配去找自己的切面(增强器),然后把增强器和被切的对象创成一个代理对象.

第三步: 代理对象调用过程(jdk代理 ,cglib代理) proxyTragetClass来指定是否固定cglib

通过责任链模式+递归的来进行调用
先执行我们的
异常通知…….(catch里面执行异常通知的方法)
返回通知:(由于正是在这里返回通知中没有进行任何的try catch处理,,,,那么程序抛出异常 就不会执行返回通知的方法而是直接执行到异常通知了)
后置通知:正是因为在后置通知中,代码在finally里中 所以他才是总是被执行的……
前置通知:执行我们的前置通知.
递归终止条件满足:执行我们的目标方法:
1、前置方法
2、后置通知
3、返回通知/异常通知