深度解析xxl-rpc之服务提供者

服务提供者

服务提供者包结构
在这里插入图片描述

启动

大概流程

在这里插入图片描述
XxlRpcService 注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface XxlRpcService {
    /**
     * @return
     */
    String version() default "";
}

可以看出服务提供者注解上就一个version参数,该参数是用来记录服务版本的。
XxlRpcSpringProviderFactory 类
我们在spring中使用的时候曾书写过配置类,该配置类new了一个XxlRpcSpringProviderFactory 对象交给spring管理,该类的作用就是负责 找出带有@XxlRpcService 注解的类,然后进行基本配置与server的启动。

@Configuration
public class XxlRpcProviderConfig {
    private Logger logger = LoggerFactory.getLogger(XxlRpcProviderConfig.class);

    @Value("${xxl-rpc.remoting.port}")
    private int port;  // 对外提供服务的端口

    @Value("${xxl-rpc.registry.zk.zkaddress}")
    private String zkaddress; // zk地址
    
    @Value("${xxl-rpc.registry.zk.zkdigest}")
    private String zkdigest;

    @Value("${xxl-rpc.env}")
    private String env;

    @Bean
    public XxlRpcSpringProviderFactory xxlRpcSpringProviderFactory() {
    	// 创建对象
        XxlRpcSpringProviderFactory providerFactory = new XxlRpcSpringProviderFactory();
        //设置提供服务的端口
        providerFactory.setPort(port);
        if (zkaddress != null) {
        	//设置一些成员  使用哪种注册中心
            providerFactory.setServiceRegistryClass(ZkServiceRegistry.class);
            // 注册中的一些参数
            providerFactory.setServiceRegistryParam(new HashMap<String, String>(){{
                put(Environment.ZK_ADDRESS, zkaddress);
                put(Environment.ZK_DIGEST, zkdigest);
                put(Environment.ENV, env);
            }});
        }
        return providerFactory;
    }

}

接下来具体看下XxlRpcSpringProviderFactory类的继承关系

public class XxlRpcSpringProviderFactory extends XxlRpcProviderFactory implements ApplicationContextAware, InitializingBean,DisposableBean {}

继承了XxlRpcProviderFactory 类 实现了ApplicationContextAware , InitializingBean, DisposableBean 接口


实现ApplicationContextAware 接口,同时也需要重写 setApplicationContext()方法

@Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 去spring 的ioc 容器中查找带有XxlRpcService  注解的所有类
        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(XxlRpcService.class);
        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
            for (Object serviceBean : serviceBeanMap.values()) {
                // valid
                //判断一下看看实现接口了没有
                if (serviceBean.getClass().getInterfaces().length ==0) {
                    throw new XxlRpcException("xxl-rpc, service(XxlRpcService) must inherit interface.");
                }
                // add service
                XxlRpcService xxlRpcService = serviceBean.getClass().getAnnotation(XxlRpcService.class);
                //找到类上有注解    对应接口全类名
                String iface = serviceBean.getClass().getInterfaces()[0].getName();

                // 找到注解上面的版本信息
                String version = xxlRpcService.version();

                super.addService(iface, version, serviceBean);
            }
        }
        // TODO,addServices by api + prop
    }

作者在该方法中 首先通过 ApplicationContext 找到带有@XxlRpcService 的类,然后遍历这些类判断有没有实现接口, 没有抛出异常,接着获取到该类上的@XxlRpcService 注解的信息 拿到版本信息与该接口的全类名,最后调用父类addService 方法。

    private Map<String, Object> serviceData = new HashMap<String, Object>();
	public void addService(String iface, String version, Object serviceBean){
		// 通过一定规则生成key
		String serviceKey = makeServiceKey(iface, version);
		// 将key 与带有注解的对象 存储在map中
		serviceData.put(serviceKey, serviceBean);
		logger.info(">>>>>>>>>>> xxl-rpc, provider factory add service success. serviceKey = {}, serviceBean = {}", serviceKey, serviceBean.getClass());
	}

addService方法主要是将查找出的全类名与版本信息按照一定的规则生成一个key然后将key 与该对象存入map中。
到这ApplicationContextAware 接口已经走完了,作用就是找到提供服务的类,然后存到map中。


XxlRpcSpringProviderFactory 类还实现类 InitializingBean接口 ,重写afterPropertiesSet方法 ,该方法的执行时机是 当设置好类属性的时候

 @Override
    public void afterPropertiesSet() throws Exception {
    	//做准备工作
        this.prepareConfig();
        super.start();
    }

