spring aop 学习
1.匹配包、类型
//匹配ProductService类里头的所有方法
@pointcut("within(com.imooc.service.ProductService)")
public void matchType(){}
//匹配com.imooc包及子包下所有类的方法
@poincut("within(com.imooc..*)")
public void matchType(){}
2.匹配对象
/*
* public class DemoDao implements IDao{}
*/
//匹配AOP对象的目标对象为指定类型的方法,即DemoDao的aop代理对象的方法
@pointcut("this(com.imooc.DemoDao)")
public void thisDemo(){}
//匹配实现IDao接口的目标对象(而不是aop代理后的对象)的方法,这里即DemoDao的方法
@pointcut("target(com.imooc.IDao)")
public void targetDemo(){}
//匹配所有以Service结尾的bean里头的方法
@pointcut("bean(*Service)")
public void beanDemo(){}
3.参数匹配
//匹配任何以find开头而且只有一个Long参数的方法
@pointcut("execution(* *..find*(Long))")
public void argsDemo1(){}
//匹配任何只有一个Long参数的方法
@pointcut("args(Long)")
public void argsDemo2(){}
//匹配任何以find开头的而且第一个参数为Long型的方法
@pointcut("execution(* *.find*(Long,..))")
public void argsDemo3(){}
//匹配第一个参数为Long型的方法
@pointcut("args(Long,..)")
public void argsDemo4(){}
@pointcut("args(Long,..) && within(com.imooc.service.*)")
public void argsDemo4(){}
4.匹配注解
//匹配方法标注有AdminOnly的注解的方法
@pointcut("@annotation(com.imooc.demo.security.AdminOnly)")
public void annoDemo(){}
//匹配标注有Beat的类的底下的方法,要求的annotation的RetentionPolicy级别为Class
@pointcut("within(com.google.common.annotations.Beat)")
public void annoWithinDemo(){}
//匹配注有Repository的类底下的方法,要求的annotation的RetentionPolicy级别为RUNTIME
@pointcut("@target(org.springframework.stereotype.Repository)")
public void annoTargetDemo(){}
//匹配传入的参数类标注有Repository注解的方法
@poincut("args(org.springframework.stereotype.Repository)")
public void annoArgsDemo(){}
5种Advice注解
-
@Before,前置通知
-
@After(finally),后置通知,方法执行完之后
-
@AfterReturning,返回通知,成功执行之后
-
@AfterThrowing,异常通知,抛出异常之后
-
@Around,环绕通知
注意事项:
1、不宜把重要的业务逻辑放到aop中处理
2、无法拦截static、final方法和private方法
3、spring aop 是无法拦截内部调用的。
例如:下面这段代码在第二次调用getMenuList是无法从缓存中获取,因为此时的this不是经过aop代理的bean。
//下面这段代码在第二次调用getMenuList是无法从缓存中获取
@Component
public class MenuService {
@Cacheable(cacheNames = {"menu"})
public List<String> getMenuList(){
System.out.println("");
System.out.println("mock:get from db");
return Arrays.asList("article","comment","admin");
}
public List<String> getRecommends(){
return this.getMenuList();
}
}
//可以将代码改为从代理Bean对象调用
//1.获取从spring代理的bean
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext ctx;
public static ApplicationContext getContext() {
return ctx;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
}
2.//使用代理对象解决内部调用
@Component
public class MenuService {
@Cacheable(cacheNames = {"menu"})
public List<String> getMenuList(){
System.out.println("");
System.out.println("mock:get from db");
return Arrays.asList("article","comment","admin");
}
public List<String> getRecommends(){
MenuService proxy = ApplicationContextHolder.getContext().getBean(MenuService.class);
return proxy.getMenuList();
}
}