文章目录
1、概述
AOP(Aspect Oriented Programming),意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程中的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2、作用
AOP在Spring中提供声明式事务,同时允许用户自定义切面,下面是在AOP中会遇到的一些名词:
- 横切关注点:跨越应用程序多个模块的方法或功能,即与我们业务逻辑无关,但是我们需要关注的部分。如日志、安全、缓存、事务等……
- 切面:跨多个类的关注点的模块化。在 Spring AOP 中,Aspect即切面是通过使用常规类(基于模式的方法)或使用
@Aspect
注解注释的常规类来实现的。 - 通知:Aspect在特定连接点采取的行动,即切面必须要完成的工作,通知Advice是类中的一个方法。
- 目标:Target,被通知的对象
- 代理:Proxy,向目标对象应用通知之后创建的对象
- 切入点:PointCut, 切面通知执行的“地点”的定义,Advice 与切入点表达式相关联,并在与切入点匹配的任何连接点处运行。切入点表达式匹配的连接点的概念是 AOP 的核心,Spring 默认使用 AspectJ 切入点表达式语言。
- 连接点:JointPoint,程序执行过程中的一个点,即与切入点匹配的执行点。在 Spring AOP 中,一个连接点总是代表一个方法执行。
在Spring AOP中包含以下类型的Advice
3、AOP的实现
在使用AOP织入之前,我们需要导入一个依赖包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
3.1、通过Spring API实现
- UserService业务接口
public interface UserService {
/** 模拟业务中的增 **/
public void add();
/** 模拟业务中的删 **/
public void delete();
/** 模拟业务中的改 **/
public void update();
/** 模拟业务中的查 **/
public void query();
}
- UserSeriveceImpl实现类
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("add业务");
}
@Override
public void delete() {
System.out.println("delete业务");
}
@Override
public void update() {
System.out.println("update业务");
}
@Override
public void query() {
System.out.println("query业务");
}
}
- 增强类编写
public class Log implements MethodBeforeAdvice {
/**
* @description 方法前增强
* @author xBaozi
* @date 20:37 2022/3/1
* @param method 要执行的目标对象的方法
* @param objects 被调用方法的参数
* @param o 目标对象
**/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
- 编写applicationContext.xml
- 导入AOP对应的约束,即第3、7、8行
- 分别注册真实角色即实现类和增强类的bean对象
- 对AOP进行配置,标明切入点和需要执行的增强类
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.xbaozi.service.UserServiceImpl"/>
<bean id="lod" class="com.xbaozi.advice.Log"/>
<bean id="afterLog" class="com.xbaozi.advice.AfterLog"/>
<!--aop的配置-->
<aop:config>
<!--切入点,expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointCut" expression="execution(* com.xbaozi.service.UserServiceImpl.*(..))"/>
<!--执行环绕,advice-ref为需要执行方法的对象,pointcut-ref切入点-->
<aop:advisor advice-ref="lod" pointcut-ref="pointCut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
</aop:config>
</beans>
- 测试
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.delete();
}
- 执行结果
3.2、通过自定义类实现
- 业务层和实体类依旧使用上面的UserServerImpl
- 编写自定义的切入类
public class DiyPointcut {
public void before() {
System.out.println("方法执行前");
}
public void after() {
System.out.println("方法执行后");
}
}
- 编写applicationContext.xml
- 导入AOP对应的约束,即第3、7、8行
- 分别注册真实角色即实现类和自定义切入类的bean对象
- 对AOP进行配置,标明切入点和需要执行的方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.xbaozi.service.UserServiceImpl"/>
<bean id="diy" class="com.xbaozi.config.DiyPointcut"/>
<!--AOP配置-->
<aop:config>
<!--指明切面类-->
<aop:aspect ref="diy">
<!--指明切入点-->
<aop:pointcut id="diyPointcut" expression="execution(* com.xbaozi.service.UserServiceImpl.*(..))"/>
<!--指明执行自定义类中的方法-->
<aop:before pointcut-ref="diyPointcut" method="before"/>
<aop:after pointcut-ref="diyPointcut" method="after"/>
</aop:aspect>
</aop:config>
</beans>
- 测试类和上述一致
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.delete();
}
- 运行结果
3.3、通过注解实现
- 编写一个注解实现的增强类
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.xbaozi.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("使用注解--方法执行前");
}
@After("execution(* com.xbaozi.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("使用注解--方法执行后");
}
@Around("execution(* com.xbaozi.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:" + jp.getSignature());
// 执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
- 编写applicationContext.xml
- 导入AOP对应的约束,即第3、7、8行
- 分别注册真实角色即实现类和注解实现的增强类的bean对象
- 增加支持注解的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.xbaozi.service.UserServiceImpl"/>
<bean id="annotationPointcut" class="com.xbaozi.config.AnnotationPointcut"/>
<!--增加支持注解的配置-->
<aop:aspectj-autoproxy/>
</beans>
- 测试类和上述的都相同
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.delete();
}
- 运行结果