这个afterPropertiesSet 主要是调用了 prepareConfig 方法来进行数据准备与初始化工作, 接着看看这个方法。


    private void prepareConfig(){
	       // prepare config
	     // 请求方式与序列化方式
	    NetEnum netTypeEnum = NetEnum.autoMatch(netType, null);
	    Serializer.SerializeEnum serializeEnum = Serializer.SerializeEnum.match(serialize, null);
	    Serializer serializer = serializeEnum!=null?serializeEnum.getSerializer():null;
	    if (NetUtil.isPortUsed(port)) {
	        throw new XxlRpcException("xxl-rpc provider port["+ port +"] is used.");
	    }
    // init config
        super.initConfig(netTypeEnum, serializer, ip, port, accessToken, serviceRegistryClass, serviceRegistryParam);
}

prepareConfig 方法主要是 请求方式与数据序列化方式找到对应的类(请求方式与序列化方式 是可以在配置类中set的),判断提供服务端口是否被占用,紧接着有调用了父类的 initConfig 方法。

	private NetEnum netType;
	private Serializer serializer;
	private String ip;					// for registry
	private int port = 7080;			// default port
	private String accessToken;
	private Class<? extends ServiceRegistry> serviceRegistryClass;   // 注册中心
	private Map<String, String> serviceRegistryParam;		// 注册中心参数

	public void initConfig(NetEnum netType,
						  Serializer serializer,
						  String ip,
						  int port,
						  String accessToken,
						   Class<? extends ServiceRegistry> serviceRegistryClass,
						  Map<String, String> serviceRegistryParam) {

		this.netType = netType;
		this.serializer = serializer;
		this.ip = ip;
		this.port = port;
		this.accessToken = accessToken;
		this.serviceRegistryClass = serviceRegistryClass;
		this.serviceRegistryParam = serviceRegistryParam;
	}

initConfig 就是将一些配置参数 赋值 给父类的成员。
afterPropertiesSet 方法中还调用了 父类的 start() 方法,我们来看下该方法。

	private Server server;		//  服务器 类  netty   mina  jetty
	private ServiceRegistry serviceRegistry;  // 注册中心  类

	public void start() throws Exception {
		// start server
		server = netType.serverClass.newInstance();

		// 设置启动回调函数
		server.setStartedCallback(new BaseCallback() {		// serviceRegistry started
			@Override
			public void run() throws Exception {
				// start registry
				if (serviceRegistryClass != null) {
					serviceRegistry = serviceRegistryClass.newInstance();
					serviceRegistry.start(serviceRegistryParam);

					if (serviceData.size() > 0) {
						String ipPort = IpUtil.getIpPort(ip, port);
						for (String serviceKey :serviceData.keySet()) {

							// 注册处理
							serviceRegistry.registry(serviceKey, ipPort);
						}
					}
				}
			}
		});

		// 设置停止回调函数
		server.setStopedCallback(new BaseCallback() {		// serviceRegistry stoped
			@Override
			public void run() {
				// stop registry
				if (serviceRegistry != null) {
					if (serviceData.size() > 0) {
						String ipPort = IpUtil.getIpPort(ip, port);
						for (String serviceKey :serviceData.keySet()) {
							serviceRegistry.remove(serviceKey, ipPort);
						}
					}
					serviceRegistry.stop();
				}
			}
		});
		server.start(this);
	}

start方法 主要是 通过请求方式对应到请求server (netty ,jetty, mina)。设置类start的回调函数与stop的回调函数。紧接着这又调用了server的start方法,并把自己传过去。接下来的server 以 netty的server 为例 (NettyServer)。

