自定义注解怎么用

分类: 365bet体育在线15 时间: 2025-09-03 00:51:13 作者: admin

什么是注解

Java的注解(Annotation)是一种元数据,它可以提供程序的额外信息,帮助程序员更好地管理程序。注解通常被用作代码的标记或者指定某些行为的方式。在Java中,注解以@符号开头,放在代码的各个位置,包括类、方法、成员变量、参数等地方。注解可以通过反射机制在程序运行时获取到,并能对程序的执行产生一定的影响。Java提供了一些系统注解,例如@Override、@Deprecated等等,同时也支持自定义注解。

注解和注释有什么区别

注解和注释看似相似,但它们在意义和使用方式上有很大的不同。

注释(Comment)是程序员在代码中添加的一些说明信息,它们并不会对程序的运行产生任何影响,仅仅是为了方便程序员对代码的理解和维护。注释可以是单行或多行,以 // 或 /.../ 形式添加。

注解(Annotation)则是一种用来标记程序元素和提供编译器和框架额外信息的元数据。注解以 @ 符号开头,可以加在类、方法、变量等各种程序元素上,它们能够为程序的开发、维护、测试和部署等各个环节提供很多便利。注解的作用不限于提供说明信息,它还可以通过反射机制在程序运行时动态地检查和操作程序元素。

因此,注解和注释的主要区别在于:注释只是为了代码的可读性和辅助程序员理解,没有实际的功能;而注解则具有明确的语义和作用,并能够为程序的开发和维护提供各种服务。

自定义注解怎么用

自定义注解需要使用@interface定义,其内容可以由编程人员自行定义。下面是一个简单的自定义注解的例子:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Log {

String value() default "";

}

该注解被定义为@Log,可以用于方法上,它有一个可选的value属性供注解使用者添加一些描述信息。

注意,以上代码是不能直接运行的,因为还涉及到aop切面和反射的知识,完整示例程序看文末。

自定义注解在实际开发中可以有很多用途,下面举几个例子:

@ParamName注解

在Java中,方法的参数没有名称,只能通过索引来访问。有时候代码可读性会因为这个问题而受到影响,因此我们可以用自定义注解来为方法的参数添加名称:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.PARAMETER)

public @interface ParamName {

String value();

}

使用方式:

public void foo(@ParamName("param1") int param1, @ParamName("param2") double param2) {

// do something

}

这样,在运行时我们就可以通过反射机制获取到每个参数的名称。

@Cacheable注解

在实际开发中,我们往往需要对一些计算量较大或者耗时较长的方法进行缓存,用自定义注解可以非常方便地实现这个功能:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Cacheable {

String value();

}

然后我们可以用反射机制获取到被@Cacheable注解的方法,对其返回值做缓存。

@Encrypt注解

在实际开发中,我们可能需要对某些敏感数据进行加密,而不是直接存储明文。用自定义注解可以为某些变量添加自动加密的功能,例如:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

public @interface Encrypt {

boolean enable() default true;

}

然后我们可以通过反射机制获取到被@Encrypt注解的变量,如果该注解的enable属性为true,就对该变量进行加密操作。

SpringBoot中的常见注解

@SpringBootApplication:该注解为Spring Boot的入口注解,整合了@Configuration、@EnableAutoConfiguration和@ComponentScan三个注解。

@RestController:声明一个控制器类,并且该类中的所有方法都以JSON的形式返回。

@RequestBody:该注解用于接收请求体的数据,并将其转换为Java对象。

@RequestMapping:定义访问路由,可以设置请求方法、参数、请求头等。

@PathVariable:获取RESTful接口中的路径参数。

@RequestParam:获取请求参数。

@Autowired:该注解用于自动注入依赖,可以配合@Qualifier注解进行精确匹配。

@Value:该注解用于获取配置文件中的属性值。

@ConfigurationProperties:该注解用于将配置文件中的属性值注入到Java Bean中。

@EnableAutoConfiguration:该注解自动配置Spring应用程序,简化了Spring应用程序的配置。

@ConditionalOnProperty:该注解用于控制某个配置项是否启用,可以设置默认值、匹配规则等。

@EnableAsync:该注解启用异步调用。

