在这里多谈一些关于AOP 方面的知识,如果你对AOP 方面的知识比较熟悉,可以直接略过这个段落,往下看。
一、AOP概述
AOP(面向切面编程) 概念:这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
AOP 相关术语:
- Aspect(切面):指横切性的关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是对横切性关注点的抽象。是Pointcut和Advice的结合,切面可以由多个Poincut和Advice组成。
- Joinpoint(连接点):被拦截的点(也就是需要被拦截的类的方法)。在spring中,这些点指的只能是方法,因为Spring只支持方法类型的拦截,实际上Joinpoint还可以拦截field或类构造器。
- Pointcut(切点):对Jointpoint(连接点)进行拦截的定义,也就是在切面中定义的方法,并声明该方法拦截了Jointpoint(连接点)。
- Advice(通知):切入点拦截到Jointpoint(连接点)之后要做的事情。通知分为前置通知(@Before)、后置通知(@AfterReturning)、异常通知(@AfterThrowing)、最终通知(@After)和环绕通知(@Around)。
- Target(目标对象):代理的目标对象。
- Weave(织入):指将aspects应用到target对象并使proxy对象创建的过程称为织入。
五种基本通知类型注解:
- 前置通知(@Before):拦截目标方法,在目标方法执行之前开始执行。
- 后置通知(After):在目标方法执行之后开始执行。也可以获取目标方法的返回值。
- 返回通知(@AferRunning):在方法返回执行结果之后执行。
- 异常通知(@AfterThrowing):在目标方法抛出异常后,执行增强。
- 环绕通知(@Around):相当于整个代理模式过程,围绕方法执行。
二、在Spring Boot 中使用AOP
开发流程:
- 在pom.xml 中引入AOP 依赖。
- 写一个类,加上@Aspect 注解,封装横切关注点,配置对应的通知。
- 将这个类纳入到Spring 容器中。
过程实现:
在pom.xml 中添加AOP 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Person 类
package com.jas.aop;
import org.springframework.stereotype.Component;
@Component
public class Person {
public void sayHi(){
System.out.println("Hello");
}
}
Log 类
package com.jas.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/** 使用@Component 把这个类纳入到Spring 容器,@Aspect 注解表示这个类是一个切面类 */
@Component
@Aspect
public class Log {
/** 定义一个前置通知*/
/** 匹配com.jas.aop 包及其子包下的所有方法 */
@Before("execution(* com.jas.aop..*.*(..))")
public void log(){
System.out.println("... before ...");
}
}
测试类(入口类)
package com.jas.springboot;
import com.jas.aop.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication(scanBasePackages = "com.jas")
public class SpringbootApplication {
public static void main(String[] args) throws Exception{
ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
Person person = context.getBean(Person.class);
person.sayHi();
System.out.println(person.getClass());
}
}
启动入口类输出
三、Spring Boot AOP 两种动态代理方式
动态代理方式概述:
AOP 的源码中用到了两种动态代理来实现拦截切入功能:JDK 动态代理和CGLIB 动态代理。两种方式各有优劣。
JDK 动态代理是由java 内部的反射机制来实现的,CGLIB 动态代理底层则是借助asm 来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm 在生成类之后的相关执行过程中比较高效(可以通过将asm 生成的类进行缓存,这样解决asm 生成类过程低效问题)。
还有一点必须注意:JDK 动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,JDK 动态代理不能应用。由此可以看出,JDK 动态代理有一定的局限性,CGLIB 这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。
关于JDK 动态代理知识,可参考博文:JDK 动态代理。
但是从上面的输出来看使用的是基于CGLIB 的代理方式,因为JDK 的动态代理类必须是实现了接口的类。下面写一个接口类来测试一下。
动态代理方式演示:
在全局配置文件中配置代理方式,true 表示使用CGLIG,false 表示使用JDK 动态代理。
需要注意的是,当为false 时,如果代理类没有实现接口,则使用的也是基于CGLIB 的动态代理。
spring.aop.proxy-target-class=false
Animal 接口
package com.jas.aop;
public interface Animal {
void yell();
}
Dog 类
package com.jas.aop;
import org.springframework.stereotype.Component;
@Component
public class Dog implements Animal{
@Override
public void yell() {
System.out.println("wang wang ...");
}
}
在入口类加上对应的代码
System.out.println(context.getBean(Animal.class).getClass());
输出
参考资料
http://blog.youkuaiyun.com/heyutao007/article/details/49738887

本文详细介绍了AOP的概念及核心术语,如切面、连接点等,并通过实例展示了如何在SpringBoot中使用AOP,包括配置依赖、定义切面类及通知等步骤。
745

被折叠的 条评论
为什么被折叠?



