一、AOP 面向切面编程

1.1 作用以及优势

  1. 作用:在运行期间,不修改源码对已有方法进行增强
  2. 优势:
  • 减少代码重复率;
  • 提高开发效率;
  • 维护方便;

    1.2 需要jar包

    image.png

1.3 AOP的相关性质

  1. AOP底层通过代理模式实现不修改代码而增强功能。
  2. 连接点:被代理的对象中的所有方法/函数(可以被增强的点)都是连接点
  3. 切入点:需要/可以被增强的点既是连接点又是切入点。
  4. Advice(通知、增强)
  • 前置、后置、环绕、通知,增强 目标方法的内容
  1. Target(目标对象)
  2. Weaving织入:把增强应用到目标对象来创建新的代理对象的过程。
  3. Spring通过动态代理的方式进行织入。
  4. Proxy(代理):一个类被AOP织入增强后,就产生了结果代理类。
  5. Aspect(切面) :切入点(要增强的方法)和通知(怎么增强的具体实现)之间的关系称之为切面。

1.4 基于XML的AOP配置

1.4.1 分类
  1. aop:conflg: 作用于声明开始aop的配置
  2. aop;aspect: 作用:配置切面
  3. aop:pointcut: 作用:配置切入点表达式
  4. aop:before: 作用:用于配置前置通知
  5. aop: after-returnlng:
  6. aop:aftre_throwing: 用于配置异常通知
  7. aop:after: 用于配置最终通知
  8. aop:around : 用于配置环绕通知

1.4.2 测试案例

流程:生成通知类、目标类、配置通知类目标类。

  1. 通知类,进行配置一些用于增强的通知方法

    1. public class AopLoggerManager {
    2. // 前置通知
    3. public void beforeAdvice(){
    4. System.out.println("前置通知开始记录日志了---------");
    5. }
    6. //后置通知
    7. public void afterAdvice(){
    8. System.out.println("后置通知开始记录日志了---------");
    9. }
    10. //异常通知
    11. public void exceptionAdvice(){
    12. System.out.println("异常通知开始记录日志了---------");
    13. }
    14. //最终通知
    15. public void endAdvice(){
    16. System.out.println("最终通知开始记录日志了---------");
    17. }
    18. }
  2. 生成核心类

    1. public class modulet1 implements moduleimp{
    2. public void getmethon1(){
    3. System.out.println("核心业务1");
    4. }
    5. public void getmethon2(){
    6. System.out.println("核心业务2");
    7. }
    8. public void getmethon3(){
    9. System.out.println("核心业务3");
    10. }
    11. }
  3. 配置XML

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans
    7. http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/context
    9. http://www.springframework.org/schema/context/spring-context.xsd
    10. http://www.springframework.org/schema/aop
    11. http://www.springframework.org/schema/aop/spring-aop.xsd">
    12. <!--配置通知类-->
    13. <bean id="aopLogger" class="com.eagleslab.springaop.logger.AopLoggerManager"></bean>
    14. <!--配置目标类-->
    15. <bean id="aopModule" class="com.eagleslab.springaop.module.ModuleImpl"></bean>
    16. <!--开始配置aop-->
    17. <aop:config>
    18. <!--配置切面(切入点和通知之间的关系)-->
    19. <aop:aspect id = "aspect" ref="aopLogger">
    20. <!--声明一个切入点表达式(声明/定位所有需要被增强方法的位置)-->
    21. <aop:pointcut id="pt01" expression="execution(* com.eagleslab.springaop.module.Module.*(..))"/>
    22. <!--开始配置通知-->
    23. <!--前置通知-->
    24. <aop:before method="beforeAdvice" pointcut-ref="pt01"></aop:before>
    25. <!--后置通知-->
    26. <aop:after-returning method="afterAdvice" pointcut-ref="pt01"></aop:after-returning>
    27. <!--异常通知-->
    28. <aop:after-throwing method="exceptionAdvice" pointcut-ref="pt01"></aop:after-throwing>
    29. <!--最终通知-->
    30. <aop:after method="endAdvice" pointcut-ref="pt01"></aop:after>
    31. </aop:aspect>
    32. </aop:config>
    33. </beans>

环绕通知:可以替代所有通知的功能,主要是它可以在器对于的通知类中的对应方法中实现很多功能。

  1. //环绕通知
  2. //注意该通知方法需要传入一个参数。
  3. public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
  4. //获取调用目标方法的参数
  5. Object[] args = proceedingJoinPoint.getArgs();
  6. try {
  7. System.out.println("前置通知开始记录日志----");
  8. //调用目标方法
  9. proceedingJoinPoint.proceed(args);
  10. System.out.println("后置通知开始记录日志----");
  11. } catch (Throwable throwable) {
  12. System.out.println("异常通知开始记录日志----");
  13. throwable.printStackTrace();
  14. }finally {
  15. System.out.println("最终通知开始记录日志---");
  16. }
  17. }

1.4.5 基于注解的AOP配置

流程:开启扫描包——>开启AOP注解的支持——>添加注解

  1. @Component("aopLogger")
  2. // 用于声明当前类为通知类
  3. @Aspect
  4. public class AopLoggerManager {
  5. //声明一个切入点表达式
  6. @Pointcut("execution(* com.eagleslab.springaop.module.Module.*(..))")
  7. public void pt01(){};
  8. //注意书写格式:
  9. //前置通知
  10. @AfterReturning("pt01()")
  11. public void beforeAdvice(){
  12. System.out.println("前置通知开始记录日志了---------");
  13. }
  14. //后置通知
  15. @Before("pt01()")
  16. public void afterAdvice(){
  17. System.out.println("后置通知开始记录日志了---------");
  18. }
  19. //异常通知
  20. @AfterThrowing("pt01()")
  21. public void exceptionAdvice(){
  22. System.out.println("异常通知开始记录日志了---------");
  23. }
  24. //最终通知
  25. @After("pt01()")
  26. public void endAdvice(){
  27. System.out.println("最终通知开始记录日志了---------");
  28. }

@Component(“aopModule”)

二、Spring单元测

2.1 需要jar包

image.png

2.2 实际测试

通过spring的测试模块整合junit在程序运行期间获取核心容器对象。

  1. //@RunWith 用来替换运行器,替换为spring提供的运行器。
  2. @RunWith(SpringJUnit4ClassRunner.class)
  3. //指定核心配置文件的位置。
  4. @ContextConfiguration(locations = "classpath:xml/beans.xml")
  5. public class SpringAopDemo01 {
  6. //取出核心配置对象
  7. @Autowired
  8. private ApplicationContext applicationContext;
  9. @Test
  10. public void test01(){
  11. Object emp = applicationContext.getBean("emp");
  12. System.out.println(emp);
  13. }
  14. }

运行结果
image.png