@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(){{
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 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 serviceData = new HashMap();
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 serviceRegistryParam; // 注册中心参数
public void initConfig(NetEnum netType,
Serializer serializer,
String ip,
int port,
String accessToken,
Class extends ServiceRegistry> serviceRegistryClass,
Map 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() {
@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();
}
}
});
该回调方法主要是将之前注册到注册中心的服务移除掉。
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
使用之前设置的解码规则 进行解码成对象,然后添加到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 对象进行编码 然后再流转到其他调用者手中。