Dubbo Rest HttpServer分析
2020-02-20 本文已影响0人
晴天哥_王志
TomcatHttpServer
public class TomcatHttpServer extends AbstractHttpServer {
private static final Logger logger = LoggerFactory.getLogger(TomcatHttpServer.class);
private final Tomcat tomcat;
private final URL url;
public TomcatHttpServer(URL url, final HttpHandler handler) {
super(url, handler);
this.url = url;
// 绑定handler到DispatcherServlet对象当中
DispatcherServlet.addHttpHandler(url.getPort(), handler);
String baseDir = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
tomcat = new Tomcat();
// 设置tomcat的目录和端口号
tomcat.setBaseDir(baseDir);
tomcat.setPort(url.getPort());
// 设置tomcat的connector属性
tomcat.getConnector().setProperty(
"maxThreads", String.valueOf(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS)));
tomcat.getConnector().setProperty(
"maxConnections", String.valueOf(url.getParameter(Constants.ACCEPTS_KEY, -1)));
tomcat.getConnector().setProperty("URIEncoding", "UTF-8");
tomcat.getConnector().setProperty("connectionTimeout", "60000");
tomcat.getConnector().setProperty("maxKeepAliveRequests", "-1");
tomcat.getConnector().setProtocol("org.apache.coyote.http11.Http11NioProtocol");
// 设置Context属性
Context context = tomcat.addContext("/", baseDir);
// 绑定dispatcher属性到serverlet当中
Tomcat.addServlet(context, "dispatcher", new DispatcherServlet());
// 设置tomcat的servlet的mapping属性
context.addServletMapping("/*", "dispatcher");
// 添加servletContext到全局的ServletManager当中
ServletManager.getInstance().addServletContext(url.getPort(), context.getServletContext());
try {
// 启动tomcat服务
tomcat.start();
} catch (LifecycleException e) {
throw new IllegalStateException("Failed to start tomcat server at " + url.getAddress(), e);
}
}
}
- 绑定HttpHandler到DispatcherServlet。
- 绑定DispatcherServlet到Tomcat对象。
- 保存Context到ServletManager对象中。
- 启动Tomcat对象。
JettyHttpServer
public class JettyHttpServer extends AbstractHttpServer {
private static final Logger logger = LoggerFactory.getLogger(JettyHttpServer.class);
private Server server;
private URL url;
public JettyHttpServer(URL url, final HttpHandler handler) {
super(url, handler);
this.url = url;
Log.setLog(new StdErrLog());
Log.getLog().setDebugEnabled(false);
// 绑定handler到DispatcherServlet对象当中
DispatcherServlet.addHttpHandler(url.getParameter(Constants.BIND_PORT_KEY, url.getPort()), handler);
// 设置线程属性
int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setDaemon(true);
threadPool.setMaxThreads(threads);
threadPool.setMinThreads(threads);
// 设置connector对象属性
SelectChannelConnector connector = new SelectChannelConnector();
String bindIp = url.getParameter(Constants.BIND_IP_KEY, url.getHost());
if (!url.isAnyHost() && NetUtils.isValidLocalHost(bindIp)) {
connector.setHost(bindIp);
}
connector.setPort(url.getParameter(Constants.BIND_PORT_KEY, url.getPort()));
// 创建server对象并绑定线程池和connector对象
server = new Server();
server.setThreadPool(threadPool);
server.addConnector(connector);
// 绑定servletMapping 到 ServletHandler
ServletHandler servletHandler = new ServletHandler();
ServletHolder servletHolder = servletHandler.addServletWithMapping(DispatcherServlet.class, "/*");
servletHolder.setInitOrder(2);
// 绑定context到server对象并绑定ServletHandler
Context context = new Context(server, "/", Context.SESSIONS);
context.setServletHandler(servletHandler);
// 添加servletContext到全局的ServletManager当中
ServletManager.getInstance().addServletContext(url.getParameter(Constants.BIND_PORT_KEY, url.getPort()), context.getServletContext());
try {
// 启动server
server.start();
} catch (Exception e) {
throw new IllegalStateException("Failed to start jetty server on " + url.getParameter(Constants.BIND_IP_KEY) + ":" + url.getParameter(Constants.BIND_PORT_KEY) + ", cause: "
+ e.getMessage(), e);
}
}
}
- 绑定HttpHandler到DispatcherServlet。
- 绑定DispatcherServlet到Server对象。
- 保存Context到ServletManager对象中。
- 启动Server对象。
DubboHttpServer
public class DubboHttpServer extends BaseRestServer {
//HttpServletDispatcher内包含resteasy的ServletContainerDispatcher
private final HttpServletDispatcher dispatcher = new HttpServletDispatcher();
// resteasy的ResteasyDeployment
private final ResteasyDeployment deployment = new ResteasyDeployment();
private HttpBinder httpBinder; // httpBinderApative
private HttpServer httpServer;
public DubboHttpServer(HttpBinder httpBinder) {
this.httpBinder = httpBinder;
}
@Override
protected void doStart(URL url) {
// 绑定RestHandler到具体的server当中
httpServer = httpBinder.bind(url, new RestHandler());
// 获取serverletContext的上下文信息
ServletContext servletContext = ServletManager.getInstance().getServletContext(url.getPort());
if (servletContext == null) {
servletContext = ServletManager.getInstance().getServletContext(ServletManager.EXTERNAL_SERVER_PORT);
}
if (servletContext == null) {
throw new RpcException("No servlet context found. If you are using server='servlet', " +
"make sure that you've configured " + BootstrapListener.class.getName() + " in web.xml");
}
// 绑定deployment到servletContext当中,
// servletContext为jettyHttpServer或TomcatHttpServer中servletContext
servletContext.setAttribute(ResteasyDeployment.class.getName(), deployment);
try {
// 绑定HttpServer中servletContext到dispatcher当中
dispatcher.init(new SimpleServletConfig(servletContext));
} catch (ServletException e) {
throw new RpcException(e);
}
}
protected ResteasyDeployment getDeployment() {
return deployment;
}
private class RestHandler implements HttpHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
// 执行真正的分发动作,由HttpServletDispatcher执行
dispatcher.service(request, response);
}
}
}
public abstract class BaseRestServer implements RestServer {
@Override
public void start(URL url) {
getDeployment().getMediaTypeMappings().put("json", "application/json");
getDeployment().getMediaTypeMappings().put("xml", "text/xml");
getDeployment().getProviderClasses().add(RpcContextFilter.class.getName());
getDeployment().getProviderClasses().add(RpcExceptionMapper.class.getName());
loadProviders(url.getParameter(Constants.EXTENSION_KEY, ""));
doStart(url);
}
@Override
public void deploy(Class resourceDef, Object resourceInstance, String contextPath) {
if (StringUtils.isEmpty(contextPath)) {
getDeployment().getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef));
} else {
getDeployment().getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef), contextPath);
}
}
}
- DubboHttpServer设置ResteasyDeployment对象。
- ServletManager中获取servletContext对象。
- 绑定servletContext对象到HttpServletDispatcher当中。
- RestHandler中通过HttpServletDispatcher执行分发操作。
- DubboHttpServer的deploy()绑定deployment对象。
RestProtocol
public class RestProtocol extends AbstractProxyProtocol {
private static final int DEFAULT_PORT = 80;
private final Map<String, RestServer> servers = new ConcurrentHashMap<String, RestServer>();
private final RestServerFactory serverFactory = new RestServerFactory();
private final List<ResteasyClient> clients = Collections.synchronizedList(new LinkedList<ResteasyClient>());
private volatile ConnectionMonitor connectionMonitor;
@Override
protected <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException {
String addr = getAddr(url);
Class implClass = (Class) StaticContext.getContext(Constants.SERVICE_IMPL_CLASS).get(url.getServiceKey());
RestServer server = servers.get(addr);
if (server == null) {
server = serverFactory.createServer(url.getParameter(Constants.SERVER_KEY, "jetty"));
server.start(url);
servers.put(addr, server);
}
String contextPath = getContextPath(url);
if ("servlet".equalsIgnoreCase(url.getParameter(Constants.SERVER_KEY, "jetty"))) {
ServletContext servletContext = ServletManager.getInstance().getServletContext(ServletManager.EXTERNAL_SERVER_PORT);
if (servletContext == null) {
throw new RpcException("No servlet context found. Since you are using server='servlet', " +
"make sure that you've configured " + BootstrapListener.class.getName() + " in web.xml");
}
String webappPath = servletContext.getContextPath();
if (StringUtils.isNotEmpty(webappPath)) {
webappPath = webappPath.substring(1);
if (!contextPath.startsWith(webappPath)) {
throw new RpcException("Since you are using server='servlet', " +
"make sure that the 'contextpath' property starts with the path of external webapp");
}
contextPath = contextPath.substring(webappPath.length());
if (contextPath.startsWith("/")) {
contextPath = contextPath.substring(1);
}
}
}
final Class resourceDef = GetRestful.getRootResourceClass(implClass) != null ? implClass : type;
// 部署对应的impl对象到server当中
server.deploy(resourceDef, impl, contextPath);
final RestServer s = server;
return new Runnable() {
@Override
public void run() {
// TODO due to dubbo's current architecture,
// it will be called from registry protocol in the shutdown process and won't appear in logs
s.undeploy(resourceDef);
}
};
}
}
- RestProtocol负责启动HttpServer对象。
- RestProtocol负责部署信息到deployment当中。