前言
之前的源码解析章节,本人讲解了Spring IOC 的核心部分的源码。如果你熟悉Spring AOP的使用的话,在了解Spring IOC的核心源码之后,学习Spring AOP 的源码,应该可以说是水到渠成,不会有什么困难。
但是直接开始讲Spring AOP的源码,本人又觉得有点突兀,所以便有了这一章。Spring AOP 的入门使用介绍:包括Spring AOP的一些概念性介绍和配置使用方法。
这里先贴一下思维导图。
AOP 是什么
AOP : 面向切面编程(Aspect Oriented Programming)
Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
最近在看李智慧的《大型网站技术架构》一书中,作者提到,开发低耦合系统是软件设计的终极目标之一。AOP这种面向切面编程的的方式就体现了这样的理念。将一些重复的、和业务主逻辑不相关的功能性代码(日志记录、安全管理等)通过切面模块化地抽离出来进行封装,实现关注点分离、模块解耦,使得整个系统更易于维护管理。
这样分而治之的设计,让我感觉到了一种美感。
AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。
AOP 的实现并不是因为 Java 提供了什么神奇的钩子,可以把方法的几个生命周期告诉我们,而是我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。
名词概念
前面提到过,Spring AOP 延用了 AspectJ 中的概念,使用了 AspectJ 提供的 jar 包中的注解。也就是Spring AOP里面的概念和术语,并不是Spring独有的,而是和AOP相关的。
概念可以草草看过,在看了之后的章节之后再回来看会对概念理解的更深。
术语 | 概念 |
---|---|
Aspect |
切面是Pointcut 和Advice 的集合,一般单独作为一个类。Pointcut 和Advice 共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能。 |
Joinpoint |
这表示你的应用程序中可以插入AOP方面的一点。也可以说,这是应用程序中使用Spring AOP框架采取操作的实际位置。 |
Advice |
这是在方法执行之前或之后采取的实际操作。 这是在Spring AOP框架的程序执行期间调用的实际代码片段。 |
Pointcut |
这是一组一个或多个切入点,在切点应该执行Advice 。 您可以使用表达式或模式指定切入点,后面示例会提到。 |
Introduction |
引用允许我们向现有的类添加新的方法或者属性 |
Weaving |
创建一个被增强对象的过程。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。 |
PS:在整理概念的时候有个疑问,为什么网上这么多中文文章把advice 翻译成“通知”呢???概念上说得通吗???我更愿意翻译成“增强”(并发中文网ifeve.com 也是翻译成增强)
还有一些注解,表示Advice的类型,或者说增强的时机,看过之后的示例之后会更加的清楚。
术语 | 概念 |
---|---|
Before |
在方法被调用之前执行增强 |
After |
在方法被调用之后执行增强 |
After-returning |
在方法成功执行之后执行增强 |
After-throwing |
在方法抛出指定异常后执行增强 |
Around |
在方法调用的前后执行自定义的增强行为(最灵活的方式) |
使用方式
Spring 2.0 之后,Spring AOP有了两种配置方式。
- schema-based:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间
<aop />
- @AspectJ 配置:Spring 2.0 以后提供的注解方式。这里虽然叫做 @AspectJ,但是这个和 AspectJ 其实没啥关系。
PS:个人比较钟情于@AspectJ 这种方式,使用下来是最方面的。也可能是因为我觉得XML方式配置的Spring Bean很不简洁、写起来不好看吧,所以有点排斥吧。23333~
本文主要针对注解方式讲解,并且给出对应的DEMO;之后的源码解析也会以注解的这种方式为范例讲解Spring AOP的源码(整个源码解析看完,会对其他方式触类旁通,因为原理都是一样的)
如果对其他配置方式感兴趣的同学可以google其他的学习资料。
来一条分割线,正式开始
1. 开启@AspectJ
注解配置方式
开启@AspectJ
的注解配置方式,有两种方式
-
在XML中配置:
<aop:aspectj-autoproxy/>
-
使用
@EnableAspectJAutoProxy
注解@Configuration @EnableAspectJAutoProxy public class Config { }
开启了上述配置之后,所有在容器中,被@AspectJ
注解的 bean 都会被 Spring 当做是 AOP 配置类,称为一个 Aspect。
NOTE:这里有个要注意的地方,@AspectJ 注解只能作用于Spring Bean 上面,所以你用 @Aspect 修饰的类要么是用 @Component注解修饰,要么是在 XML中配置过的。
比如下面的写法,
// 有效的AOP配置类
@Aspect
@Component
public class MyAspect {
//....
}
// 如果没有在XML配置过,那这个就是无效的AOP配置类
@Aspect
public class MyAspect {
//....
}
2. 配置 Pointcut (增强的切入点)
Pointcut 在大部分地方被翻译成切点,用于定义哪些方法需要被增强或者说需要被拦截。
在Spring 中,我们可以认为 Pointcut 是用来匹配Spring 容器中所有满足指定条件的bean的方法。
比如下面的写法,
// 指定的方法
@Pointcut("execution(* testExecution(..))")
public void anyTestMethod() {
}
下面完整列举一下 Pointcut 的匹配方式:
-
execution:匹配方法签名
这个最简单的方式就是上面的例子,
"execution(* testExecution(..))"
表示的是匹配名为testExecution
的方法,*
代表任意返回值,(..)
表示零个或多个任意参数。 -
**within:**指定所在类或所在包下面的方法(Spring AOP 独有)
// service 层 // ".." 代表包及其子包 @Pointcut("within(ric.study.demo.aop.svc..*)") public void inSvcLayer(