spring-aop详解

最近学习了spring-aop,在学习spring-aop之前建议先学习一下动态代理,一个是jdk动态代理,一个cglib动态代理,其中jdk动态代理是基于接口的,cglib基于类的

spring动态代理和cglib动态代理可以参考:https://juejin.im/post/5b90e648f265da0aea695672

aop常用的场景:权限管理、事务管理等,日志管理用的应该很少

jdk动态代理和cglib动态代理都是在编译时织入

aop相关概念

pointcut:切点 连接点的集合

joinpoint:连接点 目标对象中的方法

Weaving:把代理逻辑加入到目标对象上的过程

advice:增强

通知类型

Before:前置增强

After:后置增强

AfterThrowing:抛出错误的时候增强,try catch则无效

After(finally)

Around:环绕增强

 各种连接点的粒度

execution:作用到方法级别上

如:execution(public * *(..))作用在任意类的任意方法上

within:作用到类级别上

within(com.xyz.someapp.trading..*)
作用在包
com.xyz.someapp.trading的任意类上,如果表达式包含方法则不生效
execution和within的区别就是execution可以作用到方法级别上,within只能作用在类级别上(很少用),我们通常也是用execution

args:作用于匹配的参数上
args(java.io.Serializable)   
args(Integer, ..) 作用于第一个参数是Integer的类型的方法
annotation:基于注解 
@annotation(com.share.annotation.MonitorAnnotation)
作用于注解MonitorAnnotation(自定义),其中注解只能是方法级别,不能是类级别
this:作用于代理对象
this(com.xyz.service.AccountService)
如果代理对象是AccountService则this通知有效,否则无效
target:作用于目标对象
target(com.xyz.service.AccountService)
如果目标对象是AccountService则target通知有效,否则无效

spring-aop基于注解示例

在类上加上@Aspectj,@Component(被spring管理)

主类

 1 public class Aop {
 2     public static void main(String[] args) {
 3         AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfig.class);
 4         UserDao userDao = ctx.getBean(UserDao.class);
 5         userDao.queryAll();
 6         System.out.println("===args===");
 7         CityMapper cityMapper = ctx.getBean(CityMapper.class);
 8         cityMapper.getById(1);
 9 
10     }
11 }
View Code

execution

 1 @Aspect
 2 @Component
 3 public class MyAspect {
 4 
 5     /**
 6      * 设置切点位置
 7      */
 8     @Pointcut("execution(public * com.share.dao.*.*(..))")
 9     public void anyMethod() {
10         System.out.println("all method");
11     }
12 
13     @Pointcut("within(com.share.dao.*.*)")
14     public void withMethod() {
15         System.out.println("aop within ....");
16     }
17 
18     /**
19      * 前置通知
20      */
21     @Before("com.share.aspect.MyAspect.anyMethod()")
22     public void before() {
23         System.out.println("before...");
24     }
25 
26     /**
27      * 后置通知
28      */
29     @After("com.share.aspect.MyAspect.anyMethod()")
30     public void after() {
31         System.out.println("after ....");
32     }
33 
34     @Around("com.share.aspect.MyAspect.anyMethod()")
35     public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
36         System.out.println("start...");
37         Object proceed = joinPoint.proceed();
38         System.out.println("end..");
39         return proceed;
40     }
41 
42     @Before("withMethod()")
43     public void withinBefore() {
44         System.out.println("within before ");
45     }
46 }
View Code

within

 1 @Aspect
 2 @Component
 3 public class WithinAspect {
 4 
 5     /**
 6      * 设置切点位置
 7      * 如果表达式是within(com.share.dao.*.*则不会起作用,表名了within的作用范围是类级别
 8      */
 9     @Pointcut("within(com.share.dao.*)")
10     public void withMethod() {
11         System.out.println("aop within ....");
12     }
13 
14     @Before("withMethod()")
15     public void withinBefore() {
16         System.out.println("within before ");
17     }
18 }
View Code

args

 1 @Aspect
 2 @Component
 3 public class ArgsAspect {
 4 
 5     @Pointcut("args(Integer, ..))")
 6     public void args() {
 7 
 8     }
 9 
10     @Before("com.share.aspect.ArgsAspect.args())")
11     public void argsBefore() {
12         System.out.println("args before...");
13     }
14 
15     @Before("@args(com.share.annotation.MonitorAnnotation)")
16     public void argsAnnotationBefore() {
17         System.out.println("args MonitorAnnotation before...");
18     }
19 }
View Code

annotation

 1 @Aspect
 2 @Component
 3 public class AnnotationAspect {
 4 
 5     @Pointcut("@annotation(com.share.annotation.MonitorAnnotation)")
 6     public void annotationMethod() {
 7         System.out.println("hhh");
 8     }
 9 
10     @Before("annotationMethod()")
11     public void annotation() {
12         System.out.println("before annotation ");
13     }
14 }
View Code

this target

 1 @Aspect
 2 @Component
 3 public class ThisAspectj {
 4 
 5     @Pointcut("this(com.share.dao.UserDaoImpl)")
 6     public void pointCutThis() {
 7 
 8     }
 9 
10     @Pointcut("target(com.share.dao.UserDaoImpl)")
11     public void pointCutTarget() {
12 
13     }
14 
15     /**
16      * @EnableAspectJAutoProxy(proxyTargetClass = true)
17      * 默认false false表示作用在代理类上,使用jdk动态代理 true表示作用目标类 使用的cglib代理 cglib代理的父类
18      * @param joinPoint
19      */
20     @Before("pointCutThis()")
21     public void beforeThis(JoinPoint joinPoint) {
22         Object[] args = joinPoint.getArgs();
23         Arrays.stream(args).forEach(System.out::print);
24         System.out.println("this ....");
25     }
26 
27     @Before("pointCutTarget()")
28     public void beforeTarget(JoinPoint joinPoint) {
29         Object[] args = joinPoint.getArgs();
30         Arrays.stream(args).forEach(System.out::print);
31         System.out.println("target ....");
32     }
33 
34 }
View Code

完整的代码参考 

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop

 代码验证说明:

我这边使用的全部是注解,所以大家验证this和target是要注意将false改成true,默认false

@EnableAspectJAutoProxy(proxyTargetClass = false)

代码地址:https://gitee.com/code_fun/example/tree/master/spring_aop

 其中主类中的下面代码是加载spring配置,其中UserDao是代理类,jdk动态代理中代理类继承了Proxy和UserDao所以proxyTargetClass为false试this无法作用UserDaoImpl,target能作用于目标类UserDaoImpl,proxyTargetClass为true时,cglib为UserDaoImpl继承父类UserDao则能作用到

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfig.class);
UserDao userDao = ctx.getBean(UserDao.class);
其他的没一个个去测试,如有错误欢迎留言或者加入群513650703共同讨论
posted @ 2018-09-23 22:20  学无终  阅读(102)  评论(0)    收藏  举报