前置简介
上一节:https://juejin.im/post/6865916387471310856
上一节说了JDK动态代理和基于CGLIB的动态代理,下面说一下动态代理在Spring中的使用,
我们将在下面的demo里使用 spring boot + aop + 注解 实现一个具备缓存功能的接口。
首先在项目中引用spring-boot-starter-aop
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
创建一个Biz
@Service
public class DataBiz {
public List<String> getList() {
return Arrays.asList("1","2","3");
}
}
创建一个Controller
@RestController
public class DataController {
@Autowired
private DataBiz dataBiz;
@GetMapping("/hello")
public List<String> getList() {
return dataBiz.getList();
}
}
首先我们根据上面的两个类可以看到,我们通过访问一个http://ip:端口/hello的地址,
获取一个list返回结果,
下面我们有一个需求,就是只有第一次访问这个接口的时候,真正调用了biz的方法获取返回值,
其余的时候,都是通过缓存中拿,
这个需求我们用spring aop来实现以下,看下面创建的类。
创建Cache注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
}
这个类用于配合切面使用,告诉切面需要拦截哪些方法,就是一个标记。
创建切面类
// 标记这是一个切面类
@Aspect
// 告诉Spring这个类需要进行bean管理
@Configuration
public class CacheAspect {
Map<String,Object> cache = new HashMap<>();
// 环绕通知,并且拦截带有Cache的方法,在方法的前后进行切面处理
@Around("@annotation(Cache)")
public Object cache(ProceedingJoinPoint point) throws Throwable {
// 获取方法信息
MethodSignature signature = (MethodSignature) point.getSignature();
// 获取方法名称
String methodName = signature.getName();
// 从缓存中获取方法的返回值
Object cacheValue = cache.get(methodName);
// 如果缓存中有 就返回缓存值
if(cacheValue != null) {
System.out.println("从缓存中返回");
return cacheValue;
} else {
// 否则调用真实的方法,获取返回值缓存,并返回
System.out.println("从方法中返回");
cacheValue = point.proceed();
cache.put(methodName,cacheValue);
return cacheValue;
}
}
}
最后,在biz类的方法里加上我们定义的Cache注解。
@Service
public class DataBiz {
@Cache
public List<String> getList() {
return Arrays.asList("1","2","3");
}
}
完成上面的步骤我们基于一个Spring Aop实现的缓存功能就实现了,看下面效果。
上面我们用到的AOP切面是 @Around
环绕通知,
还有 @After
(方法执行后) @Before
(方法执行前) 等使用方式,
可以查看Spring Aop官方文档,做更多的了解https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop
最后要注意的是,Spring的Aop默认是基于JDK的动态代理的,但是Spring Boot 引入Aop的时候,
自动将配置改成了基于Cglib的代理,这个请多注意。
本篇代码示例:https://github.com/qiaomengnan16/DecoratorPatternDemo