首页 / 更多教程 / 08 spring中的AOP
08 spring中的AOP
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了08 spring中的AOP,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含12272字,纯文字阅读大概需要18分钟。
内容图文
![08 spring中的AOP](/upload/InfoBanner/zyjiaocheng/993/b79e30c1245948c6b2d20b7c5f3784f4.jpg)
目录
8 spring中的AOP
8.1 AOP的概述
8.1.1 什么是AOP
AOP(Aspect Oriented Programming)即面向切面编程。它把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
8.1.2 AOP的优势与作用
一、作用
在程序运行期间,不修改源码对已有方法进行增强。
二、优势
1. 减少重复代码
2. 提高开发效率
3. 维护方便
8.1.3 AOP的实现方式
AOP是由动态代理实现的。
8.2 spring中的AOP
我们学习 spring 的 aop,就是通过配置的方式,实现将重复代码抽取,采用动态代理增强方法。
8.2.1 AOP相关术语
一、Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。例如业务层接口中的方法,它们可以将业务逻辑与增强代码结合起来。
二、Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。需要被增强的方法才是切入点。
三、Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
四、Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
五、Target(目标对象):: 代理的目标对象。
六、Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入
七、Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
八、Aspect(切面):是切入点和通知(引介)的结合。
8.2.2 使用spring中AOP需要做的事
一、开发阶段(编程人员需要做的):
1. 编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
2. 把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。
3. 在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。
二、运行阶段(spring框架需要做的):
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
8.3 spring基于xml的AOP配置
8.3.1 环境准备
一、导入依赖
除spring的核心依赖spring-context外,还需导入支持切入点表达式的依赖aspectjweaver。
- pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>
二、导入配置文件约束
- bean.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">
</beans>
三、编写业务层接口与实现类
- IAccountService接口
/**
* 模拟账户的业务层接口
*
* @author MaRui
* @date 2021-05-02 18:47
*/
public interface IAccountService {
/**
* 模拟保存账户的方法
*/
void saveAccount();
/**
* 模拟更新账户的方法
* @param id
*/
void updateAccount(int id);
/**
* 模拟删除账户的方法
* @return
*/
int deleteAccount();
}
- AccountService实现类
import com.marui.service.IAccountService;
/**
* @author MaRui
* @date 2021-05-02 18:50
*/
public class AccountService implements IAccountService {
@Override
public void saveAccount() {
System.out.println("执行了保存方法");
}
@Override
public void updateAccount(int id) {
System.out.println("执行了更新方法");
}
@Override
public int deleteAccount() {
System.out.println("执行了删除方法");
return 0;
}
}
四、编写通知工具类
- Logger工具类
/**
* 用于记录日志的工具类,提供了公共代码
*
* @author MaRui
* @date 2021-05-02 18:53
*/
public class Logger {
public void beforePrintLog() {
System.out.println("前置通知方法执行了");
}
public void afterReturningPrintLog() {
System.out.println("后置通知方法执行了");
}
public void afterThrowingPrintLog() {
System.out.println("异常通知方法执行了");
}
public void afterPrintLog() {
System.out.println("最终通知方法执行了");
}
}
8.3.2 四种通知的配置
- ean.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">
<!--配置spring的IoC,把service对象配置进来-->
<bean id="accountService" class="com.marui.service.impl.AccountServiceImpl"></bean>
<!--spring中基于xml的aop配置步骤
1. 把通知Bean也交给spring管理
2. 使用<aop:config>标签表名开始AOP的配置
3. 使用<aop:aspect>标签表名配置切面
id属性:给切面定义一个唯一标识
ref属性:是指定通知类bean的id
4. 在<aop:aspect>标签的内部使用对应标签来配置通知的类型
(1)<aop:before>标签:表示配置前置通知
method属性:用于指定通知类中的哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义是指对业务层哪些方法增强
pointcut-ref属性:用于引用<aop:pointcut>中的切入点表达式
切入点表达式写法: execution(访问修饰符 返回值 包名.类名.方法名(参数列表))
切入点表达式全通配写法: execution(* *..*.*(..))
切入点表达式常用写法:execution(* com.marui.service.impl.*.*(..))
(2)<aop:after-returning>:表示配置后置通知
(3)<aop:after-throwing>:表示配置异常通知,与后置通知不能同时存在
(4)<aop:after>:表示配置最终通知
(5)<aop:after>:表示配置最终通知
(6)<aop:pointcut>:切入点标签,当定义在<aop:aspect>内时,只有当前切面有效,若写在外面,则所有切面生效
id属性:用于指定切表达式的唯一标识
expression属性:用于指定表达式内容
-->
<!--配置通知类-->
<bean id="logger" class="com.marui.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面-->
<aop:aspect id="logAdvice" ref="logger">
<!--配置前置通知:在切入点方法执行前执行-->
<aop:before method="beforePrintLog" pointcut="execution(* com.marui.service.impl.*.*(..))"></aop:before>
<!--配置后置通知:在切入点方法正常执行后执行-->
<aop:after-returning method="afterReturningPrintLog" pointcut="execution(* com.marui.service.impl.*.*(..))"></aop:after-returning>
<!--配置异常通知:在切入点方法产生异常后执行-->
<aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* com.marui.service.impl.*.*(..))"></aop:after-throwing>
<!--配置最终通知:无论如何都会执行-->
<aop:after method="afterPrintLog" pointcut-ref="pointcut1"></aop:after>
<!--配置切入点通用表达式-->
<aop:pointcut id="pointcut1" expression="execution(* com.marui.service.impl.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
8.3.3 环绕通知的配置
- Logger工具类
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 用于记录日志的工具类,提供了公共代码
*
* @author MaRui
* @date 2021-05-02 18:53
*/
public class Logger {
public void beforePrintLog() {
System.out.println("前置通知方法执行了");
}
public void afterReturningPrintLog() {
System.out.println("后置通知方法执行了");
}
public void afterThrowingPrintLog() {
System.out.println("异常通知方法执行了");
}
public void afterPrintLog() {
System.out.println("最终通知方法执行了");
}
public Object aroundPrintLog(ProceedingJoinPoint pjp) {
beforePrintLog();
Object returnValue = null;
try {
returnValue = pjp.proceed(pjp.getArgs());
afterReturningPrintLog();
} catch (Throwable throwable) {
afterThrowingPrintLog();
throwable.printStackTrace();
} finally {
afterPrintLog();
}
return returnValue;
}
}
- bean.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">
<!--配置spring的IoC,把service对象配置进来-->
<bean id="accountService" class="com.marui.service.impl.AccountServiceImpl"></bean>
<!--配置通知类-->
<bean id="logger" class="com.marui.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面-->
<aop:aspect id="logAdvice" ref="logger">
<!--配置环绕通知-->
<aop:around method="aroundPrintLog" pointcut-ref="pointcut1"></aop:around>
<!--配置切入点表达式-->
<aop:pointcut id="pointcut1" expression="execution(* com.marui.service.impl.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
8.4 spring基于注解的AOP配置
spring基于注解的aop配置,在使用四种通知进行配置时有调用顺序问题,谨慎使用推荐使用环绕通知。
8.4.1 编写配置文件
- bean.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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.marui"></context:component-scan>
<!-- 开启spring注解aop的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
8.4.2 添加注解
- AccountServiceImpl实现类
import com.marui.service.IAccountService;
import org.springframework.stereotype.Service;
/**
* @author MaRui
* @date 2021-05-02 18:50
*/
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Override
public void saveAccount() {
System.out.println("执行了保存方法");
}
@Override
public void updateAccount(int id) {
System.out.println("执行了更新方法");
}
@Override
public int deleteAccount() {
System.out.println("执行了删除方法");
return 0;
}
}
- 使用四种基本通知的Logger工具类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 用于记录日志的工具类,提供了公共代码
*
* @author MaRui
* @date 2021-05-02 18:53
*/
@Component("logger")
//表示为切面
@Aspect
public class Logger {
//定义通用的切入点表达式
@Pointcut("execution(* com.marui.service.impl.*.*(..))")
private void pointcut1() {
}
@Before("execution(* com.marui.service.impl.*.*(..))")
public void beforePrintLog() {
System.out.println("前置通知方法执行了");
}
@AfterReturning(pointcut = "execution(* com.marui.service.impl.*.*(..))")
public void afterReturningPrintLog() {
System.out.println("后置通知方法执行了");
}
@AfterThrowing("execution(* com.marui.service.impl.*.*(..))")
public void afterThrowingPrintLog() {
System.out.println("异常通知方法执行了");
}
@After("pointcut1()")
public void afterPrintLog() {
System.out.println("最终通知方法执行了");
}
public Object aroundPrintLog(ProceedingJoinPoint pjp) {
beforePrintLog();
Object returnValue = null;
try {
returnValue = pjp.proceed(pjp.getArgs());
afterReturningPrintLog();
} catch (Throwable throwable) {
afterThrowingPrintLog();
throwable.printStackTrace();
} finally {
afterPrintLog();
}
return returnValue;
}
}
- 使用环绕通知配置的Logger工具类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 用于记录日志的工具类,提供了公共代码
*
* @author MaRui
* @date 2021-05-02 18:53
*/
@Component("logger")
//表示为切面
@Aspect
public class Logger {
//定义通用的切入点表达式
@Pointcut("execution(* com.marui.service.impl.*.*(..))")
private void pointcut1() {
}
public void beforePrintLog() {
System.out.println("前置通知方法执行了");
}
public void afterReturningPrintLog() { System.out.println("后置通知方法执行了"); }
public void afterThrowingPrintLog() {
System.out.println("异常通知方法执行了");
}
public void afterPrintLog() {
System.out.println("最终通知方法执行了");
}
@Around("pointcut1()")
public Object aroundPrintLog(ProceedingJoinPoint pjp) {
beforePrintLog();
Object returnValue = null;
try {
returnValue = pjp.proceed(pjp.getArgs());
afterReturningPrintLog();
} catch (Throwable throwable) {
afterThrowingPrintLog();
throwable.printStackTrace();
} finally {
afterPrintLog();
}
return returnValue;
}
}
8.4.3 使用纯注解配置AOP
在主配置文件上加上@EnableAspectJAutoProxy注解。
内容总结
以上是互联网集市为您收集整理的08 spring中的AOP全部内容,希望文章能够帮你解决08 spring中的AOP所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。