
目录
- AOP(Aspect Oriented Programming):面向切面编程。
- StringAOP:AOP是一种思想,SpringAOP是一个框架,提供了一种对AOP思想的实现。
- 作用:定义一个统一的切面代码,基于AOP,可以用于多处代码(方法)横切一刀,进行统一的处理。
- 使用场景:
【1】统一日志记录;
【2】统一方法执行时间统计;
【3】统一的返回格式设置;
【4】统一的异常处理;
【5】事务的开发和提交等。
AOP的组成(StringAOP只能对方法进行增强):
- 连接点:AOP本身包含这个该奶奶,表示要增强的代码范围。SpringAOP没有体现(只能对方法进行增强)。
- 切点:提供规则来匹配连接点中要增强的代码。(切点相当于保存了众多连接点的一个集合)
- 切面:有切点和通知组成,相当于AOp实现的某个功能的集合。
- 通知:定义什么时间执行统一的代码。
通知包含:
- 前置通知使用@Before:通知方法会在目标方法调用之前执行;
- 后置通知使用@After:通知方法会在目标方法返回或者抛出异常后调用;
- 返回之后通知使用@AfterReturning:通知方法会在目标方法返回后调用;
- 抛异常后通知使用@AfterThrowing:通知方法会在目标方法抛出异常后调用;
- 环绕通知使用@Around:通知包裹被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。
使用SpringAOP来实现AOP功能。SpringAOP实现的步骤如下:
- 添加SpringAOP框架支持;
- 定义切面和切点;
- 定义通知。
在pom.xml文件中添加如下配置:
-
-
-
org.springframework.boot -
spring-boot-starter-aop -
定义切面(@Aspect):

定义切点(@PointCut):
pointcut方法为一个空方法,不需要方法体,此方法名就是起到一个“标识”的作用,标识通知方法具体指的是哪个切点(切点可能有多个)。
- //定义切点:匹配方法的规则是,org.example.service包下任意类,以select开头的方法
- @Pointcut("execution(* org.example.service.*.select*(..))")
- public void pointcut(){}
切点函数(exection())说明:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
//修饰符和异常可以省略
AspectJ支持的三种通配符:
- (*):匹配任意一个字符(包、类、方法、方法参数);
- (*..):匹配任意字符,可以匹配多个元素,表示类时,必须和*联合使用;
- (+):表示按照类型匹配指定类的所有类,必须跟在类名后面,如com.cad.Car+,表示继承该类的所有子类包括本身。
表达式示例:

指定切点(要匹配的方法),方法增强时间,增强的逻辑。
- //定义通知:定义增强的时间及逻辑,并指定切点
- //前置通知
- @Before("pointcut()")
- public void before(){
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");
- System.out.println("当前时间为:"+df.format(new Date()));
- }
SpringAOP时基于动态代理(一种设计模式)实现的,Spring对AOP的支持仅限于方法级别的拦截(基于方法增加)。
实现方式:
- JDK:基于接口的方式来实现=>目标类必须实现某个接口;
- CGLIB:基于继承的方式来实现=>目标类不能被final修饰。
增强的方式,基于目标类生成一个代理类,实际使用的是代理类。
织入是把切面应用到目标对象并创建新的代理对象的过程,切面指定的连接点被织入到目标对象中,在目标对象的生命周期中有以下三个点(AOP的织入)可以进行织入(StringAOP只能在运行期进行织入):
- 编译期:切面在目标类编译时被织入。(AspectJ的织入编译器就是以这种方式进行织入);
- 类加载器:切面在目标类加载到JVM时被织入;(需要特殊的类加载器)
- 运行期:切面在应用运行的某一时刻被织入。在织入切面时,AOP容器会为目标对象动态创建一个代理对象。
SpringAOP动态代理的两种实现方式:JDK和CGLIB。
- CGLIB时Java中的动态代理框架,主要作用是根据目标类和方法,动态生成代理类;
- Java中的动态代理框架,几乎都是依赖字节码框架实现;
- 字节码框架是直接操作class字节码的框架。可以加载已有的class字节码文件信息,修改部分信息,或动态生成一个class。
JDK和CGLIB区别:
- JDK是基于接口的方式来实现。之后通过InvocationHander及Proxy,在运行时动态的在内存中生成代理类对象,该代理对象是通过实现同样的接口实现,该代理类是在运行期是,动态的织入统一的业务逻辑字节码来完成;
- CGLIB是基于继承的方式实现(继承被代理类),在运行时动态的生成代理类对象。