Spring 注解编程AOP

  1. AOP的常用注解
  2. AOP的源码分析
  3. 事务的注解与源码分析

AOP的常用注解

Aspect-Oriented Programming 面向切面编程,主要包含切面Aspect,切入点Pointcut以及通知(切入时机)Advice,通知包含方法执行之前Before、方法执行之后After、方法环绕Around,通知方法参数有JoinPoint,Around方法参数有ProceedingJoinPoint

  • JoinPoint只能放在方法的第一个参数,主要方法如下
    • getArgs() 返回方法的参数
    • getThis() 返回代理对象
    • getTarget() 返回目标对象
    • getSignature() 返回通知方法的签名
    • toString() 返回通知方法有用描述
  • ProceedingJoinPoint只能放在方法的第一个参数,主要方法如下
    • proceed(Object[] args) 执行目标方法

@EnableAspectJAutoProxy

启用切面,相当于xmlaop:aspectj-autoproxy

1
<aop:aspectj-autoproxy />
  • proxyTargetClass 对应xml中属性proxy-target-class,是否启用CGLIB
  • exposeProxy 对应xml中属性expose-proxy ,是否暴露代理,设置为true的时候,可以通过AopContext.currentProxy() 获取代理实例(通过ThreadLocal进行实现的)

@Aspect

切面,横切多个类的关系的模块化

1
2
3
4
@Aspect
@Component
public class LogAspect {
}

相当于xml

1
2
3
4
5
<aop:config>
<aop:aspect id="logAspect" ref="logAspectBean">
</aop:config>

<bean id="logAspectBean" class="top.felixfly.aop.apesct.LogAspect"></bean>

@Pointcut

切点,执行方法的切点

1
2
3
@Pointcut("execution(* top.felixfly.aop.service.*Service.*(..))")
public void servicePoint() {
}

相当于xml

1
2
3
4
<aop:config>
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
</aop:config>

