上一篇文章《手把手教你写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注解,在程序启动的时候就能实现自动注册的逻辑。最后按照惯例,附上本案例的源码,登录后即可下载。
还没有评论,来说两句吧...