关于Spring AOP的理解
AOP为Aspect Oriented Programming的缩写 :面向切面编程, AOP是OOP的延续 AOP并不是一种技术,只是一种思想,即面向切面编程的思想
在开发中日志的使用时很频繁的,下面就来用AOP来解决一下开发中的日志输出的问题
@Service
public class TestService {
public int sum(int a ,int b ){
System.out.println("参数为:"+a+"+"+b);
int sum = a+b;
System.out.println("结果为:"+sum);
return sum;
}
}
@Autowired
private TestService testService;
@Test
void contextLoads() {
testService.sum(1,2);
}
参数为:1+2
结果为:3
在不使用aop的情况下,我们打印日志要这样写,这样写的话就是业务代码跟日志输出都写在了一起,使得代码冗余,而且在后面假如说,不需要将参数输出到日志中了,这样需要一个类一个类的修改代码,工作量时很大的
AOP就很方便简单的解决了这个问题
image-20200815173638193.pngAOP的理解
这是之前的日志输出方法
image-20200815173809830.png这个时使用AOP的日志输出方法
其实AOP,面向切面很好理解,就是在一个类上横切一刀,将我们需要的代码切入,并且不影响之前代码的执行,实现了解耦
image-20200815181439994.pngAOP的优点
1、面向切面编程使得每个关注点都集中于一个地方而不是分散在多处代码中,便于后期的统一维护管理。
2、服务模块更简洁,它们只包含主要关注点,而次要关注点的代码被转移到切面中了。
3、对原方法进行方法增强,且不影响原方法的正常使用。
4、使用简单可插拔的配置,在实际逻辑执行之前、之后或周围动态添加横切关注点。
AOP的术语
名称 | 描述 |
---|---|
切面(Aspect) | 切面是通知和切点的结合 |
通知(Advice) | 通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题 |
切点(Pointcut) | 切点定义了在何处工作,也就是真正被切入的地方,也就是在哪个方法应用通知 |
连接点(Join point) | 连接点是在应用执行过程中能够插入切面的一个点 |
引入(Introduction) | 引入让一个切面可以声明被通知的对象实现了任何他们没有真正实现的额外接口,而且为这些对象提供接口的实现 |
织入(Weaving) | 织入是把切面应用到目标对象并创建新的代理对象的过程 |
其中在Spring中有5中通知类型
名称 | 描述 |
---|---|
前置通知(Before) | 在目标方法被调用之前调用 |
后置通知(After) | 在目标方法完成之后调用 |
返回通知(After-returning) | 在目标方法成功执行之后调用 |
异常通知(After-throwing) | 在目标方法抛出异常后调用 |
环绕通知(Around) | 通知包裹了被通知的方法,可同时定义前置通知和后置通知 |
SpringBoot 实现AOP
-
新建一个SpringBoot项目
-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
-
AOP的实现需要进行配置,在Spring 中使用的时xm的方式进行配置,但是在SpringBoot中取消了xml,改为使用了配置类进行配置
package com.mango.Aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @Author: * @Date: * @Component 被Spring管理 * @Aspect 声明他是一个aop的类 */ @Component @Aspect public class TestAspect { /** * @Pointcut("execution(* com.mango.service.*.*(..))") * execution 括号中的是一个表达式,表面在com.mango.service 这个包下的所有类所有方法所有返回值,所有参数 * 申明切入点 * execution 关键字 * * com.mango.service. *. * (..) ) * 所有的返回值 包名 所有类 所有方法 所有的参数 */ @Pointcut("execution(* com.mango.service.*.*(..))") public void pointcut(){} /** * @Before("pointcut()") 前置通知,在切入点之前 * @param joinPoint 可以通过他来获取方法以及参数 */ @Before("pointcut()") public void before(JoinPoint joinPoint){ Object [] args = joinPoint.getArgs(); for (Object arg : args) { System.out.println("参数为:"+arg); } } /** * @param joinPoint * @param returnValue * @AfterReturning(value = "pointcut()",returning = "returnValue") * returning 获取返回值 */ @AfterReturning(value = "pointcut()",returning = "returnValue") public void returning(JoinPoint joinPoint,Object returnValue){ System.out.println("结果为:"+returnValue); } }
@Service
public class TestService {
public int sum(int a ,int b ){
int sum = a+b;
return sum;
}
}
@SpringBootTest
class SpringbootAopApplicationTests {
@Autowired
private TestService testService;
@Test
void contextLoads() {
testService.sum(1,2);
}
}
参数为:1
参数为:2
结果为:3
其他的After之类的就不再举例了,用法都是一样的
这样就是实现了AOP,是不是很简单,其实AOP的使用时很简单的,重要的是理解AOP的这种思想
AOP的运用的技术
SpringAOP使用了两种代理机制,一种是基于JDK的动态代理,另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。
切面植入的方法:
编译期织
类装载期织入
动态代理织入 在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面
AOP 有两种主要的框架,SpringAOP和AspectJ
在一般情况下使用SpringAOP就可以解决我们的问题,如果无法解决,Spring支持对AspectJ 的集成,可以使用AspectJ解决
网友评论