1. AOP是什么?
AOP(Aspect Orient Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善。它以通过预编译方式和运行期动态代理方式,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。
2. AOP 应用场景分析?
实际项目中通常会将系统分为两大部分,一部分是核心业务,一部分是非核业务。在编程实现时我们首先要完成的是核心业务的实现,非核心业务一般是通过特定方式切入到系统中,这种特定方式一般就是借助AOP进行实现。AOP就是要基于OCP(开闭原则),在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以"控制"对象的执行。例如AOP应用于项目中的日志处理,事务处理,权限处理,缓存处理等等。
3. Spring AOP 应用原理分析
Spring AOP底层基于代理机制(动态方式)实现功能扩展:
1) 假如目标对象(被代理对象)实现接口,则底层可以采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口)。
2) 假如目标对象(被代理对象)没有实现接口,则底层可以采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型)。
说明:Spring boot2.x 中AOP现在默认使用的CGLIB代理,假如需要使用JDK动态代理可以在配置文件(applicatiion.properties)中进行如下配置:
spring.aop.proxy-target-class=false
4. Spring 中AOP 相关术语分析
- 切面(aspect): 横切面对象,一般为一个具体类对象(可以借助@Aspect声明)。
- 通知(Advice):在切面的某个特定连接点上执行的动作(扩展功能),例如 around,before,after等。
- 连接点(joinpoint):程序执行过程中某个特定的点,一般指向被拦截到的目标方法。
- 切入点(pointcut):对多个连接点(Joinpoint)一种定义,一般可以理解为多个连接点的集合。
5. 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
6. redis使用AOP案例
@Aspect //标识我是一个切面
@Component //交给Spring容器管理
public class CacheAOP {
@Autowired
private JedisCluster jedis; //完成集群对象的注入
//private ShardedJedis jedis; //完成分片对象的注入
//private Jedis jedis; //单台redis
/**
* 注意事项: 当有多个参数时,joinPoint必须位于第一位.
* 需求:
* 1.准备key= 注解的前缀 + 用户的参数
* 2.从redis中获取数据
* 有: 从缓存中获取数据之后,直接返回值
* 没有: 查询数据库之后再次保存到缓存中即可.
*
* 方法:
* 动态获取注解的类型,看上去是注解的名称,但是实质是注解的类型. 只要切入点表达式满足条件
* 则会传递注解对象类型.
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) throws Throwable {
Object result = null; //定义返回值对象
String preKey = cacheFind.preKey();
String key = preKey + "::" + Arrays.toString(joinPoint.getArgs());
//1.校验redis中是否有数据
if(jedis.exists(key)){
//如果数据存在,需要从redis中获取json数据,之后直接返回
String json = jedis.get(key);
//1.获取方法对象, 2.获取方法的返回值类型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//2.获取返回值类型
Class returnType = methodSignature.getReturnType();
result = ObjectMapperUtil.toObject(json,returnType);
System.out.println("AOP查询redis缓存!!!");
}else{
//代表没有数据,需要查询数据库
result = joinPoint.proceed();
//将数据转化为JSON
String json = ObjectMapperUtil.toJSON(result);
if(cacheFind.seconds() > 0){
jedis.setex(key, cacheFind.seconds(), json);
}else{
jedis.set(key,json);
}
System.out.println("AOP查询数据库!!!");
}
return result;
}
}