深入理解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


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

目录
相关文章
|
5天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
3天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
16 2
|
5天前
|
XML Java 数据格式
Spring使用AOP 的其他方式
Spring使用AOP 的其他方式
14 2
|
5天前
|
XML Java 数据格式
Spring 项目如何使用AOP
Spring 项目如何使用AOP
19 2
|
5天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
15 2
|
10天前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
23 5
|
Java 程序员 API
spring4.1.8扩展实战之八:Import注解
spring框架下做开发时,@Import是常见的注解,可以用来动态创建bean,今天我们先从源码分析原理,再用实战来验证Import的作用
304 0
spring4.1.8扩展实战之八:Import注解
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
53 0
|
2月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
137 0