前言
最近又开始看源码了,虽然Spring AOP早就看过了,但是有的时候还是记得不熟,虽然Spring AOP已经被人分析了千万遍了,但仍然无法逃出我的魔爪...
Spring AOP
什么是AOP?
我们通常叫它面向切面编程。但是似乎这种说法太官方了,不太容易理解。
我们可以这样来解释它,在我们开发的过程中,总有一些与我们主业务逻辑关系不大的代码会散落在代码中的各个地方,难以维护。
AOP就是把这些横切性问题与主业务分离,统一进行管理。从而起到解耦的目的
Spring AOP基本使用
AOP的增强类型
AOP的增强类型其实就是我们配置xml文件时的 advice,不知道为什么叫AOP增强(大多数人认可的方式)
我个人理解为 AOP建议我们使用的地方,分为以下5种
前置增强 (org.springframework.aop.BeforeAdvice) 表示在目标方法执行前来实施增强(用在目标方法执行之前)
后置增强 (org.springframework.aop.AfterReturningAdvice) 表示在目标方法执行后来实施增强(用在目标方法执行之后)
环绕增强 (org.aopalliance.intercept.MethodInterceptor) 表示在目标方法执行前后同时实施增强(用在目标方法执行之中)
异常抛出增强 (org.springframework.aop.ThrowsAdvice) 表示在目标方法抛出异常后来实施增强(用在目标方法抛出异常)
引介增强 (org.springframework.aop.introductioninterceptor) 表示在目标类中添加一些新的方法和属性
AOP的用途
Spring AOP的用途有很多,最常用的应该就是记录 日志了。上面我们说到了Spring aop会把横切性问题与主业务分离,统一进行管理。
那么这么横切性问题即会出先在业务之前,又会出现在业务之后,甚至存在于整个业务之中。所以,它有什么用,我们大可发挥自己的想象空间。如:做权限管理
在用户执行主业务(登录)之前,先做认证授权操作。做缓存,在执行业务之前(查询数据库),先去nosql里面查。还有很多用法,只不过
看我们怎么用罢了。
使用范例
这里,我们就简单的演示一下aop的作用,就记录一下目标方法执行时间
1.引入AOP的dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.创建UserService
package com.example.originaltest.service; import org.springframework.stereotype.Service; /** * @Auther: Anthony * @Date: 2019/5/6 18:21 * @Description: */ public interface UserService { void login(); }
3.创建具体实现
package com.example.originaltest.service; import org.springframework.stereotype.Service; /** * @Auther: Anthony * @Date: 2019/5/6 18:21 * @Description: */ @Service("userService") public class UserServiceImpl{ public void login() { System.out.println("UserServiceImpl login"); } }
4.创建AOP切面
package com.example.originaltest.springaop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class UserAspect { @Pointcut("execution(* com.example.originaltest.service.*.*(..))") private void pointcut(){ } @Around("com.example.originaltest.springaop.UserAspect.pointcut()") public Object around(ProceedingJoinPoint joinPoint){ long current = System.currentTimeMillis(); Object process = null; try{ process = joinPoint.proceed(); }catch (Throwable throwable) { throwable.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("消耗时间:"+(end-current)); return process; } @Before("com.example.originaltest.springaop.UserAspect.pointcut()") public void before(){ System.out.println("before"); } @After("com.example.originaltest.springaop.UserAspect.pointcut()") public void after(){ System.out.println("After"); } }
这里有几个概念,需要提一下:
1.@Aspect:切面 其实就是前面说的与主业务无关的部分,这些部分的整体就是一个切面。也有这样理解,这些与主业务无关的代码被剥离了出来,自成体系,形成切面
2.@Pointcut:切入点 可以理解为从哪些业务里被剥离出来,既然是从那些业务里被剥离出来的,自然也作用于那些业务。可以认为是作用的地方
3.@Around,@Before,@After: 这些就是前面说的增强,也即作用在目标方法的什么位置。这里还有几个增强没有展示。
5.创建启动类
package com.example.originaltest; import com.example.originaltest.service.UserService; import com.example.originaltest.service.UserServiceImpl; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * @Auther: Anthony * @Date: 2019/5/6 18:22 * @Description: */ @EnableAspectJAutoProxy @ComponentScan("com.example.originaltest.*") public class SpringAnnotationApplication { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringAnnotationApplication.class); UserService userService = (UserService) annotationConfigApplicationContext.getBean("userService"); // UserServiceImpl userService = (UserServiceImpl) annotationConfigApplicationContext.getBean("userService"); userService.login(); } }
@EnableAspectJAutoProxy 这里是自动代理注解,可以理解为开启AOP功能,这里注释了一段代码,先埋个伏笔。
6.执行结果
AOP的几个增强都发挥了作用。
源码分析
1.IOC容器的初始化,这在之前IOC那篇文章里已经提到过.