Spring 创建一个自定义注解

简介: 平时在用springBoot的使用,常常会用到@Service,@Compent等等注解,简化了我们的开发流程,提升了开发效率.那如何自己来写一个注解呢?下面就来介绍一下。

网络异常,图片无法展示
|


前言


平时在用springBoot的使用,常常会用到@Service@Compent等等注解,简化了我们的开发流程,提升了开发效率.那如何自己来写一个注解呢?下面就来介绍一下。

写一个注解

创建一个注解主要分两部分,一部分是创建注解类,一部分是创建一个切面类

创建注解类

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnn {
    String value() default "d";
}

创建注解类的关键字就是@interface,这个注解类设置了一个value变量,默认值为d;

在注解类上面还有@Target@Retention注解,下面来说说创建注解类时需要用到的几个注解:

@Target

用来标记这个注解可以用于哪些地方,与ElementType枚举类搭配使用,那这个枚举类里面有什么内容呢?

public enum ElementType {
    /** 类,接口(包括注释类型)或枚举声明*/
    TYPE,
    /** 字段声明(包括枚举常量)*/
    FIELD,
    /** 方法声明*/
    METHOD,
    /** 形式参数(形参-调用方法时传入的参数)声明 */
    PARAMETER,
    /** 构造函数声明 */
    CONSTRUCTOR,
    /** 局部变量声明 */
    LOCAL_VARIABLE,
    /** 注释类型声明 */
    ANNOTATION_TYPE,
    /** 包声明 */
    PACKAGE,
    /**
     * 类型参数声明
     * java8新特性:
     * @since 1.8
     */
    TYPE_PARAMETER,
    /**
     * 任何类型声明 
     * java8新特性:
     * @since 1.8
     */
    TYPE_USE
}

@Retention

该注解表示自定义注解的生命周期

public enum RetentionPolicy {
    /**
     * 注释将被编译器丢弃。
     */
    SOURCE,
    /**
     * 注释由编译器记录在类文件中
     * 但不必在运行时由VM保留。 这是默认值
     */
    CLASS,
    /**
     *注释由编译器记录在类文件中,并且
     *在运行时由VM保留,因此可以以反射方式读取它们。
     */
    RUNTIME
}

写一个切面类

因为用到了切面,所以我们要先导入Spring AOP这个依赖包。

<!--SpringBoot项目导入AOP-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

创建切面类

@Aspect
@Component
public class MyAnnAop {
    private Logger logger= LoggerFactory.getLogger(MyAnnAop.class);
    @Pointcut("@annotation(com.example.demo.annotation.MyAnn)")
    public void ann(){
    }
    @Before("ann()")
    public void before(JoinPoint joinPoint){
        logger.info("打印:开始前");
    }
    @AfterReturning(value = "ann()",returning = "res")
    public Object dochange(JoinPoint joinPoint,Object res){
        logger.info("AfterReturning通知开始-获取数据:{}",res);
        //获取数据
        Map<String,String> map= (Map<String, String>) res;
        //添加新值
        map.put("s1","我是在AOP中添加的新值");
        return map;
    }
}

Spring AOP说明

具体可以查阅Spring AOP相关资料

注解 说明
@Before 前置通知,在连接点方法前调用
@Around 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法
@After 后置通知,在连接点方法后调用
@AfterReturning 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常
@AfterThrowing 异常通知,当连接点方法异常时调用

使用自定义的注解

这里使用普通的SpringBoot来使用注解,创建一个Service,在里面使用注解,然后才控制层调用

//服务层
@Service
public class TestService {
    @MyAnn
    public Map test(){
        Map<String,String>  map=new HashMap<>();
        map.put("t1","我是在Service设置的值");
        return map;
    }
}
//控制层
@RestController
public class Test2 {
    private Logger logger= LoggerFactory.getLogger(Test2.class);
    @Autowired
    private TestService testService;
    @GetMapping("/test")
    public String test(String id){
        Map<String,String> s=testService.test();
        logger.info("控制层输出:{}",s.get("s1"));
        return "sccess";
    }
}

输出

com.example.demo.aop.MyAnnAop : AfterReturning通知开始-获取数据:{t1=我是在Service设置的值}
com.example.demo.web.Test2    : 控制层输出:我是在AOP中添加的新值

注意事项

上面那样使用注解是没问题的,但是如果是下面这样使用,AOP就会失效

@RestController
public class Test2 {
    private Logger logger= LoggerFactory.getLogger(Test2.class);
    @Autowired
    private TestService testService;
    @GetMapping("/test")
    public String test(String id){
        Map<String,String> s=this.test2();
        logger.info("控制层输出:{}",s.get("s1"));
        return "sccess";
    }
    @MyAnn
    public Map test2(){
        Map<String,String>  map=new HashMap<>();
        map.put("t1","我是在控制层设置的值");
        return map;
    }
}

输出

com.example.demo.web.Test2       : 控制层输出:null

这是应为内部方法调用,调用的是具体方法,并没有调用使用AOP后生成的代理方法

目录
相关文章
|
16天前
|
Java Spring 容器
如何解决spring EL注解@Value获取值为null的问题
本文探讨了在使用Spring框架时,如何避免`@Value(&quot;${xxx.xxx}&quot;)`注解导致值为null的问题。通过具体示例分析了几种常见错误场景,包括类未交给Spring管理、字段被`static`或`final`修饰以及通过`new`而非依赖注入创建对象等,提出了相应的解决方案,并强调了理解框架原理的重要性。
56 4
|
2月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
144 1
|
2月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
73 0
|
13天前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
53 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
5天前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
10天前
|
XML Java 数据库
Spring boot的最全注解
Spring boot的最全注解
|
11天前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
11天前
|
Java API Spring
springBoot:注解&封装类&异常类&登录实现类 (八)
本文介绍了Spring Boot项目中的一些关键代码片段,包括使用`@PathVariable`绑定路径参数、创建封装类Result和异常处理类GlobalException、定义常量接口Constants、自定义异常ServiceException以及实现用户登录功能。通过这些代码,展示了如何构建RESTful API,处理请求参数,统一返回结果格式,以及全局异常处理等核心功能。
|
17天前
|
Java Spring 容器
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
这篇文章讨论了在Spring Boot 3.2.1版本中,同名同类型的bean和@Service注解类之间冲突的问题得到了解决,之前版本中同名bean会相互覆盖,但不会在启动时报错,而在配置文件中设置`spring.main.allow-bean-definition-overriding=true`可以解决这个问题。
51 0
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
|
22天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
42 2