之前已经写过不少文章分析SpringIOC相关的源码部分,接下来准备研究一下AOP部分,个人觉得AOP相比IOC要困难一些,因为AOP的概念显得更加抽象,所以在分析AOP相关源码之间,首先必须要搞清楚一些概念问题。
Advice(通知)
Advice就是具体的你想要增加的功能了。
Pointcut(切入点)
Pointcut主要就是用来申明哪些类、哪些方法需要使用到Advice。
Aspect(切面)
Aspect从源码部分来理解,就是Advice和Pointcut组合后变成了一类功能的抽象,比如事务切面、日志切面等等,就理解为Advice+Pointcut就是切面。
Joinpoint(连接点)
Joinpoint就是发生在运行时的一种概念,符合Pointcut规则的方法,再根据Advice的类型找到在方法调用之前,或者之后的那些点就是连接点。
Weaving(织入)
Weaving也是一个运行时的概念,就是一个把Advice的功能添加到Joinpoint上的过程,最后会生成相关的代理对象。
通过一段代码,加深理解
@Component
@Aspect
public class DemoAspect {
//切入点,定义了一个表达式,表示com.wyl.learn.service包及其子包下的所有方法都满足条件
@Pointcut("execution(* com.wyl.learn.service..*.*(..))")
public void log() {
}
/**
* @Before 前置通知
* @After 后置通知,无论执行后是正常还是异常
* @AfterReturning 正常执行完后的通知
* @Around 环绕通知,方法调用前后的通知
* @AfterThrowing 抛出异常后的通知
*/
//具体的通知,@Before为前置通知,表示在调用目标方法之前会先调用beforeLog这个方法。
//"log()"表示,待增强的方法必须要在log这个切入点条件中。
@Before("log()")
public void beforeLog(JoinPoint joinPoint) {
System.out.println("Before 前置通知=====");
}
@AfterReturning("log()")
public void afterReturningLog(JoinPoint joinPoint) {
System.out.println("AfterReturning 返回后通知=====");
}
@After("log()")
public void afterLog(JoinPoint joinPoint) {
System.out.println("After 后置通知=====");
}
@Around("log()")
public void aroundLog(ProceedingJoinPoint joinPoint) {
System.out.println("=====around before");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("=====around after");
}
/**
* 上面定义的@Pointcut和@Before,组合起来就可以理解为是一个切面,
* 此切面定义的就是对service包及其子包下的所有方法,在调用前增加beforeLog中定义的两行打印的内容。
*/
}
package com.wyl.learn.service;
@Component
public class HelloSpring {
//这个方法中每个符合Advice类型的前后点,就是Joinpoint
public void hello() {
//around before
//@Before
System.out.println("方法自身输出内容:hello spring!");
try {
//如果没有异常,around after
//如果没有异常,@After
//如果没有异常,@AfterReturning
} catch (Exception e) {
//如果有异常,around after
//如果有异常,@After
//如果有异常,@AfterReturning
throw e;
}
}
}
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn");
HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring");
helloSpring.hello();
}
}
输出结果:
=====around before
Before 前置通知=====
方法自身输出内容:hello spring!
=====around after
After 后置通知=====
AfterReturning 返回后通知=====