Spring笔记03-面向切面编程AOP
3.1 AOP的概念
AOP适用于以下场景:代码交织(code tangling)和代码分散(code scattering)
代码交织是指一个方法完成多个功能,这几个功能之间又没有必然联系,比如我们需要做日志、检查授权和执行业务逻辑,如果我们不用AOP的话那这三个就混在一起了。
代码分散式指比如我们有多处需要做日志,然后这些代码在多个地方重复。
AOP允许我们将这些动作封装成一个类,然后告诉Spring我们希望在多个地方调用这个类(成为Aspect),从而避免代码交织和分散。
AOP会设计到一下几个概念:
- 连接点Join Point
- 切入点Point Cut
- Advice
- Aspect
- Weaving
3.1.1 连接点(Join Point)和切入点(Point Cut)
连接点,指的是我们能够应用我们Aspect的地方。这是告诉我们where to use the Aspects.
在一般概念的AOP上,我们可以在任何地方用Aspect,但是Spring对这一规则做了限制,我们只能用在Spring管理的Bean的公共方法中。
切入点一般来说可以认为和连接点类似。表示我们实际声明的连接点。
3.1.2 Advice
Advice指的是我们想应用的方法(The functionality we want to apply),比如是Before, After等。
3.1.3 Aspect
Aspect是Point Cut和Advice的结合,也就是我们什么时候做、做什么。
3.1.4 Weaving
将Aspect应用到系统的过程(The process of applying an aspect to our system)
好了,在将AOP应用到我们前面讲到的例子之前,我们先添加一些依赖:
1 | compile group: 'org.springframework', name: 'spring-aop', version: '4.3.2.RELEASE' |
spring-aop
底层是调用aspectj
,但是有时候我们会直接使用aspectj
因此这里还是直接添加一下依赖。
3.2 定义切入点和应用Advice
这一节我们对之前的例子应用AOP。我们对Game
做记录,记录下每个方法的调用,什么时候添加setHomeTeam
, setAwayTeam
等。
首先,我们需要在Bean配置里添加注解@EnableAspectJAutoProxy
。这个注解表示Spring使用AspectJ的注解代理。
1 | @Configuration |
第二部,我们新建一个aspects
包,并在包下面创建LoggingAspect
类:
1 | import org.aspectj.lang.annotation.Aspect; |
这里,我们创建了类,并用@Aspect
标示它是一个Aspect。一个Aspect由切入点和Advice组成,@Before
指定了切入点,也就是匹配所有lx.spring.core
包及其下面的包中的set
开头只有一个参数返回类型是void
类型的方法。callSetters()
方法是advice。
因为我们给Aspect加了@Component
,加之我们在配置时用了@ComponentScan
,所以现在我们什么都不用做,就会自动的调用这个方法了。是不是很神奇?
1 | Team royals = context.getBean("royals", Team.class); |
其实,我们的callSetters()
方法可以添加JoinPoint
参数,用来提供一些调用信息,这样大大提高了AOP的功能,比如:
1 | @Before("execution(void lx.spring.core..*.set*(*))") //指定Point Cut |
3.3 Advice的类型
Advice包含很多内容,请查看Spring文档的AspectJ部分。这里举一个例子:
1 | @Around("execution(String playGame())") |
这个是在执行前和执行后都会执行,其中ProceedingJoinPoint.proceed()
会调用对应的方法。