Spring中基于XML的AOP配置详解

网友投稿 234 2022-11-15


Spring中基于XML的AOP配置详解

1. 准备工作

1.1 创建工程 day03_eesy_03SpringAOP

1.2 在配置文件pom.xml中添加依赖

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.itheima

day03_eesy_03springAOP

1.0-SNAPSHOT

jar

org.springframework

spring-context

5.2.4.RELEASE

org.aspectj

aspectjweaver

1.9.5

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.itheima

day03_eesy_03springAOP

1.0-SNAPSHOT

jar

org.springframework

spring-context

5.2.4.RELEASE

org.aspectj

aspectjweaver

1.9.5

说明: aspect依赖是用来声明切入点坐标的

1.3 编写业务层代码

1.创建包 service

2.创建业务层接口IAccountService.java

/**

* 账户的业务层接口

*/

public interface IAccountService {

/**

* 模拟保存账户

*/

void saveAccount();

/**

* 模拟更新账户

*/

void updateAccount(Integer i);

/**

* 模拟删除账户

*/

int deleteAccount();

}

3.创建业务层实现类AccountServiceImpl.java

/**

* 账户的业务层实现类

*/

public class AccountServiceImpl implements IAccountService {

public void saveAccount() {

System.out.println("执行了保存");

}

public void updateAccount(Integer i) {

System.out.println("执行力更新");

}

public int deleteAccount() {

System.out.println("执行了删除");

return 0;

}

}

4.创建日志类

​ 该类为用于记录日志的工具类,它里面提供了公共的代码(通知)

Logger.java

/**

* 用于记录日志的工具类,它里面提供了公共的代码

*/

public class Logger {

/**

* 用于打印日志,计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)

*/

public void printLog(){

System.out.println("Logger类中的printLog方法开始记录日志了");

}

}

2. 进行配置

创建配置文件 bean.xml

先添加包含AOP的约束,后添加配置

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

说明: 切入点表达式最好按软件的提示写,自己直接手写在测试时容易报错

3. 创建测试类AOPTest.java

/**

* 测试AOP的配置

*/

public class AOPTest {

public static void main(String[] args) {

//1.获取容器

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

//2.获取对象

IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");

accountService.saveAccount();

}

}

4. 运行结果

5. 目录结构

6. 切入点表达式写法补充

6.1 介绍

6.2 在bean.xml中表示

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schXBmMFCQjKemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schXBmMFCQjKemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

6.3 在测试类AOPTest.java中测试

/**

* 测试AOP的配置

*/

public class AOPTest {

public static void main(String[] args) {

//1.获取容器

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

//2.获取对象

IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");

accountService.saveAccount();

accountService.updateAccount(1);

accountService.deleteAccount();

}

}

6.4 运行结果

7. 四种通知类型补充

7.1 在Logger.java类中添加方法

/**

* 用于记录日志的工具类,它里面提供了公共的代码

*/

public class Logger {

/**

* 前置通知

*/

public void beforePrintLog(){

System.out.println("前置通知:Logger类中的printLog方法开始记录日志了");

}

/**

* 后置通知

*/

public void afterReturningPrintLog(){

System.out.println("后置通知:Logger类中的printLog方法开始记录日志了");

}

/**

* 异常通知

*/

public void afterThrowingPrintLog(){

System.out.println("异常通知:Logger类中的printLog方法开始记录日志了");

}

/**

* 最终通知

*/

public void afterPrintLog(){

System.out.println("最终通知:Logger类中的printLog方法开始记录日志了");

}

}

7.2 在bean.xml中进行配置

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

7.3 在测试类AOPTest.java中运行

/**

* 测试AOP的配置

*/

public class AOPTest {

public static void main(String[] args) {

//1.获取容器

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

//2.获取对象

IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");

accountService.saveAccount();

}

}

7.4 运行结果

8. 通用化切入点表达式

用于解决在bean.xml文件中配置通知时多次写切入点表达式的问题

使用 aop:pointcut标签,在bean.xml中进行配置

8.1 在aop:aspect标签内部使用aop:pointcut

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

运行结果:

此时,aop:pointcut定义的切入点表达式只能在当前切面中使用

8.2 在aop:aspect标签外部使用aop:pointcut

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

运行结果:

此时所有的切面都能使用该aop:pointcut定义的切入点表达式

主要: 当在aop:aspect标签外部使用aop:pointcut标签定义切入点表达式的时候,由于使用的约束的规定, aop:pointcut标签只能在 aop:aspect标签上方

9. Spring的环绕通知

9.1 在Logger.java中添加实现环绕通知的方法 aroundPringLog

/**

* 用于记录日志的工具类,它里面提供了公共的代码

*/

public class Logger {

/**

* 环绕通知

*

*/

public void aroundPringLog(){

System.out.println("Logger类中的aroundPringLog方法开始记录日志了");

}

}

9.2 在bean.xml中完成配置

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd">

9.3 此时运行结果

9.4 问题分析

此时只执行了通知方法,而切入点方法没有执行

原因:

​ 通过对比动态的代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而本案例中的代码没有

9.5 完善aroundPringLog方法

Logger.java

/**

* 用于记录日志的工具类,它里面提供了公共的代码

*/

public class Logger {

/**

* 环绕通知

* 问题:

* 当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了

* 分析:

* 通过对比动态的代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有

* 解决:

* Spring框架为我们提供了一个接口,ProceedingJoinPoint,该接口有一个方法proceed(),此方法就相当于明确调用切入点方法

* 该接口可以作为环绕通知的方法参数, 在程序执行的时候,Spring框架会为我们提供该接口供我们使用

*

* Spring的环绕通知:

* 他是Spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式

*/

public Object aroundPringLog(ProceedingJoinPoint proceedingJoinPoint){

Object returnValue = null;

try {

Object[] args = proceedingJoinPoint.getArgs(); //得到方法执行所需要的参数

System.out.println("Logger类中的aroundPringLog方法开始记录日志了-----前置");

returnValue = proceedingJoinPoint.proceed(args); //明确调用业务层方法,切入点方法

System.out.println("Logger类中的aroundPringLog方法开始记录日志了-----后置");

return returnValue;

}catch (Throwable throwable){

System.out.println("Logger类中的aroundPringLog方法开始记录日志了-----异常");

throw new RuntimeException(throwable);

}finally {

System.out.println("Logger类中的aroundPringLog方法开始记录日志了-----最终");

}

}

}

9.6 运行结果

9.7 目录结构


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用Spring源码报错java:找不到类 InstrumentationSavingAgent的问题
下一篇:Java工程如何打印程序日志过程解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~