你该学会自己写 Java 注解了

开发 前端
相信大家也发现了,注解类定义好之后并不能立马生效,比如在一个类上添加注解@ServiceReference,我们期望服务启动后这个类能自动暴露自己,但是你会发现什么也没发生,这是为什么呢?

​我们通过Hello World这个例子引入了RPC 框架,知道了客户端要想调用服务端需要靠两个注解来实现,下面我们一起来实现这两个注解。

注解相关的实现代码是 RPC 框架的核心代码,后面写完后可以打包成一个 jar 包作为框架供业务代码中使用,这样我们前面写的客户端和服务端 demo 就可以正常工作了。

好了,铺垫这么多,我们真正开始写 RPC 框架代码了。RPC 框架计划提供两个注解:

  • @ServiceReference
  • @ServiceExpose

@ServiceReference

@ServiceReference​注解用来引用服务端提供的服务,客户端启动后可以自动注入对应的bean,像调用本地方法一样调用远程服务的方法。

首先,我们来定义一个注解类,interface​关键字用来声明接口,前面加一个@​就可以用来定义注解类,如上面约定客户端侧注解名为:ServiceReference。

public @interface ServiceReference {
}

注解类还可以加很多配置项,一般用几个元注解进行修饰:

@Target​表示我们定义的这个注解使用的范围,ElementType​是枚举类有很多枚举值,这里我们只用到ElementType.FIELD,业务含义:当前这个自定义注解只能在类的成员变量上使用。

@Retention​表示注解的保留策略,RetentionPolicy.RUNTIME​的意思是希望注解能一直保留到运行期,那为什么要保留到运行期呢?因为我们希望在运行期通过这个注解自动注入依赖。如果取值为RetentionPolicy.SOURCE则表示仅保存在源码中,在代码编译后就会丢掉这个注解的信息。

@Documented与文档相关的,没有其他业务含义,这里不再赘述。

一个完整的注解类详细代码如下:


@Target({ElementType.FIELD})
// 注解保留策略
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceReference {
}

注解已经定义好了,代码非常简单,使用起来也比较简单,在类的成员变量上加一个这样的注解即可:

class A {
@ServiceReference
private XxxService xxxService;

……省略
}

可能有小伙伴要问了,为什么加一个简单的注解就能将远程服务的依赖注入进来?这其实是框架背后的功劳,服务启动后会自动扫描框架的注解,根据不同的注解框架会有对应的初始化动作,至于@ServiceReference的初始化逻辑我们下一个小节再详细展开讲。

下面接着看另外一个注解。

@ServiceExpose

@ServiceExpose注解用于服务端暴露自己的服务接口(方法),进而可被客户端发现调用。

与@ServiceReference​类似,定义一个注解,取名叫做:ServiceExpose。

public @interface ServiceExpose {
}

与@ServiceReference​稍微有点不同的是,多增加了一个元注解:@Component​以及@Target取值不一样。

@Component是Spring​原生的注解,Spring​启动后会扫描注解并将其初始化一个bean​,用于配合@ServiceExpose注解使用,具体逻辑后面章节会详细介绍。

@Target​用于约束注解的使用范围,ElementType.TYPE表示当前这个注解仅可在类(class)、接口(interface)、枚举(enum)类上使用,在其他地方使用是非法的,会编译失败。

完整的代码如下:

// 元注解,Spring 原生注解
@Component
// 约束注解使用范围
@Target({ElementType.TYPE})
// 注解保留策略
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceExpose {
}

代码结构

在前面搭建环境时创建了一个maven​工程,我们继续在工程中创建一个 package并取名为:annotation,刚才写完的两个注解类代码放进去。

目前框架的代码结构如下:

├── easy-rpc-spring-boot-starter
│ ├── pom.xml
│ ├── src
│ │ └── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── leixiaoshuai
│ │ │ └── easyrpc
│ │ │ ├── annotation
│ │ │ │ ├── ServiceExpose.java
│ │ │ │ └── ServiceReference.java
│ │ └── resources

小结

前面带领大家写完了框架中核心的两个注解类:@ServiceReference​ 和 @ServiceExpose​,客户端常使用@ServiceReference​引用服务端;服务端常使用@ServiceExpose暴露自身的服务便于客户端发现和使用。

定义注解的步骤非常简单:

  • 使用@interface声明注解类
  • 注解类前面添加元注解,如:@Target、@Retention等

相信大家也发现了,注解类定义好之后并不能立马生效,比如在一个类上添加注解@ServiceReference,我们期望服务启动后这个类能自动暴露自己,但是你会发现什么也没发生,这是为什么呢?

其实注解仅仅只是一种标记的手段,自身并无业务逻辑,如果你希望注解实现预期效果,需要自己去写一段驱动代码,代码中可以通过反射方式扫描所有添加了注解的地方,然后执行对应的逻辑,至于什么时候执行这段驱动代码,需要结合注解的保留策略,一般是编译或者运行中执行。

明白了这个道理之后,要想使@ServiceReference​ 和 @ServiceExpose这两个注解实现对应的功能,需要分别写一段驱动程序,这段代码在后续的章节会详细介绍,我们接着往下看。

责任编辑:武晓燕 来源: 爱笑的架构师
相关推荐

2020-03-06 10:25:10

注解Java代码

2024-01-18 09:38:00

Java注解JDK5

2021-03-29 09:37:17

SpringBoot常用注解Spring Boot

2022-11-11 08:29:24

C语言中文字符代码

2022-12-22 08:14:54

2023-09-22 08:01:10

2023-11-02 16:51:07

Python代码

2024-01-19 08:25:38

死锁Java通信

2012-02-09 10:42:24

Java

2014-08-13 11:20:10

创业者

2024-01-29 07:43:42

Java独占锁共享锁

2021-11-22 23:42:02

Go监控程序

2019-12-23 14:32:38

Java内部类代码

2012-11-30 11:19:02

JavaScript

2024-03-15 08:23:26

异步编程函数

2023-11-06 17:37:17

技术架构任务队列

2018-03-21 16:19:40

MVCMVPMVVM

2024-06-12 00:00:00

2023-11-27 07:33:55

2023-01-28 09:50:17

java多线程代码
点赞
收藏

51CTO技术栈公众号