@Override
	public void start(final XxlRpcProviderFactory xxlRpcProviderFactory) throws Exception {

		thread = new Thread(new Runnable() {
			@Override
			public void run() {

				EventLoopGroup bossGroup = new NioEventLoopGroup();
				EventLoopGroup workerGroup = new NioEventLoopGroup();
				try {
					ServerBootstrap bootstrap = new ServerBootstrap();
					bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
							.childHandler(new ChannelInitializer<SocketChannel>() {
								@Override
								public void initChannel(SocketChannel channel) throws Exception {
									// 设置编码解码
									channel.pipeline()
											.addLast(new NettyDecoder(XxlRpcRequest.class, xxlRpcProviderFactory.getSerializer()))
											.addLast(new NettyEncoder(XxlRpcResponse.class, xxlRpcProviderFactory.getSerializer()))
											.addLast(new NettyServerHandler(xxlRpcProviderFactory));
								}
							})
							.option(ChannelOption.SO_TIMEOUT, 100)
							.option(ChannelOption.SO_BACKLOG, 128)
							.option(ChannelOption.TCP_NODELAY, true)
							.option(ChannelOption.SO_REUSEADDR, true)
							.childOption(ChannelOption.SO_KEEPALIVE, true);
					ChannelFuture future = bootstrap.bind(xxlRpcProviderFactory.getPort()).sync();

                    logger.info(">>>>>>>>>>> xxl-rpc remoting server start success, nettype = {}, port = {}", NettyServer.class.getName(), xxlRpcProviderFactory.getPort());

                    // 回调处理 ,进行注册中心注册
                    onStarted();

					Channel serviceChannel = future.channel().closeFuture().sync().channel();
				} catch (InterruptedException e) {
					logger.error(e.getMessage(), e);
				} finally {
					workerGroup.shutdownGracefully();
					bossGroup.shutdownGracefully();
				}
			}
		});
		// 设置守护线程
		thread.setDaemon(true);
		thread.start();

	}

这个方法通过之前配置的一些参数(端口,编解码方式)启动了netty 服务器,紧接着 调用了 onStarted 方法,这个方法在父类Server 中。

	public void onStarted() {
		if (startedCallback != null) {
			try {
				startedCallback.run();
			} catch (Exception e) {
				logger.error(">>>>>>>>>>> xxl-rpc, server startedCallback error.", e);
			}
		}
	}

onStarted 方法主要是回掉了在 XxlRpcProviderFactory类中start 为server 对象设置的回调函数。 再回头看下该回调函数干了啥。

// 设置启动回调函数
		server.setStartedCallback(new BaseCallback() {		// serviceRegistry started
			@Override
			public void run() throws Exception {
				// start registry
				if (serviceRegistryClass != null) {
					serviceRegistry = serviceRegistryClass.newInstance();
					serviceRegistry.start(serviceRegistryParam);

					if (serviceData.size() > 0) {
						String ipPort = IpUtil.getIpPort(ip, port);
						for (String serviceKey :serviceData.keySet()) {

							// 注册处理
							serviceRegistry.registry(serviceKey, ipPort);
						}
					}
				}
			}
		});

该回调函数主要是对咱们那个存储注解类的map进行遍历,注册到注册中心中。
到这算是启动完成了。


停止

XxlRpcSpringProviderFactory 该类还实现spring的 DisposableBean接口,重写了destroy 方法。该方法执行时机是该实例销毁的时候。

@Override
    public void destroy() throws Exception {
        super.stop();
    }

调用了父类的stop 方法

	public void  stop() throws Exception {
		// stop server
		server.stop();
	}

父类的stop方法又调用了stop。这里同样是使用netty请求方式来(NettyServer)。

	@Override
	public void stop() throws Exception {

        // destroy server
        if (thread!=null && thread.isAlive()) {
            thread.interrupt();
        }
		// 将注册中心上面的服务移除
        onStoped();
        logger.info(">>>>>>>>>>> xxl-rpc remoting server destroy success.");
	}

中断启动时设置的守护线程。调用了父类的onStoped 的方法。父类方法又回调了之前设置的回调方法

	// 设置停止回调函数
		server.setStopedCallback(new BaseCallback() {		// serviceRegistry stoped
			@Override
			public void run() {
				// stop registry
				if (serviceRegistry != null) {
					if (serviceData.size() > 0) {
						String ipPort = IpUtil.getIpPort(ip, port);
						for (String serviceKey :serviceData.keySet()) {
							serviceRegistry.remove(serviceKey, ipPort);
						}
					}
					serviceRegistry.stop();
				}
			}
		});

该回调方法主要是将之前注册到注册中心的服务移除掉。


提供服务

大体流程

在这里插入图片描述
提供服务这块我们以netty进行解析。

channel.pipeline()
											.addLast(new NettyDecoder(XxlRpcRequest.class, xxlRpcProviderFactory.getSerializer()))
											.addLast(new NettyEncoder(XxlRpcResponse.class, xxlRpcProviderFactory.getSerializer()))
											.addLast(new NettyServerHandler(xxlRpcProviderFactory));