切入点表达式

  • execution 切入表达式,这个Spring中最常用的

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

    • execution(public * *(..)) 所有包下的public方法
    • execution(* set*(..)) 所有已set开头的方法`*
    • execution(* com.xyz.service.AccountService.*(..))AccountService下的所有方法
    • execution(* com.xyz.service.*.*(..)) service包下的所有类的方法
    • execution(* com.xyz.service..*.*(..)) service包以及子包的所有类的方法
  • within

    • within(com.xyz.service.*) service包下的所有类的方法
    • within(com.xyz.service.*) service包以及子包所有类的方法
  • this 指定代理实现的接口

  • this(com.xyz.service.AccountService) 指定AccountService接口下的所有方法

  • target 执行目标对象实现的接口

  • target(com.xyz.service.AccountService) 指定AccountService接口下的所有方法

  • args 执行目标方法的参数

  • args(java.io.Serializable)Serializable参数的所有方法

  • @target

  • @target(org.springframework.transaction.annotation.Transactional) 目标对象有@Transactional注解的类所有方法

  • @within

  • @within(org.springframework.transaction.annotation.Transactional) 目标对象有@Transactional注解申明的类所有方法

  • @annotation

  • @annotation(org.springframework.transaction.annotation.Transactional)@Transactional注解的所有方法

  • @args

  • @args(com.xyz.security.Classified)@Classified注解的单参数方法

  • bean

    • bean(*ServiceImpl) 所有以ServiceImpl结尾Bean的所有方法

@Before

在切点的方法之前执行方法

1
2
3
4
@Before("servicePoint()")
public void before(JoinPoint joinPoint) {
System.out.println("before。。。。。");
}

相当于xml

1
2
3
4
5
6
7
<aop:config>
<aop:aspect id="logAspect" ref="logAspect">
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
<aop:before pointcut-ref="servicePoint" method="before"/>
</aop:aspect>
</aop:config>

@AfterReturning

在切点的方法执行返回执行

1
2
3
4
@AfterReturning(value="servicePoint()",returing="object")
public void afterReturning(JoinPoint joinPoint,Object object) {
System.out.println("afterReturning。。。。。");
}

相当于xml

1
2
3
4
5
6
7
<aop:config>
<aop:aspect id="logAspect" ref="logAspect">
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
<aop:after-returning pointcut-ref="servicePoint" method="afterReturning" returning="object" />
</aop:aspect>
</aop:config>

@AfterThrowing

在切点的方法执行抛出异常执行

1
2
3
4
@AfterThrowing(value = "servicePoint()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("afterThrowing。。。。。" + ex);
}

相对于xml

1
2
3
4
5
6
7
<aop:config>
<aop:aspect id="logAspect" ref="logAspect">
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
<aop:after-throwing pointcut-ref="servicePoint" method="afterThrowing" throwing="ex" />
</aop:aspect>
</aop:config>

@After

在切点方法执行之后执行,也就是在@AfterReturning或者@AfterThrowing之前执行

1
2
3
4
@After("servicePoint()")
public void after(JoinPoint joinPoint) {
System.out.println("after。。。。。");
}

相当于xml

1
2
3
4
5
6
7
<aop:config>
<aop:aspect id="logAspect" ref="logAspect">
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
<aop:after pointcut-ref="servicePoint" method="after" />
</aop:aspect>
</aop:config>

@Around

在切点方法执行前后执行

1
2
3
4
5
6
7
8
9
10
@Around(value = "servicePoint()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 执行目标方法之前,在@Before方法之前执行
System.out.println("around before。。。。。" );
// 执行目标方法
Object retVal = joinPoint.proceed(joinPoint.getArgs());
// 执行目标方法之后,@After之前执行
System.out.println("around after。。。。。" );
return retVal;
}

相当于xml

1
2
3
4
5
6
7
<aop:config>
<aop:aspect id="logAspect" ref="logAspect">
<aop:pointcut id="servicePoint"
expression="execution(* top.felixfly.aop.service.*Service.*(..))"/>
<aop:around pointcut-ref="servicePoint" method="around" />
</aop:aspect>
</aop:config>

AOP的执行顺序

正常执行流程:@Around -> @Before -> @After -> @AfterReturning

异常执行流程:@Around -> @Before -> @After -> @AfterThrowing

切面的主要接口

PointCut 切入点

  • ClassFilter 类的过滤器
  • MethodMatcher 方法的匹配器

Advice 通知

  • BeforeAdvice 前置通知
  • AfterAdvice 后置通知
  • AfterReturningAdvice 执行返回通知
  • ThrowsAdvice 异常通知

MethodInterceptor 方法的拦截器(继承Advice)

  • MethodBeforeAdviceInterceptor 方法前置拦截器
  • AspectJAroundAdvice ApectJ环绕拦截器
  • AspectJAfterAdvice ApectJ后置拦截器
  • AfterReturningAdviceInterceptor 后置返回拦截器
  • AspectJAfterThrowingAdvice 后置异常拦截器

Advisor 通知器

  • Advice 通知

PointcutAdvisor 切入点通知器(继承Advisor)

  • Pointcut 切入点

动态代理的主要接口

AopProxy Aop动态代理

  • JdkDynamicAopProxy Jdk动态代理
  • CglibAopProxy Cglib动态代理
    • ObjenesisCglibAopProxy 扩展的 Cglib动态代理

这个是通过org.springframework.aop.framework.DefaultAopProxyFactory进行动态匹配生成,构建执行链org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice关联了Advisor

AOP的源码分析

@EnableAspectJAutoProxy

注解通过@Import(AspectJAutoProxyRegistrar.class)注册

  • 实现ImportBeanDefinitionRegistrar
  • AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
    • 注册org.springframework.aop.config.internalAutoProxyCreator ——AnnotationAwareAspectJAutoProxyCreator,最高优先级

AnnotationAwareAspectJAutoProxyCreator

实现主要接口

  • BeanFactoryAware BeanFactory回调接口
  • InstantiationAwareBeanPostProcessor 实例化执行的接口
  • BeanPostProcessor Bean后置处理器

BeanFactoryAware BeanFactory回调接口

  • AbstractAdvisorAutoProxyCreator#setBeanFactory

  • AnnotationAwareAspectJAutoProxyCreator#initBeanFactory

    • ReflectiveAspectJAdvisorFactory

      处理Advice通知注解@Around@Before@After@AfterReturning@AfterThrowing

      构建了一个PointcutAdvisor(InstantiationModelAwarePointcutAdvisorImpl)

      • AspectJExpressionPointcut PointCut切点表达式
      • Advice 通知
    • BeanFactoryAspectJAdvisorsBuilderAdapter

InstantiationAwareBeanPostProcessor 实例化执行的接口

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 实例化执行的方法

AbstractAutoProxyCreator#postProcessBeforeInstantiation

  • 判断是否是通知Bean
    • AdvicePointcutAdvisorAopInfrastructureBean 这几个类的子类
    • @Aspect注解的类
    • bean的名词是否以bean的Class名称开头并且以.ORIGINAL结束
  • 是否需要跳过
    • 获取Advisor通知器列表(获取到了InstantiationModelAwarePointcutAdvisorImpl)
  • 是否自定义TargetSourceCreator,若是有直接执行createProxy

BeanPostProcessor Bean后置处理器

BeanPostProcessor#postProcessAfterInitialization 初始化执行的方法

AbstractAutoProxyCreator#postProcessAfterInitialization

  • wrapIfNecessary
    • 判断是否是通知Bean
    • 是否需要跳过
    • 判断是否有Advice通知的Bean创建代理
      • createProxy
        • DefaultAopProxyFactory#createAopProxy
          • config.isProxyTargetClass()
            • 接口或者是Proxy的子类,使用JdkDynamicAopProxy
            • 其他使用ObjenesisCglibAopProxy
          • 创建JdkDynamicAopProxy

通过代码实现切面

实现一个PointAdvisor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 日志通知器
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/5/18
*/
public class TraceBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {


@Override
public Pointcut getPointcut() {
// 所有的方法
return Pointcut.TRUE;
}
}

实现一个MethodInterceptor

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
/**
* 日志拦截器
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/5/18
*/
public class TraceInterceptor extends SimpleTraceInterceptor {


private final AtomicInteger count = new AtomicInteger();

@Override
protected boolean isLogEnabled(Log logger) {
// 调整日志级别
return logger.isInfoEnabled();
}


@Override
protected void writeToLog(Log logger, String message, Throwable ex) {
// 打印日志方式
if (Objects.nonNull(ex)) {
logger.error(message, ex);
return;
}
logger.info(message);
}


@Override
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
// 这地方有个并发的问题
// 可以构建个上下文用ThreadLocal处理,ThreadLocal什么时候进行移除?
int num = count.incrementAndGet();
long start = System.currentTimeMillis();
try {
Object proceed = invocation.proceed();
// 执行序号|执行方法名|执行时间|入参|出参|错误信息
writeToLog(logger, getDescription(invocation, num, proceed, System.currentTimeMillis() - start));
return proceed;

} catch (Throwable ex) {
writeToLog(logger, getDescription(invocation, num, null, System.currentTimeMillis() - start), ex);
throw ex;
}
}

private String getDescription(MethodInvocation invocation, int num, Object returnObject, long time) {
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
return String.format("%d|%s#%s|%d|%s|%s", num,
method.getDeclaringClass().getSimpleName(), method.getName(), time, JSON.toJSONString(arguments),
Objects.isNull(returnObject) ? "" : JSON.toJSONString(returnObject));
}
}

配置Bean信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Aop切面配置
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2019/11/28
*/
@Configuration
@EnableAspectJAutoProxy // 一定要开启,不开启无效,自定义的实现是通过EnableAspectJAutoProxy来实现的
public class AopConfiguration {

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TraceBeanFactoryPointcutAdvisor traceBeanFactoryPointcutAdvisor(){
TraceBeanFactoryPointcutAdvisor pointcutAdvisor = new TraceBeanFactoryPointcutAdvisor();
pointcutAdvisor.setAdvice(traceInterceptor());
return pointcutAdvisor;
}

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TraceInterceptor traceInterceptor(){
return new TraceInterceptor();
}
}

若是不希望拦截所有的方法,自行实现Pointcut

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
/**
* 日志切面
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/5/18
*/
public class TracePointcut implements Pointcut, Serializable {

public static final TracePointcut INSTANCE = new TracePointcut();

/**
* Enforce Singleton pattern.
*/
private TracePointcut() {
}

@Override
public ClassFilter getClassFilter() {
// service 注解打点,true表示派生的注解
return new AnnotationClassFilter(Service.class, true);
}

@Override
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}

/**
* Required to support serialization. Replaces with canonical
* instance on deserialization, protecting Singleton pattern.
* Alternative to overriding {@code equals()}.
*/
private Object readResolve() {
return INSTANCE;
}

@Override
public String toString() {
return "Pointcut.TRUE";
}
}

事务的注解与源码分析

事务的解决问题

  • 脏读

    一个线程在处理数据,事务还未提交;另一个线程可以读到此数据

  • 重复读

    一个线程读数据,另一个线程改数据,导致同一个线程获取的数据不一致。

  • 幻读

    一个线程读数据,另一个线程添加数据,导入同一个线程获取的数据条目不一致,多出来的条目称为幻行。

事务的隔离级别Connection

  • READ_UNCOMMITTED 读未提交的
  • READ_COMMITTED 读已提交
  • REPEATABLE_READ 重复读
  • SERIALIZABLE 串行

事务的传播机制TransactionDefinition

  • REQUIRED 必须以事务执行,若有事务,以当前事务执行,没有事务重新启动新事务执行
  • SUPPORTS 支持事务执行,若有事务,用当前事务执行,没有事务不进行事务操作
  • MANDATORY 支持事务执行,若有事务,用当前事务执行,没有事务抛错
  • REQUIRES_NEW 以新事务执行
  • NOT_SUPPORTED 支持无事务执行
  • NEVER 无事务执行,有事务抛错
  • NESTED 若是有事务存在,嵌套事务执行

常用注解

@EnableTransactionManagement

开启事务的注解

@Transactional

启用事务的注解

源码分析

@EnableTransactionManagement

通过@Import(TransactionManagementConfigurationSelector.class)注册

  • PROXY JDK代理通知

    • AutoProxyRegistrar

      • AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)

        注册org.springframework.aop.config.internalAutoProxyCreator ——InfrastructureAdvisorAutoProxyCreator

        优先级判断

      • AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)

        org.springframework.aop.config.internalAutoProxyCreator设置属性proxyTargetClass

    • ProxyTransactionManagementConfiguration

      注册如下的Bean

      • transactionAdvisor——BeanFactoryTransactionAttributeSourceAdvisor 事务通知者
        • TransactionAttributeSource
        • Advice——TransactionInterceptor
      • transactionAttributeSource——AnnotationTransactionAttributeSource
      • transactionInterceptor——TransactionInterceptor 事务方法拦截器
        • TransactionAttributeSource
        • TransactionManager
  • ASPECTJ AspectJ代理通知

    • AspectJJtaTransactionManagementConfiguration
    • AspectJTransactionManagementConfiguration

Spring 注解编程AOP
http://example.com/2019/01/09/Spring/Spring 注解编程AOP/
作者
FelixFly
发布于
2019年1月9日
许可协议