我们继续围绕Netty手写实现RPC基础篇进行优化,主要引入几个点
- 集成spring,实现注解驱动配置
- 集成zookeeper,实现服务注册
- 增加负载均衡实现
增加注解驱动#
主要涉及到的修改模块
- netty-rpc-protocol
- netty-rpc-provider
netty-rpc-protocol#
当前模块主要修改的类如下。
图7-1
下面针对netty-rpc-protocol模块的修改如下
增加注解驱动#
这个注解的作用是用来指定某些服务为远程服务
@Target(ElementType.TYPE)// Target说明了Annotation所修饰的对象范围, TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention(RetentionPolicy.RUNTIME)// Reteniton的作用是定义被它所注解的注解保留多久,保留至运行时。所以我们可以通过反射去获取注解信息。
@Component
public @interface GpRemoteService {
}
SpringRpcProviderBean#
这个类主要用来在启动NettyServer,以及保存bean的映射关系
@Slf4j
public class SpringRpcProviderBean implements InitializingBean, BeanPostProcessor {
private final int serverPort;
private final String serverAddress;
public SpringRpcProviderBean(int serverPort) throws UnknownHostException {
this.serverPort = serverPort;
InetAddress address=InetAddress.getLocalHost();
this.serverAddress=address.getHostAddress();
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("begin deploy Netty Server to host {},on port {}",this.serverAddress,this.serverPort);
new Thread(()->{
try {
new NettyServer(this.serverAddress,this.serverPort).startNettyServer();
} catch (Exception e) {
log.error("start Netty Server Occur Exception,",e);
e.printStackTrace();
}
}).start();
}
//bean实例化后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean.getClass().isAnnotationPresent(GpRemoteService.class)){ //针对存在该注解的服务进行发布
Method[] methods=bean.getClass().getDeclaredMethods();
for(Method method: methods){ //保存需要发布的bean的映射
String key=bean.getClass().getInterfaces()[0].getName()+"."+method.getName();
BeanMethod beanMethod=new BeanMethod();
beanMethod.setBean(bean);
beanMethod.setMethod(method);
Mediator.beanMethodMap.put(key,beanMethod);
}
}
return bean;
}
}
Mediator#
主要管理bean以及调用
BeanMethod#
@Data
public class BeanMethod {
private Object bean;
private Method method;
}
Mediator#
负责持有发布bean的管理,以及bean的反射调用
public class Mediator {
public static Map<String,BeanMethod> beanMethodMap=new ConcurrentHashMap<>();
private volatile static Mediator instance=null;
private Mediator(){
}
public static Mediator getInstance(){
if(instance==null){
synchronized (Mediator.class){
if(instance==null){
instance=new Mediator();
}
}
}
return instance;
}
public Object processor(RpcRequest rpcRequest){
String key=rpcRequest.getClassName()+"."+rpcRequest.getMethodName();
BeanMethod beanMethod=beanMethodMap.get(key);
if(beanMethod==null){
return null;
}
Object bean=beanMethod.getBean();
Method method=beanMethod.getMethod();
try {
return method.invoke(bean,rpcRequest.getParams());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
RpcServerProperties#
定义配置属性
@Data
@ConfigurationProperties(prefix = "gp.rpc")
public class RpcServerProperties {
private int servicePort;
}
RpcProviderAutoConfiguration#
定义自动配置类
@Configuration
@EnableConfigurationProperties(RpcServerProperties.class)
public class RpcProviderAutoConfiguration {
@Bean
public SpringRpcProviderBean rpcProviderBean(RpcServerProperties rpcServerProperties) throws UnknownHostException {
return new SpringRpcProviderBean(rpcServerProperties.getServicePort());
}
}
修改RpcServerHandler#
修改调用方式,直接使用Mediator的调用即可。
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, RpcProtocol<RpcRequest> msg) throws Exception {
RpcProtocol resProtocol=new RpcProtocol<>();
Header header=msg.getHeader();
header.setReqType(ReqType.RESPONSE.code());
Object result=Mediator.getInstance().processor(msg.getContent()); //主要修改这个部分
resProtocol.setHeader(header);
RpcResponse response=new RpcResponse();
response.setData(result);
response.setMsg("success");
resProtocol.setContent(response);
ctx.writeAndFlush(resProtocol);
}
}
netty-rpc-provider#
这个模块中主要修改两个部分
- application.properties
- NettyRpcProviderMain
NettyRpcProviderMain#
@ComponentScan(basePackages = {"com.example.spring.annotation","com.example.spring.service","com.example.service"})
@SpringBootApplication
public class NettyRpcProviderMain {
public static void main(String[] args) throws Exception {
SpringApplication.run(NettyRpcProviderMain.class, args);
//去掉原来的实例化部分
}
}
application.properties#
增加一个配置属性。
gp.rpc.servicePort=20880
UserServiceImpl#
把当前服务发布出去。
@GpRemoteService //表示将当前服务发布成远程服务
@Slf4j
public class UserServiceImp