Spring5源码(30)-基于Schema的AOP

简介: Spring5源码(30)-基于Schema的AOP


前几篇已经对AOP中的相关概念做了解释,但是都是通过编码方式实现的,每次都需要通过ProxyFactory去创建代理,接下来我们介绍Spring中的自动代理方式来实现AOP,基于Schema配置文件方式和基于@AspectJ注解的方式。当然自动代理实现的机制,放到后面的章节分析,本篇权当温习,也为接下来的源码分析做好铺垫。

1.普通切面
  • 目标对象

package com.lyc.cn.v2.day06;
public interface Animal {
    void sayHello(String name,int age);
    void sayException(String name, int age);
}

package com.lyc.cn.v2.day06;
public class Cat implements Animal {
    @Override
    public void sayHello(String name, int age) {
        System.out.println("--调用被增强方法");
    }
    @Override
    public void sayException(String name, int age) {
        System.out.println("==抛出异常:" + 1 / 0);
    }
}
  • 切面类

package com.lyc.cn.v2.day06;
import org.aspectj.lang.ProceedingJoinPoint;
public class CatAspect {
    /**
     * 前置增强
     */
    public void beforeAdvice(String name, int age) {
        System.out.println("==前置增强,name:" + name + ",age:" + age);
    }
    /**
     * 后置异常增强
     */
    public void afterExceptionAdvice(String name, int age) {
        System.out.println("==后置异常增强,name:" + name + ",age:" + age);
    }
    /**
     * 后置返回增强
     */
    public void afterReturningAdvice(String name, int age) {
        System.out.println("==后置返回增强,name:" + name + ",age:" + age);
    }
    /**
     * 后置最终增强
     */
    public void afterAdvice(String name, int age) {
        System.out.println("==后置最终增强,name:" + name + ",age:" + age);
    }
    /**
     * 环绕增强
     */
    public Object roundAdvice(ProceedingJoinPoint p, String name, int age) {
        System.out.println("==环绕增强开始,name:" + name + ",age:" + age);
        Object o = null;
        try {
            o = p.proceed();
            Object[] args = p.getArgs();
            if (null != args) {
                for (int i = 0; i < args.length; i++) {
                    System.out.println("==环绕增强参数值:" + args[i]);
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("==环绕增强结束,name:" + name + ",age:" + age);
        return o;
    }
}
  • 配置文件

<?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="cat" class="com.lyc.cn.v2.day06.Cat"/>
    <!-- 切面类-->
    <bean id="catAspect" class="com.lyc.cn.v2.day06.CatAspect"/>
    <!--AOP配置(一)-->
    <aop:config proxy-target-class="true">
        <!-- 切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.lyc.cn.v2.day06..*.*(..)) and args(name,age)"/>
        <aop:aspect ref="catAspect" order="0">
            <!--前置增强,在切入点选择的方法之前执行-->
            <aop:before method="beforeAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
            <!--后置异常增强,在切入点选择的方法抛出异常时执行-->
            <aop:after-throwing method="afterExceptionAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
            <!--后置返回增强,在切入点选择的方法正常返回时执行-->
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
            <!--后置最终增强,在切入点选择的方法返回时执行,不管是正常返回还是抛出异常都执行-->
            <aop:after method="afterAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
            <!--
                环绕增强,环绕着在切入点选择的连接点处的方法所执行的通知,可以决定目标方法是否执行,
                什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值
            -->
            <aop:around method="roundAdvice" pointcut-ref="pointcut" arg-names="p,name,age"/>
        </aop:aspect>
    </aop:config>
</beans>
  • 测试类及结果

package com.lyc.cn.v2.day06;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
    @Test
    public void test1() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
        Cat cat = ctx.getBean("cat", Cat.class);
        cat.sayHello("美美", 3);
    }
    @Test
    public void test2() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
        Cat cat = ctx.getBean("cat", Cat.class);
        cat.sayException("美美", 3);
    }
}

// 测试1
==前置增强,name:美美,age:3
==环绕增强开始,name:美美,age:3
--调用被增强方法
==环绕增强参数值:美美
==环绕增强参数值:3
==环绕增强结束,name:美美,age:3
==后置最终增强,name:美美,age:3
==后置返回增强,name:美美,age:3

// 测试2
==前置增强,name:美美,age:3
==环绕增强开始,name:美美,age:3
==环绕增强结束,name:美美,age:3
==后置最终增强,name:美美,age:3
==后置返回增强,name:美美,age:3java.lang.ArithmeticException: / by zero
    at com.lyc.cn.v2.day06.Cat.sayException(Cat.java:12)
    at com.lyc.cn.v2.day06.Cat$$FastClassBySpringCGLIB$$336350b6.invoke(<generated>

相信大家对这样的配置已经非常熟悉了,而且在配置文件中已经有了比较完善的说明,而且Schema的配置方式已经不是那么流行,所以我们不做过多的介绍。

2.引介增强

Spring引入允许为目标类对象引入新的接口。

  • 引介接口和实现

package com.lyc.cn.v2.day06;
/**
 * 引入
 * @author: LiYanChao
 * @create: 2018-10-28 15:48
 */
public interface IIntroduce {
    void sayIntroduce();
}

package com.lyc.cn.v2.day06;
/**
 * @author: LiYanChao
 * @create: 2018-10-28 15:48
 */
public class IntroduceImpl implements IIntroduce {
    @Override
    public void sayIntroduce() {
        System.out.println("--引入");
    }
}
  • 修改配置文件配置引介增强
    <aop:aspect/>标签中加入如下配置:

<!--
    引入
    1、types-matching:匹配需要引入接口的目标对象的AspectJ语法类型表达式。
    2、implement-interface:定义需要引入的接口。
    3、default-impl和delegate-ref:定义引入接口的默认实现,二者选一,
      default-impl是接口的默认实现类全限定名,而delegate-ref是默认的实现的委托Bean名。
-->
<aop:declare-parents types-matching="com.lyc.cn.v2.day06.Cat"
                 implement-interface="com.lyc.cn.v2.day06.IIntroduce"
                 default-impl="com.lyc.cn.v2.day06.IntroduceImpl"/>
  • 测试及结果

@Test
public void test3() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
    // 注意:getBean获取的是cat
    IIntroduce introduce = ctx.getBean("cat", IIntroduce.class);
    introduce.sayIntroduce();
}

--引入
3.总结

本篇主要回顾一下基于Schema的AOP的配置方式,都是基于配置文件,当然这里涉及到的知识点也很多,这里只是做了简单的介绍,关于更多的配置,大家可以参考Spring的官方文档。





目录
相关文章
|
3月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
422 0
|
2月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
7月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1100 13
|
4月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
4月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
8月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
504 70
|
9月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1061 0
|
9月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
516 0