集成 SpringBoot Starter
字数: 0 字 时长: 0 分钟
需求分析
前面我们在本地编写了一个消费者模块和一个提供者模块,已经测试 RPC 框架功能完成。但是实际使用仍然不便,需要手动调用代理类创建代理对象,而且消费者和提供者应用启动时都需要手动初始化 RPC。
我们的目标是编写一个 t-rpc-spring-boot-starter
,用户引入后只需要几个注解即可使用 RPC 框架,而无需关心 RPC 是如何运作的。
依赖引入
我们创建一个 t-rpc-spring-boot-starter
模块,引入必要依赖,其中包含我们编写的 t-rpc-core
框架
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.ttdgg</groupId>
<artifactId>t-rpc-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
代码实现
分别创建 3 个注解和 4 个启动类
@EnableRpc
注解
这个注解用来标注在启动类上,表示是否启动 RPC 服务,服务提供者需要开启 needServer
表示需要启动 Netty 服务端
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({RpcInitBootstrap.class, RpcConsumerBootstrap.class, RpcProviderBootstrap.class, RpcServerBootstrap.class})
public @interface EnableRpc {
/**
* 是否需要启动 server
* @return
*/
boolean needServer() default true;
}
@RocReference
注解
这个注解标注在服务引用上,表示这个服务是 RPC 远程服务的引用
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RpcReference {
Class<?> interfaceClass() default void.class;
}
@RpcService
注解
这个注解标注在远程服务实现类上,表示该实现类暴露给 RPC
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RpcService {
/**
* 服务接口类
*/
Class<?> interfaceClass() default void.class;
/**
* 版本
*/
String serviceVersion() default RpcConstant.DEFAULT_SERVICE_VERSION;
}
RpcConsumerBootstrap
启动类
消费者启动类,这个类负责解析 @RpcRefernce
注解,注入相应的代理对象
java
public class RpcConsumerBootstrap implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = bean.getClass();
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field field : declaredFields) {
RpcReference rpcReference = field.getAnnotation(RpcReference.class);
if (rpcReference != null) {
Class<?> interfaceClass = rpcReference.interfaceClass();
if (interfaceClass == void.class) {
interfaceClass = field.getType();
}
field.setAccessible(true);
Object proxyObject = ServiceProxyFactory.getProxy(interfaceClass);
try {
field.set(bean, proxyObject);
field.setAccessible(false);
} catch (IllegalAccessException e) {
throw new RuntimeException("为字段注入代理对象失败",e);
}
}
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
RpcInitBootstrap
启动类
这个类负责在 Spring 初始化时,初始化 RPC 框架配置
java
/**
* Spring 初始化时,初始化 RPC 框架配置
*/
public class RpcInitBootstrap implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata
, BeanDefinitionRegistry registry) {
boolean needServer = (boolean) importingClassMetadata.getAnnotationAttributes(EnableRpc.class.getName())
.get("needServer");
RpcApplication.init();
RpcApplication.getRpcConfig().setNeedServer(needServer);
}
}
RpcProviderBootstrap
启动类
提供者启动类,负责解析 @RpcService
注解,注册提供者对外暴露的服务实现
java
public class RpcProviderBootstrap implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 获取最终目标类(穿透所有代理)
Class<?> beanClass = AopProxyUtils.ultimateTargetClass(bean);
RpcService rpcService = AnnotationUtils.findAnnotation(beanClass, RpcService.class);
if (rpcService != null) {
Class<?> interfaceClass = rpcService.interfaceClass();
if (interfaceClass == void.class) {
interfaceClass = beanClass.getInterfaces()[0];
}
String serviceName = interfaceClass.getName();
System.out.println("开始注册服务: " + serviceName);
LocalRegistry.register(serviceName, beanClass);
final RpcConfig rpcConfig = RpcApplication.getRpcConfig();
RegistryConfig registryConfig = rpcConfig.getRegistryConfig();
Registry registry = RegistryFactory.getInstance(registryConfig.getRegistry());
ServiceMetaInfo serviceMetaInfo = ServiceMetaInfo.builder()
.serviceName(serviceName)
.serviceHost(rpcConfig.getServerHost())
.servicePort(rpcConfig.getServerPort())
.build();
try {
registry.register(serviceMetaInfo);
}catch (Exception e) {
throw new RuntimeException(serviceName + "服务注册失败",e);
}
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
RpcServerBootStrap
启动类
负责在 SpringBoot 启动完毕后,启动 Netty 服务端(注意这里必须等待 SpringBoot 启动完毕,否则 Netty 会阻塞主线程开始监听,导致 SpringBoot 初始化不完全)
java
public class RpcServerBootstrap implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
final RpcConfig rpcConfig = RpcApplication.getRpcConfig();
if (rpcConfig.isNeedServer()) {
System.out.println("开始启动 server");
new NettyTcpServer().doStart(rpcConfig.getServerPort());
}else {
System.out.println("不启动 server");
}
}
}