前言:
小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。 这个Spring基础学习系列是用来记录我学习Spring框架基础知识的全过程 (这个系列是参照B站狂神的Spring5最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!) 之后我将会以一天一更的速度更新这个系列,还没有学习Spring5框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。 最后,希望能够和大家一同进步吧!加油吧!少年们! 废话不多说,让我们开始今天的学习内容吧,今天我们来到了Spring基础学习的第十站:AOP面向切面编程!
11.AOP 面向切面编程
11.1 AOP概述
11.1.1 什么是AOP?
- AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
- AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
11.1.2 AOP的优点
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务人员专心于业务逻辑的处理
- 使业务逻辑各部分之间的耦合度降低,提高程序的可重用性
- 提高系统的可维护性,同时提高了开发的效率
AOP面向切面编程结构图:
11.2 AOP在Spring中的作用
11.2.1 AOP相关概念
提供声明式事务:即允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能 (即与业务逻辑无关的,但是需要关注的部分),这就是横切关注点 (如日志管理,权限控制,事务处理、异常处理等)
- 切面 (Aspect):横切关注点被模块化的特殊对象 (也就是切入点和通知的结合),即它是一个类 (例如日志类 Log)
- 通知 (Advice):切面必须要完成的工作 (即对切入点增强的内容),它是类中的一个方法 (日志类Log中的方法,例如前置、后置和环绕通知等)
- 切入点 (PointCut):是指要对哪些JointPoint进行拦截,即被拦截的连接点 (可以理解为对切面通知执行的"地点"的定义)
- 连接点 (JointPoint):是指那些被拦截的点,在Spring中,可以使用动态代理拦截目标类的方法 (即与切入点匹配的执行点)
- 目标 (Target) :是指代理的目标对象 (也就是被通知的对象)
- 代理(Proxy):是指生成的代理对象 (即向目标对象应用通知之后创建的对象)
- 织入 (Weaving):是指把增强代码应用到目标上,生成代理对象的过程
11.2.2 AOP实现结构图
11.2.3 SpringAOP中的Advice
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5中类型的Advice
通知类型 | 作用 | 实现接口 | 应用 |
---|
前置通知 | 在目标方法执行前实施增强, | org.springframework.aop.MethodBeforeAdvice | 可以应用于权限管理 | 后置通知 | 在目标方法执行后实施增强 | org.springframework.aop.AfterReturningAdvice | 可以用关闭流、上传文件、删除临时文件等功能 | 环绕通知 | 在目标方法执行前后实施增强 | org.aopalliance.intercept.MethodInterceptor | 可以应用于日志、事务管理等功能 | 异常抛出通知 | 在方法抛出异常后执行通知 | org.springframework.aop.ThrowsAdvice | 可以应用于处理异常记录日志等功能 | 引介通知 | 在目标类中添加一些新的方法和属性 | org.springframework.aop.IntroductionInterceptor | 可以应用于老版本程序(增强类) |
即AOP在不改变原有代码的情况下,去增加新的功能
11.3 使用Spring实现AOP
11.3.1 使用AOP织入,需要导入一个依赖包
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
- 方式一:使用Spring的API接口【主要SpringAPI接口实现】
- 方式二:自定义来实现AOP【主要是切面定义】
11.3.2 使用Spring的API接口
1.创建Log实体类
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
2.创建AfterLog实体类
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
}
}
3.创建UserService接口
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
4.创建UserService接口实现类
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加一个用户");
}
public void delete() {
System.out.println("删除一个用户");
}
public void update() {
System.out.println("修改加一个用户");
}
public void query() {
System.out.println("查询一个用户");
}
}
5.applicationContext.xml配置文件
<?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 id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.Log"></bean>
<bean id="afterLog" class="com.kuang.log.AfterLog"></bean>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
6.创建测试类
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
7.测试结果
11.3.3 自定义来实现AOP
1.自定义切面类
public class DiyPointCut {
public void before() {
System.out.println("======方法执行前======");
}
public void after() {
System.out.println("======方法执行后======");
}
}
2.创建UserService接口
同11.3.2的UserService接口
3.创建UserService接口实现类
同11.3.2的UserService接口实现类
4.xml配置文件
<?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 id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
5.创建测试方法
6.测试结果
11.3.4 Aspectj切入点语法定义
定义切入点表达式:例如execution(* com.example.service.impl…*. *(…))
execution()是做常用的切点函数,其语法为:整个表达式可以分为五个部分
总结:
简单来说就是,该表达式的作用就是增强该包及其子包下的所有类的所有类型的全部方法
11.3.5 使用注解实现AOP
1.创建AnnotationPointCut实体类
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("====方法执行前====");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("====方法执行后=====");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("=====环绕前=====");
Signature signature = jp.getSignature();
System.out.println("签名为:"+signature);
Object proceed = jp.proceed();
System.out.println("=====环绕后=====");
System.out.println(proceed);
}
}
2.创建UserService接口
3.创建UserService接口实现类
- 同11.3.3UserServiceImpl实现类
4.applicationContext3.xml配置文件
<?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 id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
5.创建测试类
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
6.测试结果
好了,今天的有关AOP面向切面编程的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!
参考视频链接:https://www.bilibili.com/video/BV1WE411d7Dv(【狂神说Java】Spring5最新教程IDEA版通俗易懂)
|