Spring5源码(31)-基于@AspectJ的AOP

简介: Spring5源码(31)-基于@AspectJ的AOP


上一节介绍了基于Schema的AOP,本篇介绍基于@AspectJ的AOP。

1.@AspectJ切面
  • 目标对象

package com.lyc.cn.v2.day07;
public interface Animal {
    void sayHello();
}

package com.lyc.cn.v2.day07;
public class Dog implements Animal {
    public void sayHello() {
        System.out.println("--被增强的方法");
    }
}
  • 引介

package com.lyc.cn.v2.day07;
public interface IIntroduce {
    void sayIntroduce();
}

package com.lyc.cn.v2.day07;
public class IntroduceImpl implements IIntroduce {
    @Override
    public void sayIntroduce() {
        System.out.println("--引入");
    }
}
  • 切面

package com.lyc.cn.v2.day07;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
 * 切面类
 * @author: LiYanChao
 * @create: 2018-10-31 15:46
 */
@Aspect
public class DogAspect {
    /**
     * 例如:execution (* com.sample.service.impl..*.*(..)
     * 1、execution(): 表达式主体。
     * 2、第一个*号:表示返回类型,*号表示所有的类型。
     * 3、包名:表示需要拦截的包名,后面的两个点表示当前包和当前包的所有子包,
     * 即com.sample.service.impl包、子孙包下所有类的方法。
     * 4、第二个*号:表示类名,*号表示所有的类。
     * 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个点表示任何参数。
     **/
    @Pointcut("execution(* com.lyc.cn.v2.day07.*.*(..))")
    public void test() {
    }
    @Before("test()")
    public void beforeTest() {
        System.out.println("==前置增强");
    }
    @After("test()")
    public void afterTest() {
        System.out.println("==后置最终增强");
    }
    @AfterThrowing("test()")
    public void afterThrowingTest() {
        System.out.println("==后置异常增强");
    }
    @AfterReturning("test()")
    public void afterReturningTest() {
        System.out.println("==后置返回增强");
    }
    @Around("test()")
    public Object aroundTest(ProceedingJoinPoint p) {
        System.out.println("==环绕增强开始");
        Object o = null;
        try {
            o = p.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("==环绕增强结束");
        return o;
    }
    @DeclareParents(value = "com.lyc.cn.v2.day07.Dog", defaultImpl = IntroduceImpl.class)
    private IIntroduce iIntroduce;
}
  • 配置文件

<?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">
    <!--
        1、proxy-target-class
            如果被代理的目标对象至少实现了一个接口,则会使用JDK动态代理,所有实现该目标类实现的接口都将被代理
            如果该目标对象没有实现任何接口,则创建CGLIB动态代理。
            但是可以通过proxy-target-class属性强制指定使用CGLIB代理,
        2、expose-proxy
            解决目标对象内部的自我调用无法实施切面增强的问题
    -->
    <aop:aspectj-autoproxy proxy-target-class="true">
        <!-- 指定@Aspect类,支持正则表达式,符合该表达式的切面类才会被应用-->
        <aop:include name="dogAspect"></aop:include>
    </aop:aspectj-autoproxy>
    <!--bean-->
    <bean id="dog" class="com.lyc.cn.v2.day07.Dog"/>
    <!--AspectJ-->
    <bean name="dogAspect" class="com.lyc.cn.v2.day07.DogAspect"/>
</beans>
  • 测试及结果

package com.lyc.cn.v2.day07;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
    @Test
    public void test1() {
        // 基于@AspectJ注解方式
        ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day07.xml");
        Dog dog = ctx.getBean("dog", Dog.class);
        dog.sayHello();
    }
    @Test
    public void test2() {
        // 引入
        ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day07.xml");
        // 注意:getBean获取的是dog
        IIntroduce introduce = ctx.getBean("dog", IIntroduce.class);
        introduce.sayIntroduce();
    }
}

// 测试一
==环绕增强开始
==前置增强
--被增强的方法
==环绕增强结束
==后置最终增强
==后置返回增强

// 测试二
--引入
2.总结

前篇和本篇主要还是回顾了SpringAop的使用方式,也为了接下来的源码分析做好测试类准备,在接下来的分析中主要讲解以@AspectJ方式的实现方式。



目录
相关文章
|
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的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
5月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
904 0
|
6月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
646 0
|
2月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
297 3