本文是基于dubbo2.6.0讲解,每个版本不一样,较新的版本可按照官方配置进行配置,如有疑惑最好自行查看相关源码(本文也记录了查看源码的方式)。
官方提供QOS服务详解和相关配置:http://dubbo.apache.org/zh-cn/docs/user/references/qos.html
拿到dubbo服务ip,通过telnet命令远程连接到你的dubbo服务(中间没有任何认证),然后可通过offline和online命令上下线你所有的服务,这种命令的安全性不言而喻,但是它的初衷是方便开发者治理服务,比如某个服务有严重错误,开发者可以直接下线该服务而不影响其它服务(offline支持正则匹配)。从2.6.4/2.7.0以前,QOS服务的远程连接默认是开启的,最新版的没有这种问题。
官方提供的相关配置命令:
dubbo.application.qosEnable=true
dubbo.application.qosPort=33333
dubbo.application.qosAcceptForeignIp=false
但是由于对于dubbo2.6.0不管怎么设置都没用,后面查看源码发现可以通过下面方式进行配置和关闭服务
//引入qos服务类
import com.alibaba.dubbo.qos.server.Server;
public class App {
public static void main(String[] args) {
//配置dubbo.qos.port端口
System.setProperty(Constants.QOS_PORT,"33333");
//配置dubbo.qos.accept.foreign.ip是否关闭远程连接
System.setProperty(Constants.ACCEPT_FOREIGN_IP,"false");
SpringApplication.run(App.class, args);
//关闭QOS服务
Server.getInstance().stop();
}
}
QOS服务类
public class Server {
private static final Logger logger = LoggerFactory.getLogger(Server.class);
private static final Server INSTANCE = new Server();
public static final Server getInstance() {
return INSTANCE;
}
private int port = Integer.parseInt(ConfigUtils.getProperty(Constants.QOS_PORT, Constants.DEFAULT_PORT + ""));
public int getPort() {
return port;
}
private EventLoopGroup boss;
private EventLoopGroup worker;
private Server() {
this.welcome = DubboLogo.dubbo;
}
private String welcome;
private AtomicBoolean hasStarted = new AtomicBoolean();
/**
* welcome message
*/
public void setWelcome(String welcome) {
this.welcome = welcome;
}
/**
* start server, bind port
*/
public void start() throws Throwable {
if (!hasStarted.compareAndSet(false, true)) {
return;
}
boss = new NioEventLoopGroup(0, new DefaultThreadFactory("qos-boss", true));
worker = new NioEventLoopGroup(0, new DefaultThreadFactory("qos-worker", true));
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boss, worker);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
serverBootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new QosProcessHandler(welcome));
}
});
try {
serverBootstrap.bind(port).sync();
logger.info("qos-server bind localhost:" + port);
} catch (Throwable throwable) {
logger.error("qos-server can not bind localhost:" + port, throwable);
throw throwable;
}
}
/**
* close server
*/
public void stop() {
logger.info("qos-server stopped.");
if (boss != null) {
boss.shutdownGracefully();
}
if (worker != null) {
worker.shutdownGracefully();
}
}
}
QOS服务类是通过调用start方法启动的,但是我们也发现它也提供了一个stop方法,所以只要拿到这个类的对象就可以调用stop方法关闭。可以看到Server类使用了单例提供了getInstance方法获取对象,故可以在服务开始后,通过getInstance方法获取对象调用stop方法关闭QOS服务。
public interface Constants {
int DEFAULT_PORT = 22222;
// system property for specifying qos port
String QOS_PORT = "dubbo.qos.port";
String BR_STR = "\r\n";
String CLOSE = "close!";
// system property for whether to accept foreign IP to connect or not
String ACCEPT_FOREIGN_IP = "dubbo.qos.accept.foreign.ip";
}
此类的常量中只有 dubbo.qos.port和dubbo.qos.accept.foreign.ip,故可以了解到dubbo2.6.0中还没有提供参数关闭QOS服务的。其次可以从服务类Server中看到port是通过ConfigUtils.getProperty方法获取的,进入该工具类可以发现是通过System.getProperty(key)获取参数值的,所以application.yml文件的配置没用,只能配置在application.properties文件中,或者在启动类中手动System.setProperty(Constants.ACCEPT_FOREIGN_IP,"false")赋值进去。