深入理解Spring IOC之扩展篇(六)、基于Aop的自定义注解

简介: 深入理解Spring IOC之扩展篇(六)、基于Aop的自定义注解

上篇我们基于Spring的各种组件和注解把我们的业务逻辑和Spring进行了集成,其中我们定义了很多我们自己的注解。在本篇我们也将定义我们自己的注解,但是目的和上篇不同的是,上篇目的自定义注解是为了集成,而这篇的自定义注解是为了增强。

在demo开始之前,我先简单说下Aop中的这几个重要概念:

连接点(Joinpoint):在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后;

切点(Pointcut):所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;

增强(Advice):增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;

目标对象(Target):增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;

引介(Introduction):一种特殊的增强,它可以为类添加一些属性喝方法;

织入(Weaving):织入就是讲增强逻辑添加到目标对象的过程;

代理(Proxy):一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;

切面(Aspect):切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;

我们来看看具体的做法:

首先按照惯例,我们需要有我们自己的注解


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MyAspect {
}


然后是自己注解的处理类:


@Aspect
// 注意这里必须有Component注解
@Component
public class AspectHandler {
    @Pointcut(value = "@annotation(com.example.demo.external6.MyAspect)")
    public void myJoinPoint(){}
    @Around(value = "myJoinPoint()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around before....");
        joinPoint.proceed();
        System.out.println("around after....");
        return new MyEntity();
    }
    @Before(value = "myJoinPoint()", argNames = "joinPoint")
    public void before(JoinPoint joinPoint){
        System.out.println("before ======");
        MyEntity entity = (MyEntity)joinPoint.getArgs()[0];
        System.out.println(entity.getId());
        System.out.println("before ======");
    }
    @After(value = "myJoinPoint()", argNames = "joinPoint")
    public void after(JoinPoint joinPoint){
        System.out.println("after ==========");
        MyEntity entity = (MyEntity)joinPoint.getArgs()[0];
        System.out.println(entity.getId());
        System.out.println("after ==========");
    }
    @AfterReturning(value = "myJoinPoint()", argNames = "joinPoint,r", returning = "r")
    public void afterReturning(JoinPoint joinPoint,Object r){
        System.out.println("afterReturning");
        MyEntity r1 = (MyEntity)r;
        System.out.println(r1.getId());
    }
    @AfterThrowing(value = "myJoinPoint()", argNames = "joinPoint,tx",throwing = "tx")
    public void afterThrowing(JoinPoint joinPoint,Throwable tx){
        System.out.println("afterThrowing");
        System.out.println(tx.getMessage());
    }
}


用作测试的业务代码


@Component
public class TestService{
    @MyAspect
    public MyEntity doService(MyEntity entity){
//        if(entity.getId() == 1){
//            throw new RuntimeException("挂了");
//        }
        entity.setId(2);
        System.out.println("do service");
        return new MyEntity();
    }
}


简单构造一个实体类:


@Data
public class MyEntity {
    private int id;
}


配置类


@Configuration
@ComponentScan(basePackages = "com.example.demo.external6")
@EnableAspectJAutoProxy
public class Config {
}


注意EnableAspectJAutoProxy其中一个参数是expose-proxy,默认为false,设置为true之后你可以在被代理的类中使用AopUtil.currentProxy()方法来获取当前类的代理。另外一个参数proxyTargetClass是为你的类设置什么样的代理方式,我们知道spring aop当你的类实现了接口的时候,它会为你使用jdk动态代理,而当没有实现接口的时候会使用cglib代理,当我们把proxyTargetClass设置为true的时候,不论什么时候,都会使用cglib代理。

测试代码:


public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
        TestService testService = (TestService) annotationConfigApplicationContext.getBean("testService");
        MyEntity a = new MyEntity();
        a.setId(1);
        testService.doService(a);
    }


输出结果:


1686813573805.png


我们其实可以轻松看到执行顺序。然后我们再测试测试异常的结果,测试代码其实就是把TestService中的异常放开就行。

测试结果:


1686813581381.png


两个测试结果均符合我们的预期。

目录
相关文章
|
3天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
11 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
13天前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
28 2
|
21天前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
77 9
|
18天前
|
存储 开发框架 Java
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
文章详细介绍了Spring、IOC、DI的概念和关系,解释了控制反转(IOC)和依赖注入(DI)的原理,并提供了IOC的代码示例,阐述了Spring框架作为IOC容器的应用。
17 0
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
|
5天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
17 0
|
13天前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
33 0
|
Java 程序员 网络安全
spring4.1.8扩展实战之一:自定义环境变量验证
在之前学习spring环境初始化源码的过程中,见到有些地方能通过子类来实现自定义扩展,从本章开始,我们来逐个实践这些扩展,除了加深对spring的理解,有的扩展也能解决一些通用的问题
154 0
spring4.1.8扩展实战之一:自定义环境变量验证
|
1月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
10天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
56 2
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决