在启动的时候设置了channel这么一段处理链。
首先是 NettyDecoder 类,该类继承 ByteToMessageDecoder 而 ByteToMessageDecoder 又是继承 ChannelInboundHandlerAdapter 类的。该类主要是请求来的时候处理数据的(解码)。
NettyDecoder 解码重写decode 方法,会在请求来的时候被调用。

    @Override
    public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() < 4) {
            return;
        }
        in.markReaderIndex();
        int dataLength = in.readInt();
        if (dataLength < 0) {
            ctx.close();
        }
        if (in.readableBytes() < dataLength) {
            in.resetReaderIndex();
            return;	// fix 1024k buffer splice limix
        }
        byte[] data = new byte[dataLength];
        in.readBytes(data);

        Object obj = serializer.deserialize(data, genericClass);
        out.add(obj);
    }

使用之前设置的解码规则 进行解码成对象,然后添加到list中。
然后 又会到 NettyServerHandler类中。执行channelRead0 方法

   @Override
    public void channelRead0(final ChannelHandlerContext ctx, XxlRpcRequest xxlRpcRequest) throws Exception {

        // invoke + response
        XxlRpcResponse xxlRpcResponse = xxlRpcProviderFactory.invokeService(xxlRpcRequest);
    	
        ctx.writeAndFlush(xxlRpcResponse);
    }

该方法通过调用XxlRpcProviderFactory 类的 invokeService 方法来反射调用对应的方法取得结果。

	public XxlRpcResponse invokeService(XxlRpcRequest xxlRpcRequest) {

		//  make response
		XxlRpcResponse xxlRpcResponse = new XxlRpcResponse();
		xxlRpcResponse.setRequestId(xxlRpcRequest.getRequestId());

		// match service bean

		// 从本地找到服务
		String serviceKey = makeServiceKey(xxlRpcRequest.getClassName(), xxlRpcRequest.getVersion());
		Object serviceBean = serviceData.get(serviceKey);

		// valid
		if (serviceBean == null) {
			xxlRpcResponse.setErrorMsg("The serviceKey["+ serviceKey +"] not found.");
			return xxlRpcResponse;
		}
		// 检测超时
		if (System.currentTimeMillis() - xxlRpcRequest.getCreateMillisTime() > 3*60*1000) {
			xxlRpcResponse.setErrorMsg("The timestamp difference between admin and executor exceeds the limit.");
			return xxlRpcResponse;
		}

		// 检测token
		if (accessToken!=null && accessToken.trim().length()>0 && !accessToken.trim().equals(xxlRpcRequest.getAccessToken())) {
			xxlRpcResponse.setErrorMsg("The access token[" + xxlRpcRequest.getAccessToken() + "] is wrong.");
			return xxlRpcResponse;
		}

		// invoke
		try {
			Class<?> serviceClass = serviceBean.getClass();

			// 获取要执行的方法名称
			String methodName = xxlRpcRequest.getMethodName();

			//获取执行方法参数类型
			Class<?>[] parameterTypes = xxlRpcRequest.getParameterTypes();


			// 获取要执行方法参数值
			Object[] parameters = xxlRpcRequest.getParameters();

            Method method = serviceClass.getMethod(methodName, parameterTypes);
            method.setAccessible(true);
			Object result = method.invoke(serviceBean, parameters);

			/*FastClass serviceFastClass = FastClass.create(serviceClass);
			FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);
			Object result = serviceFastMethod.invoke(serviceBean, parameters);*/

			xxlRpcResponse.setResult(result);
		} catch (Throwable t) {
			logger.error("xxl-rpc provider invokeService error.", t);
			xxlRpcResponse.setErrorMsg(ThrowableUtil.toString(t));
		}

		return xxlRpcResponse;
	}

该方法调用请求中带到方法并封装了一个XxlRpcResponse 对象返回。
最后在响应的时候 又经过 NettyEncoder类的 encode 方法进行 编码工作。
NettyEncoder 类是继承MessageToByteEncoder类的,而MessageToByteEncoder 类又继承 ChannelOutboundHandlerAdapter类,该类有个特点就是,在响应的时候会被调用。所以调用了 NettyEncoder类的 encode 方法

  @Override
    public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
        if (genericClass.isInstance(in)) {
            byte[] data = serializer.serialize(in);
            out.writeInt(data.length);
            out.writeBytes(data);
        }
    }

encode 方法主要就是对 XxlRpcResponse 对象进行编码 然后再流转到其他调用者手中。

猜你喜欢

转载自blog.csdn.net/yuanshangshenghuo/article/details/89534834