Java注解怎么用
创始人
2025-05-31 17:12:11
0

什么是注解

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.springframeworkspring-context5.3.9
org.springframeworkspring-aop5.3.9
org.aspectjaspectjweaver1.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 {@Beanpublic LogAspect logAspect() {return new LogAspect();}public static void main(String[] args) {// 使用Spring上下文来管理BeanApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取LogService BeanUserService userService = context.getBean(UserService.class);// 调用含有@Log注解的方法userService.add();}
}

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

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

运行AppConfig,效果如预期。

 

相关内容

热门资讯

官高爵显的近义词 官高爵显的近义词有:高官显爵,官高爵显[guān gāo jué xiǎn]的意思:爵:爵位,官爵;...
切要关头的近义词 切要关头的近义词有:紧要关头,切要关头[qiè yào guān tóu]的意思:关头:关口。比喻有...
面面俱到,面面俱到的意思,面... 面面俱到miàn miàn jù dào [释义]俱:都。各方面都照顾到。也指虽然各方面都照顾...
人单势孤的近义词 人单势孤的近义词有:势单力薄,人单势孤[rén dān shì gū]的意思:人数少,力量单薄。出自...
间断的近义词   一、【近义词】  中断、中止、拆开、休止  二、【基本解释】  [释义](动)(连续的事情)中间...
乡壁虚造的近义词 乡壁虚造的近义词有:凭空捏造,无中生有,面壁虚构,乡壁虚造[xiāng bì xū zào]的意思:...
盎盂相敲的近义词 盎盂相敲的近义词有:盎盂相击,盎盂相敲[àng yú xiāng qiāo]的意思:比喻一家人争吵。...
高枕而卧的近义词 高枕而卧的近义词有:无忧无虑,高枕安卧,高枕安寝,高枕无忧,高枕而卧[gāo zhěn ér wò]...
破题儿第一遭的近义词 破题儿第一遭的近义词有:破题儿,破题儿头一遭,破题儿第一遭[pò tí ér dì yī zāo]的...
如堕烟海的近义词 如堕烟海的近义词有:如坐云雾,如堕烟雾,雾里看花,如堕烟海[rú duò yān hǎi]的意思:好...
雁杳鱼沉的近义词 雁杳鱼沉的近义词有:信断音绝,雁断鱼沉,雁逝鱼沉,雁杳鱼沉[yàn yǎo yú chén]的意思:...
汪洋大海的近义词 汪洋大海的近义词有:东洋大海,声势浩大,波澜壮阔,汪洋大海[wāng yáng dà hǎi]的意思...
明效大验的近义词 明效大验的近义词有:明验大效,明效大验[míng xiào dà yà]的意思:显著而又巨大的效验。...
难乎为继的近义词 难乎为继的近义词有:难以为继,难乎为继[nán hū wéi jì]的意思:难于继续下去。出自:清 ...
在所难免的近义词 在所难免的近义词有:在劫难逃,在所不免,在所无免,在所难免[zài suǒ nán miǎn]的意思...
恨入心髓的近义词 恨入心髓的近义词有:恨之入骨,恨之切骨,恨入骨髓,恨入心髓[hèn rù xīn suǐ]的意思:恨...
富翁的近义词 富翁的近义词  近义词:  大亨、财主  大亨:大亨 dàhēng[magnate;big wig;...
背本就末的近义词 背本就末的近义词有:背本趋末,背本逐末,背本就末[bèi běn jiù mò]的意思:指背离根本,...
问牛知马的近义词 问牛知马的近义词有:举一反三,触类旁通,问羊知马,闻一知十,问牛知马[wèn niú zhī mǎ]...
不通文墨的近义词 不通文墨的近义词有:不识之无,胸无点墨,不通文墨[bù tōng wén mò]的意思:通:精通;文...