@Async:该注解将标记的方法异步执行。

@Scheduled:该注解用于定时任务。

我们日常开发会怎么用到自定义注解

校验参数

我们可以通过自定义注解来对控制器方法的参数做参数校验,例如:

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface ValidParam {

String value();

}

public void update(@ValidParam("id") long id, @ValidParam("name") String name) {

// do something

}

然后在方法执行前,我们可以根据@ValidParam注解的值对参数进行校验。

日志输出

我们可以通过自定义注解来标注一些需要进行日志输出的方法,例如:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Log {

String value();

}

@Log("更新订单状态")

public void updateOrderStatus() {

// do something

}

然后在方法执行时,我们可以根据@Log注解的值来输出相应的日志。

缓存管理

我们可以通过自定义注解来标注一些需要进行缓存的方法,例如:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Cache {

long expire() default 3600; // 缓存失效时间,默认为3600秒

String key() default ""; // 缓存key

}

@Cache(expire = 1800, key = "user_{#id}")

public User getUserById(long id) {

// do something

}

然后在方法执行前,我们可以根据@Cache注解的值来判断是否从缓存中获取数据。

Spring AOP

我们可以通过自定义注解来搭配Spring AOP完成一些需求,例如:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface CheckLogin {

boolean required() default true; // 该接口是否需要登录

}

@CheckLogin

@RequestMapping("/getUserInfo")

public UserInfo getUserInfo() {

// do something

}

然后在AOP切面中,我们可以通过@CheckLogin注解的值来判断是否需要进行登录验证。

完整实例代码

以第一个Log注解为例,让我们来看看怎么把程序跑起来。

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Log {

String value() default "";

}

用idea创建一个maven工程,打开pom.xml,添加spring的aop模块。除此之外,还需要引入Spring IoC容器和AspectJ依赖。

org.springframework

spring-context

5.3.9

org.springframework

spring-aop

5.3.9

org.aspectj

aspectjweaver

1.9.6

Log注解

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@interface Log {

String value();

}

Log切面

@Aspect

public class LogAspect {

@Around("@annotation(com.zhujie.Log)")

public Object log(ProceedingJoinPoint joinPoint) throws Throwable {

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

Method method = signature.getMethod();

Log logAnnotation = method.getAnnotation(Log.class);

if (logAnnotation != null) {

String value = logAnnotation.value();

System.out.println("Log: " + value);

}

return joinPoint.proceed();

}

}

@Around

@Around("@annotation(com.zhujie.Log)")

这个@Around注解中的参数是切点表达式,用来匹配需要被切入的方法。其中"@annotation(com.example.Log)"这部分是一个注解切点,表示需要匹配所有被@Log注解修饰的方法。

具体来说,@Around表示在方法执行前后都执行一段代码,包裹着原本要执行的方法。在执行这段代码时,可以获取到方法和参数的信息,对其进行处理或者记录日志等操作。

@annotation表示对注解的切面,后面跟着注解的类型,比如@annotation(com.zhujie.Log)就是表示对@Log注解的切面。这个切面就是指定了需要拦截所有被@Log注解修饰的方法,用来完成相应的操作。

UserService

@Service

class UserService {

@Log("用户新增")

public void add() {

}

}

给add方法加上了@Log注解,只要add方法一执行,就会打印用户新增。

启动类:

@Configuration

@ComponentScan

@EnableAspectJAutoProxy

public class AppConfig {

@Bean

public LogAspect logAspect() {

return new LogAspect();

}

public static void main(String[] args) {

// 使用Spring上下文来管理Bean

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 获取LogService Bean

UserService userService = context.getBean(UserService.class);

// 调用含有@Log注解的方法

userService.add();

}

}

@ComponentScan注解是用来扫描指定包及其子包下的所有组件,自动将其注入到容器中。但是,对于一些比较特殊的组件,如AOP切面等,需要手动在配置类中将其注入到容器中。

在使用AOP时,有两种方式:一种是使用XML配置来创建切面,另一种是使用注解方式来创建切面。使用注解方式创建切面时,需要在配置类中使用@Bean注解来创建切面实例,并使用@EnableAspectJAutoProxy注解来开启AOP代理支持。

运行AppConfig,效果如预期。