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 }
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 }
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 }
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 }
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 }
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 }
完整的代码参考
参考: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共同讨论

浙公网安备 33010602011771号