上一篇文章《手把手教你写rpc框架系列(六)实现本地向zookeeper注册自身服务》我们实现了注册到zookeeper的工具类,在真实的业务中,我们肯定是不需要写很多代码,更希望在业务中添加一个注解就实现当前服务自动向zookeeper上注册。因此这里的话,我们需要编写下注解相关的逻辑。
首先我们自定义一个RPCService的注解,完整代码如下:
package org.wz.rpc.framework.anotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.stereotype.Component; /** * 被该注解标记的服务可提供远程RPC访问的能力,这个注解一般应用于provider上面的service,也就是serviceimpl * */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface RPCService { String value() default ""; }
那么这个注解怎么使用呢?这里的话,我们使用configuration来进行配置,首先我们创建一个AutoConfiguration类,然后添加上@Configuration这个注解,示例图如下:
在真实的业务中,我们一般会涉及到配置zookeeper等信息,把这些信息配置到配置文件中去,因此这里的话,我们首先定义下配置文件的格式,格式如下:
wz.rpc.register-address=192.168.31.218:2181 wz.rpc.server-port=18000
定义了配置格式之后,我们就需要读取配置文件,所以这里我们需要创建一个读取这个配置的配置文件,完整代码示例如下:
package org.wz.rpc.framework.register.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* 参数配置类,实现用户自定义参数
*
*/
@EnableConfigurationProperties(RpcRegisterProperty.class)
@ConfigurationProperties("wz.rpc")
public class RpcRegisterProperty {
/**
* 服务注册中心
*/
private String registerAddress = "127.0.0.1:2181";
/**
* 服务端暴露端口
*/
private Integer serverPort = 19000;
/**
* 服务协议
*/
private String protocol = "wz-rpc";
public String getRegisterAddress() {
return registerAddress;
}
public void setRegisterAddress(String registerAddress) {
this.registerAddress = registerAddress;
}
public Integer getServerPort() {
return serverPort;
}
public void setServerPort(Integer serverPort) {
this.serverPort = serverPort;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
}在这个配置文件中,我们配置了一些默认的配置,也就是当我们没有在配置文件中配置的话,就给一个默认的配置,避免启动报错。
然后我们在AutoConfiguration类里面实例化一下一个配置文件即可,代码示例如下:
@Bean
public RpcRegisterProperty rpcProperty() {
return new RpcRegisterProperty();
}现在配置文件也有了,我们需要实例化ZookeeperServiceRegister类,这个类的实例化其实主要是做的把配置文件的配置读取进去,然后初始化一个zookeeper客户端,所以我们继续在AutoConfiguration类中实例化这个ZookeeperServiceRegister,代码示例如下:
@Bean
public ServiceRegister serviceRegister(@Autowired RpcRegisterProperty property) {
log.info("configuration 准备注册服务");
return new ZookeeperServiceRegister(property.getRegisterAddress(), property.getServerPort(),
property.getProtocol());
}以上我们的工具类实例化了之后,我们接着继续考虑,既然是注册服务,那么服务肯定是动态的,所以我们需要去执行ZookeeperServiceRegister类里面的register方法。那这块怎么做呢?其实很简单,我们使用反射即可。所以我们需要编写一个类,干以下几个事情:
1、检测程序的启动 2、根据反射获取到对应的服务名 3、把服务名等参数组装一下,传递给ZookeeperServiceRegister的register方法。
所以我们依次来,首先创建一个名为DefaultRpcProcessor的类,这个因为要获取程序启动的context,因此必须实现ApplicationListener这个接口,因此这个类的示例代码如下:
public class DefaultRpcProcessor implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {}
}在这个类里面,我们需要来实现这个onApplicationEvent的方法,里面主要做的就是:
获取context 反射获取服务名 注册服务到zookeeper中
首先我们获取context这个比较简单,使用如下的代码即可:
if (Objects.isNull(event.getApplicationContext().getParent())) {
ApplicationContext context = event.getApplicationContext();
}然后反射获取的服务名及调用register方法
Map<String, Object> beans = context.getBeansWithAnnotation(RPCService.class);
if (beans.size() != 0) {
for (Object obj : beans.values()) {
try {
Class<?> clazz = obj.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
ServiceObject so;
if (interfaces.length != 1) {
RPCService service = clazz.getAnnotation(RPCService.class);
String value = service.value();
if (value.equals("")) {
throw new Exception("The exposed interface is not specific with '" + obj.getClass().getName() + "'");
}
so = new ServiceObject(value, Class.forName(value), obj);
} else {
Class<?> superClass = interfaces[0];
so = new ServiceObject(superClass.getName(), superClass, obj);
}
serviceRegister.register(so);
} catch (Exception e) {
log.error(e.getMessage(),e);
}
}
}这个方法主要的含义就是:
获取带有RPCServer这个注解的类。 反射获取这个类的类名 然后把这个类名做成服务名 拼接整个serviceobject信息 使用serviceobject调用register方法注册即可。
以上我们就实现了一个只需要添加@RPCServer注解,在程序启动的时候就能实现自动注册的逻辑。最后按照惯例,附上本案例的源码,登录后即可下载。


还没有评论,来说两句吧...