Merge pull request #49 from wolfboys/dev

tomcat support and clean code
This commit is contained in:
Wendal Chen 2017-12-12 13:22:04 +08:00 committed by GitHub
commit 36883175b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 380 additions and 196 deletions

View File

@ -36,6 +36,8 @@ import org.nutz.boot.starter.WebFilterFace;
import org.nutz.boot.starter.WebServletFace; import org.nutz.boot.starter.WebServletFace;
import org.nutz.ioc.Ioc; import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy; import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang; import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.LifeCycle; import org.nutz.lang.util.LifeCycle;
@ -43,6 +45,7 @@ import org.nutz.log.Log;
import org.nutz.log.Logs; import org.nutz.log.Logs;
import org.nutz.resource.Scans; import org.nutz.resource.Scans;
@IocBean
public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, LifeCycle, AppContextAware { public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, LifeCycle, AppContextAware {
private static final Log log = Logs.get(); private static final Log log = Logs.get();
@ -67,6 +70,9 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
@PropDoc(group = "web", value = "过滤器顺序", defaultValue = "whale,druid,shiro,nutz") @PropDoc(group = "web", value = "过滤器顺序", defaultValue = "whale,druid,shiro,nutz")
public static final String PROP_WEB_FILTERS_ORDER = "web.filters.order"; public static final String PROP_WEB_FILTERS_ORDER = "web.filters.order";
@Inject
private PropertiesProxy conf;
protected Server server; protected Server server;
protected ClassLoader classLoader; protected ClassLoader classLoader;
protected Ioc ioc; protected Ioc ioc;
@ -103,34 +109,36 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
} }
public void init() throws Exception { public void init() throws Exception {
// copy and modify from nutz-web
// 创建基础服务器 // 创建基础服务器
server = new Server(new QueuedThreadPool(Lang.isAndroid ? 50 : 500)); server = new Server(new QueuedThreadPool(getMaxThread()));
ServerConnector connector = new ServerConnector(server); ServerConnector connector = new ServerConnector(server);
PropertiesProxy conf = appContext.getConfigureLoader().get(); PropertiesProxy conf = appContext.getConfigureLoader().get();
connector.setHost(conf.get(PROP_HOST, "0.0.0.0")); connector.setHost(getHost());
connector.setPort(conf.getInt(PROP_PORT, 8080)); connector.setPort(getPort());
connector.setIdleTimeout(conf.getInt(PROP_IDLE_TIMEOUT, 300*1000)); connector.setIdleTimeout(getIdleTimeout());
server.setConnectors(new Connector[]{connector}); server.setConnectors(new Connector[]{connector});
// 设置应用上下文 // 设置应用上下文
wac = new WebAppContext(); wac = new WebAppContext();
wac.setContextPath(conf.get(PROP_CONTEXT_PATH, "/")); wac.setContextPath(getContextPath());
//wac.setExtractWAR(false); //wac.setExtractWAR(false);
//wac.setCopyWebInf(true); //wac.setCopyWebInf(true);
//wac.setProtectedTargets(new String[]{"/java", "/javax", "/org", "/net", "/WEB-INF", "/META-INF"}); //wac.setProtectedTargets(new String[]{"/java", "/javax", "/org", "/net", "/WEB-INF", "/META-INF"});
wac.setTempDirectory(new File("./tmp").getAbsoluteFile()); wac.setTempDirectory(createTempDir("jetty").getAbsoluteFile());
wac.setClassLoader(classLoader); wac.setClassLoader(classLoader);
wac.setConfigurationDiscovered(true); wac.setConfigurationDiscovered(true);
if (System.getProperty("os.name").toLowerCase().contains("windows")) { if (System.getProperty("os.name").toLowerCase().contains("windows")) {
wac.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false"); wac.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");
} }
List<Resource> resources = new ArrayList<>(); List<Resource> resources = new ArrayList<>();
for (String resourcePath : Arrays.asList("static/", "webapp/")) { for (String resourcePath : Arrays.asList("static/", "webapp/")) {
File f = new File(resourcePath); File f = new File(resourcePath);
if (f.exists()) if (f.exists()) {
resources.add(Resource.newResource(f)); resources.add(Resource.newResource(f));
}
Enumeration<URL> urls = appContext.getClassLoader().getResources(resourcePath); Enumeration<URL> urls = appContext.getClassLoader().getResources(resourcePath);
while (urls.hasMoreElements()) { while (urls.hasMoreElements()) {
resources.add(Resource.newResource(urls.nextElement())); resources.add(Resource.newResource(urls.nextElement()));
@ -156,7 +164,7 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
wac.getServletContext().setExtendedListenerTypes(true); wac.getServletContext().setExtendedListenerTypes(true);
// 设置一下额外的东西 // 设置一下额外的东西
server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize", conf.getInt(PROP_MAX_FORM_CONTENT_SIZE, 1024*1024*1024)); server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize", getMaxFormContentSize());
server.setDumpAfterStart(false); server.setDumpAfterStart(false);
server.setDumpBeforeStop(false); server.setDumpBeforeStop(false);
server.setStopAtShutdown(true); server.setStopAtShutdown(true);
@ -168,7 +176,10 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
} }
} }
// 添加其他starter提供的WebXXXX服务 addNutzSupport();
}
private void addNutzSupport() {
Map<String, WebFilterFace> filters = new HashMap<>(); Map<String, WebFilterFace> filters = new HashMap<>();
for (Object object : appContext.getStarters()) { for (Object object : appContext.getStarters()) {
if (object instanceof WebFilterFace) { if (object instanceof WebFilterFace) {
@ -177,8 +188,9 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
} }
if (object instanceof WebServletFace) { if (object instanceof WebServletFace) {
WebServletFace webServlet = (WebServletFace) object; WebServletFace webServlet = (WebServletFace) object;
if (webServlet.getServlet() == null) if (webServlet.getServlet() == null) {
continue; continue;
}
ServletHolder holder = new ServletHolder(webServlet.getServlet()); ServletHolder holder = new ServletHolder(webServlet.getServlet());
holder.setName(webServlet.getName()); holder.setName(webServlet.getName());
holder.setInitParameters(webServlet.getInitParameters()); holder.setInitParameters(webServlet.getInitParameters());
@ -186,18 +198,13 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
} }
if (object instanceof WebEventListenerFace) { if (object instanceof WebEventListenerFace) {
WebEventListenerFace contextListener = (WebEventListenerFace) object; WebEventListenerFace contextListener = (WebEventListenerFace) object;
if (contextListener.getEventListener() == null) if (contextListener.getEventListener() != null) {
continue;
wac.addEventListener(contextListener.getEventListener()); wac.addEventListener(contextListener.getEventListener());
} }
} }
String _filterOrders = conf.get(PROP_WEB_FILTERS_ORDER);
if (_filterOrders == null)
_filterOrders = "whale,druid,shiro,nutz";
else if (_filterOrders.endsWith("+")) {
_filterOrders = _filterOrders.substring(0, _filterOrders.length() - 1) + ",whale,druid,shiro,nutz";
} }
String[] filterOrders = Strings.splitIgnoreBlank(_filterOrders);
String[] filterOrders = Strings.splitIgnoreBlank(getWebFiltersOrder());
for (String filterName : filterOrders) { for (String filterName : filterOrders) {
addFilter(filters.remove(filterName)); addFilter(filters.remove(filterName));
} }
@ -207,8 +214,9 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
} }
public void addFilter(WebFilterFace webFilter) { public void addFilter(WebFilterFace webFilter) {
if (webFilter == null || webFilter.getFilter() == null) if (webFilter == null || webFilter.getFilter() == null) {
return; return;
}
log.debugf("add filter name=%s pathSpec=%s", webFilter.getName(), webFilter.getPathSpec()); log.debugf("add filter name=%s pathSpec=%s", webFilter.getName(), webFilter.getPathSpec());
FilterHolder holder = new FilterHolder(webFilter.getFilter()); FilterHolder holder = new FilterHolder(webFilter.getFilter());
holder.setName(webFilter.getName()); holder.setName(webFilter.getName());
@ -222,4 +230,51 @@ public class JettyStarter implements ClassLoaderAware, IocAware, ServerFace, Lif
public void depose() throws Exception { public void depose() throws Exception {
} }
private File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
} catch (IOException ex) {
throw new RuntimeException(
"Unable to create tempDir. java.io.tmpdir is set to "
+ System.getProperty("java.io.tmpdir"),
ex);
}
}
// --getConf---
public int getPort() {
return conf.getInt(PROP_PORT, 8080);
}
public String getHost() {
return conf.get(PROP_HOST, "0.0.0.0");
}
public int getMaxFormContentSize() {
return conf.getInt(PROP_MAX_FORM_CONTENT_SIZE, 1024 * 1024 * 1024);
}
public String getWebFiltersOrder() {
String filterOrder = conf.get(PROP_WEB_FILTERS_ORDER);
return filterOrder == null
? "whale,druid,shiro,nutz"
: filterOrder.replaceFirst("\\+$", ",whale,druid,shiro,nutz");
}
public String getContextPath() {
return conf.get(PROP_CONTEXT_PATH, "/");
}
public int getIdleTimeout() {
return conf.getInt(PROP_IDLE_TIMEOUT, 300 * 1000);
}
public int getMaxThread() {
return Lang.isAndroid ? 50 : 500;
}
} }

View File

@ -78,15 +78,11 @@
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId> <artifactId>tomcat-embed-websocket</artifactId>
</dependency> </dependency>
<!--tomcat end--> <!--tomcat end-->
<dependency> <dependency>
<groupId>org.nutz</groupId> <groupId>org.nutz</groupId>

View File

@ -1,13 +1,16 @@
package org.nutz.boot.starter.tomcat; package org.nutz.boot.starter.tomcat;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.catalina.Host; import org.apache.catalina.*;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector; import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardThreadExecutor; import org.apache.catalina.core.StandardThreadExecutor;
@ -25,14 +28,21 @@ import org.nutz.boot.starter.WebServletFace;
import org.nutz.ioc.impl.PropertiesProxy; import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Files;
import org.nutz.lang.Lang; import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.LifeCycle; import org.nutz.lang.util.LifeCycle;
import org.nutz.log.Log; import org.nutz.log.Log;
import org.nutz.log.Logs; import org.nutz.log.Logs;
import javax.servlet.ServletContext;
/** /**
* tomcat 启动器 * tomcat 启动器
* <p>
* 十步杀一人 千里不留行
* 事了扶衣去 深藏功与名
* </p>
* *
* @author benjobs (benjobs@qq.com) * @author benjobs (benjobs@qq.com)
* @author wendal (wendal1985@gmail.com) * @author wendal (wendal1985@gmail.com)
@ -59,32 +69,45 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
@PropDoc(group = "tomcat", value = "过滤器顺序", defaultValue = "whale,druid,shiro,nutz") @PropDoc(group = "tomcat", value = "过滤器顺序", defaultValue = "whale,druid,shiro,nutz")
public static final String PROP_WEB_FILTERS_ORDER = "web.filters.order"; public static final String PROP_WEB_FILTERS_ORDER = "web.filters.order";
@PropDoc(group = "tomcat", value = "静态文件路径", defaultValue = "/static/") @PropDoc(group = "tomcat", value = "静态文件路径", defaultValue = "static")
public static final String PROP_STATIC_PATH = PRE + "staticPath"; public static final String PROP_STATIC_PATH = PRE + "staticPath";
public static final String PROP_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol"; private static final String PROP_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
private static final Charset DEFAULT_CHARSET = Charset.forName("utf-8");
@Inject
private PropertiesProxy conf;
protected Tomcat tomcat; protected Tomcat tomcat;
protected StandardContext tomcatContext; protected StandardContext tomcatContext;
protected ClassLoader classLoader; protected ClassLoader classLoader;
protected AppContext appContext; protected AppContext appContext;
@Inject
private PropertiesProxy conf;
private final AtomicInteger containerCounter = new AtomicInteger(-1);
private final Object monitor = new Object();
private volatile boolean started;
//tomcat await thread
private Thread tomcatAwaitThread;
@Override @Override
public void init() throws LifecycleException { public void init() throws LifecycleException {
this.tomcat = new Tomcat(); this.tomcat = new Tomcat();
// 貌似Tomcat死活需要一个temp目录 File baseDir = createTempDir("tomcat");
File baseDir = new File("./temp");
this.tomcat.setBaseDir(baseDir.getAbsolutePath()); this.tomcat.setBaseDir(baseDir.getAbsolutePath());
// 当前支持Http就够了
Connector connector = new Connector(PROP_PROTOCOL); Connector connector = new Connector(PROP_PROTOCOL);
connector.setPort(getPort()); connector.setPort(getPort());
connector.setURIEncoding("UTF-8"); connector.setURIEncoding(DEFAULT_CHARSET.name());
// 设置一下最大线程数 // 设置一下最大线程数
this.tomcat.getService().addConnector(connector); this.tomcat.getService().addConnector(connector);
@ -98,22 +121,41 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
this.tomcat.getHost().setAutoDeploy(false); this.tomcat.getHost().setAutoDeploy(false);
this.tomcat.getEngine().setBackgroundProcessorDelay(30); this.tomcat.getEngine().setBackgroundProcessorDelay(30);
prepareContext(this.tomcat.getHost()); this.prepareContext();
this.nutzSupport();
} }
public void start() throws LifecycleException { public void start() throws LifecycleException {
synchronized (this.monitor) {
if (this.started) {
return;
}
this.tomcat.start(); this.tomcat.start();
tomcatAwaitThread = new Thread("container-" + (containerCounter.get())) {
@Override
public void run() {
TomcatStarter.this.tomcat.getServer().await();
}
};
tomcatAwaitThread.setContextClassLoader(getClass().getClassLoader());
tomcatAwaitThread.setDaemon(false);
tomcatAwaitThread.start();
this.started = true;
}
} }
public void stop() throws LifecycleException { public void stop() throws LifecycleException {
synchronized (this.monitor) {
if (started) {
this.tomcat.stop(); this.tomcat.stop();
this.tomcat = null; this.tomcat = null;
this.tomcatAwaitThread.interrupt();
this.started = false;
}
}
} }
public boolean isRunning() { public boolean isRunning() {
return true; return this.started;
} }
public void setAppContext(AppContext appContext) { public void setAppContext(AppContext appContext) {
@ -128,19 +170,35 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
return false; return false;
} }
public void fetch() {} public void fetch() {
public void depose() throws LifecycleException {
if (this.tomcat != null)
this.tomcat.stop();
} }
private void prepareContext(Host host) { public void depose() throws LifecycleException {
if (this.tomcat != null) {
this.stop();
}
}
private void prepareContext() {
File docBase = Files.findFile(getStaticPath());
docBase = (docBase != null && docBase.isDirectory()) ? docBase : createTempDir("tomcat-docbase");
this.tomcatContext = new StandardContext(); this.tomcatContext = new StandardContext();
this.tomcatContext.setDocBase(docBase.getAbsolutePath());
this.tomcatContext.setName(getContextPath()); this.tomcatContext.setName(getContextPath());
this.tomcatContext.setPath(getContextPath()); this.tomcatContext.setPath(getContextPath());
this.tomcatContext.setDelegate(false);
this.tomcatContext.addLifecycleListener(new Tomcat.FixContextListener()); this.tomcatContext.addLifecycleListener(new Tomcat.FixContextListener());
this.tomcatContext.setParentClassLoader(classLoader); this.tomcatContext.setParentClassLoader(classLoader);
this.tomcatContext.setSessionTimeout(getSessionTimeout());
this.tomcatContext.addLifecycleListener(new StoreMergedWebXmlListener());
try {
this.tomcatContext.setUseRelativeRedirects(false);
} catch (NoSuchMethodError ex) {
// Tomcat is < 8.0.30. Continue
}
for (String welcomeFile : Arrays.asList("index.html", for (String welcomeFile : Arrays.asList("index.html",
"index.htm", "index.htm",
@ -149,51 +207,39 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
this.tomcatContext.addWelcomeFile(welcomeFile); this.tomcatContext.addWelcomeFile(welcomeFile);
} }
this.tomcatContext.setUseRelativeRedirects(false);
// 注册defaultServlet // 注册defaultServlet
addDefaultServlet(); addDefaultServlet();
// 注册JspServlet addNutzSupport();
addJspServlet();
host.addChild(tomcatContext); this.tomcat.getHost().addChild(tomcatContext);
} }
private void nutzSupport() { private void addNutzSupport() {
// 添加其他starter提供的WebXXXX服务
Map<String, WebFilterFace> filters = new HashMap<String, WebFilterFace>(); Map<String, WebFilterFace> filters = new HashMap<String, WebFilterFace>();
for (Object object : appContext.getStarters()) { for (Object object : appContext.getStarters()) {
if (object instanceof WebFilterFace) { if (object instanceof WebFilterFace) {
WebFilterFace webFilter = (WebFilterFace) object; WebFilterFace webFilter = (WebFilterFace) object;
if (webFilter == null || webFilter.getFilter() == null) { if (webFilter != null && webFilter.getFilter() != null) {
continue;
}
filters.put(webFilter.getName(), webFilter); filters.put(webFilter.getName(), webFilter);
} }
}
if (object instanceof WebServletFace) { if (object instanceof WebServletFace) {
WebServletFace webServlet = (WebServletFace) object; WebServletFace webServlet = (WebServletFace) object;
if (webServlet == null || webServlet.getServlet() == null) { if (webServlet != null && webServlet.getServlet() != null) {
continue;
}
addServlet(webServlet); addServlet(webServlet);
} }
}
if (object instanceof WebEventListenerFace) { if (object instanceof WebEventListenerFace) {
WebEventListenerFace contextListener = (WebEventListenerFace) object; WebEventListenerFace contextListener = (WebEventListenerFace) object;
if (contextListener == null || contextListener.getEventListener() == null) { if (contextListener != null && contextListener.getEventListener() != null) {
continue;
}
this.tomcatContext.addApplicationEventListener(contextListener.getEventListener()); this.tomcatContext.addApplicationEventListener(contextListener.getEventListener());
} }
} }
String _filterOrders = conf.get(PROP_WEB_FILTERS_ORDER);
if (_filterOrders == null)
_filterOrders = "whale,druid,shiro,nutz";
else if (_filterOrders.endsWith("+")) {
_filterOrders = _filterOrders.substring(0, _filterOrders.length() - 1)
+ ",whale,druid,shiro,nutz";
} }
String[] filterOrders = Strings.splitIgnoreBlank(_filterOrders);
String[] filterOrders = Strings.splitIgnoreBlank(getWebFiltersOrder());
for (String filterName : filterOrders) { for (String filterName : filterOrders) {
addFilter(filters.remove(filterName)); addFilter(filters.remove(filterName));
@ -215,23 +261,8 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
addServletMapping("/", "default"); addServletMapping("/", "default");
} }
private void addJspServlet() {
// 暂不支持jsp了
// Wrapper jspServlet = this.tomcatContext.createWrapper();
// jspServlet.setName("jsp");
// jspServlet.setServletClass(JspServlet.class.getName());
// jspServlet.addInitParameter("fork", "false");
// jspServlet.addInitParameter("development", "false");
// jspServlet.setLoadOnStartup(3);
// this.tomcatContext.addChild(jspServlet);
// addServletMapping("*.jsp", "jsp");
// addServletMapping("*.jspx", "jsp");
}
private void addServlet(WebServletFace webServlet) { private void addServlet(WebServletFace webServlet) {
log.debugf("[NutzBoot] add servlet name=%s pathSpec=%s", log.debugf("[NutzBoot] add servlet name=%s pathSpec=%s", webServlet.getName(), webServlet.getPathSpec());
webServlet.getName(),
webServlet.getPathSpec());
Wrapper servlet = tomcatContext.createWrapper(); Wrapper servlet = tomcatContext.createWrapper();
servlet.setName(webServlet.getName()); servlet.setName(webServlet.getName());
@ -241,7 +272,7 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
servlet.addInitParameter(entry.getKey(), entry.getValue()); servlet.addInitParameter(entry.getKey(), entry.getValue());
} }
servlet.setOverridable(true); servlet.setOverridable(true);
tomcatContext.addChild(servlet); this.tomcatContext.addChild(servlet);
addServletMapping(webServlet.getPathSpec(), webServlet.getName()); addServletMapping(webServlet.getPathSpec(), webServlet.getName());
} }
@ -249,9 +280,7 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
if (filterFace == null || filterFace.getFilter() == null) { if (filterFace == null || filterFace.getFilter() == null) {
return; return;
} }
log.debugf("[NutzBoot] add filter name=%s pathSpec=%s", log.debugf("[NutzBoot] add filter name=%s pathSpec=%s", filterFace.getName(), filterFace.getPathSpec());
filterFace.getName(),
filterFace.getPathSpec());
FilterDef filterDef = new FilterDef(); FilterDef filterDef = new FilterDef();
filterDef.setFilter(filterFace.getFilter()); filterDef.setFilter(filterFace.getFilter());
filterDef.setFilterName(filterFace.getName()); filterDef.setFilterName(filterFace.getName());
@ -262,8 +291,9 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
} }
} }
this.tomcatContext.addFilterDef(filterDef); this.tomcatContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap(); FilterMap filterMap = new FilterMap();
filterMap.addURLPattern(filterFace.getPathSpec()); filterMap.addURLPatternDecoded(filterFace.getPathSpec());
filterMap.setFilterName(filterFace.getName()); filterMap.setFilterName(filterFace.getName());
this.tomcatContext.addFilterMap(filterMap); this.tomcatContext.addFilterMap(filterMap);
} }
@ -272,6 +302,66 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
this.tomcatContext.addServletMappingDecoded(pattern, name); this.tomcatContext.addServletMappingDecoded(pattern, name);
} }
private File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
} catch (IOException ex) {
throw new RuntimeException(
"Unable to create tempDir. java.io.tmpdir is set to "
+ System.getProperty("java.io.tmpdir"),
ex);
}
}
private static class StoreMergedWebXmlListener implements LifecycleListener {
private static final String MERGED_WEB_XML = "org.apache.tomcat.util.scan.MergedWebXml";
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
onStart((Context) event.getLifecycle());
}
}
private void onStart(Context context) {
ServletContext servletContext = context.getServletContext();
if (servletContext.getAttribute(MERGED_WEB_XML) == null) {
servletContext.setAttribute(MERGED_WEB_XML, getEmptyWebXml());
}
}
private String getEmptyWebXml() {
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("empty-web.xml");
if (stream == null) {
throw new IllegalArgumentException("Unable to read empty web.xml");
}
try {
try {
StringBuilder out = new StringBuilder();
InputStreamReader reader = new InputStreamReader(stream, DEFAULT_CHARSET);
char[] buffer = new char[1024 * 4];
int bytesRead = -1;
while ((bytesRead = reader.read(buffer)) != -1) {
out.append(buffer, 0, bytesRead);
}
return out.toString();
} finally {
stream.close();
}
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}
// --getConf--- // --getConf---
public int getPort() { public int getPort() {
return conf.getInt(PROP_PORT, 8080); return conf.getInt(PROP_PORT, 8080);
@ -285,6 +375,13 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
return conf.get(PROP_STATIC_PATH, "static"); return conf.get(PROP_STATIC_PATH, "static");
} }
public String getWebFiltersOrder() {
String filterOrder = conf.get(PROP_WEB_FILTERS_ORDER);
return filterOrder == null
? "whale,druid,shiro,nutz"
: filterOrder.replaceFirst("\\+$", ",whale,druid,shiro,nutz");
}
public String getContextPath() { public String getContextPath() {
return conf.get(PROP_CONTEXT_PATH, ""); return conf.get(PROP_CONTEXT_PATH, "");
} }
@ -296,4 +393,6 @@ public class TomcatStarter implements ClassLoaderAware, ServerFace, LifeCycle, A
public int getMaxThread() { public int getMaxThread() {
return Lang.isAndroid ? 50 : 500; return Lang.isAndroid ? 50 : 500;
} }
} }

View File

@ -21,7 +21,10 @@ import org.nutz.boot.starter.WebFilterFace;
import org.nutz.boot.starter.WebServletFace; import org.nutz.boot.starter.WebServletFace;
import org.nutz.ioc.Ioc; import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy; import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Files; import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.LifeCycle; import org.nutz.lang.util.LifeCycle;
import org.nutz.log.Log; import org.nutz.log.Log;
@ -46,6 +49,8 @@ import io.undertow.servlet.util.ImmediateInstanceFactory;
* Undertow 启动器 * Undertow 启动器
* @author qinerg(qinerg@gmail.com) * @author qinerg(qinerg@gmail.com)
*/ */
@IocBean
public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace, LifeCycle, AppContextAware { public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace, LifeCycle, AppContextAware {
private static final Log log = Logs.get(); private static final Log log = Logs.get();
@ -70,6 +75,9 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
@PropDoc(group = "undertow", value = "静态文件路径", defaultValue = "/static/") @PropDoc(group = "undertow", value = "静态文件路径", defaultValue = "/static/")
public static final String PROP_STATIC_PATH = PRE + "staticPath"; public static final String PROP_STATIC_PATH = PRE + "staticPath";
@Inject
private PropertiesProxy conf;
protected Undertow server; protected Undertow server;
protected ClassLoader classLoader; protected ClassLoader classLoader;
protected Ioc ioc; protected Ioc ioc;
@ -108,21 +116,39 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
} }
public void init() throws Exception { public void init() throws Exception {
PropertiesProxy conf = appContext.getConfigureLoader().get();
String contextPath = conf.get(PROP_CONTEXT_PATH, "/"); String contextPath = getContextPath();
deployment = Servlets.deployment().setDeploymentName("nb").setClassLoader(classLoader).setEagerFilterInit(true).setSecurityDisabled(true); deployment = Servlets.deployment().setDeploymentName("nb").setClassLoader(classLoader).setEagerFilterInit(true).setSecurityDisabled(true);
deployment.setContextPath(contextPath).setDefaultSessionTimeout(conf.getInt(PROP_SESSION, 20) * 60); deployment.setContextPath(contextPath).setDefaultSessionTimeout(getSessionTimeout());
String staticPath = conf.get(PROP_STATIC_PATH, "static"); File resRootDir = Files.findFile(getStaticPath());
File resRootDir = Files.findFile(staticPath);
if (resRootDir != null && resRootDir.isDirectory()) { if (resRootDir != null && resRootDir.isDirectory()) {
deployment.setResourceManager(new FileResourceManager(resRootDir, 1024)); deployment.setResourceManager(new FileResourceManager(resRootDir, 1024));
} else { } else {
deployment.setResourceManager(new ClassPathResourceManager(classLoader, staticPath)); deployment.setResourceManager(new ClassPathResourceManager(classLoader, getStaticPath()));
} }
// 添加其他starter提供的WebXXXX服务 addNutzSupport();
deployment.addWelcomePages("index.html", "index.htm", "index.do");
DeploymentManager manager = Servlets.defaultContainer().addDeployment(deployment);
manager.deploy();
HttpHandler servletHandler = manager.start();
PathHandler pathHandler;
if ("/".equals(contextPath)) {
pathHandler = Handlers.path(servletHandler);
} else {
pathHandler = Handlers.path(Handlers.redirect(contextPath)).addPrefixPath(contextPath, servletHandler);
}
builder.addHttpListener(getPort(),getHost()).setHandler(pathHandler);
server = builder.build();
}
private void addNutzSupport() {
Map<String, WebFilterFace> filters = new HashMap<>(); Map<String, WebFilterFace> filters = new HashMap<>();
for (Object object : appContext.getStarters()) { for (Object object : appContext.getStarters()) {
if (object instanceof WebFilterFace) { if (object instanceof WebFilterFace) {
@ -139,41 +165,19 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
} }
} }
String _filterOrders = conf.get(PROP_WEB_FILTERS_ORDER); String[] filterOrders = Strings.splitIgnoreBlank(getWebFiltersOrder());
if (_filterOrders == null)
_filterOrders = "whale,druid,shiro,nutz";
else if (_filterOrders.endsWith("+")) {
_filterOrders = _filterOrders.substring(0, _filterOrders.length() - 1) + ",whale,druid,shiro,nutz";
}
String[] filterOrders = Strings.splitIgnoreBlank(_filterOrders);
for (String filterName : filterOrders) { for (String filterName : filterOrders) {
addFilter(filters.remove(filterName)); addFilter(filters.remove(filterName));
} }
for (WebFilterFace webFilter : filters.values()) { for (WebFilterFace webFilter : filters.values()) {
addFilter(webFilter); addFilter(webFilter);
} }
deployment.addWelcomePages("index.html", "index.htm", "index.do");
DeploymentManager manager = Servlets.defaultContainer().addDeployment(deployment);
manager.deploy();
HttpHandler servletHandler = manager.start();
PathHandler pathHandler;
if ("/".equals(contextPath)) {
pathHandler = Handlers.path(servletHandler);
} else {
pathHandler = Handlers.path(Handlers.redirect(contextPath)).addPrefixPath(contextPath, servletHandler);
}
builder.addHttpListener(conf.getInt(PROP_PORT, 8080), conf.get(PROP_HOST, "0.0.0.0")).setHandler(pathHandler);
server = builder.build();
} }
public void addServlet(WebServletFace webServlet) { public void addServlet(WebServletFace webServlet) {
if (webServlet == null || webServlet.getServlet() == null) if (webServlet == null || webServlet.getServlet() == null) {
return; return;
}
log.debugf("add servlet name=%s pathSpec=%s", webServlet.getName(), webServlet.getPathSpec()); log.debugf("add servlet name=%s pathSpec=%s", webServlet.getName(), webServlet.getPathSpec());
ImmediateInstanceFactory<Servlet> factory = new ImmediateInstanceFactory<Servlet>(webServlet.getServlet()); ImmediateInstanceFactory<Servlet> factory = new ImmediateInstanceFactory<Servlet>(webServlet.getServlet());
ServletInfo servlet = new ServletInfo(webServlet.getName(), webServlet.getServlet().getClass(), factory); ServletInfo servlet = new ServletInfo(webServlet.getName(), webServlet.getServlet().getClass(), factory);
@ -187,9 +191,9 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
} }
public void addFilter(WebFilterFace webFilter) { public void addFilter(WebFilterFace webFilter) {
if (webFilter == null || webFilter.getFilter() == null) if (webFilter == null || webFilter.getFilter() == null) {
return; return;
}
log.debugf("add filter name=%s pathSpec=%s", webFilter.getName(), webFilter.getPathSpec()); log.debugf("add filter name=%s pathSpec=%s", webFilter.getName(), webFilter.getPathSpec());
ImmediateInstanceFactory<Filter> factory = new ImmediateInstanceFactory<Filter>(webFilter.getFilter()); ImmediateInstanceFactory<Filter> factory = new ImmediateInstanceFactory<Filter>(webFilter.getFilter());
FilterInfo filter = new FilterInfo(webFilter.getName(), webFilter.getFilter().getClass(), factory); FilterInfo filter = new FilterInfo(webFilter.getName(), webFilter.getFilter().getClass(), factory);
@ -204,8 +208,9 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
} }
public void addEventListener(WebEventListenerFace webEventListener) { public void addEventListener(WebEventListenerFace webEventListener) {
if (webEventListener.getEventListener() == null) if (webEventListener.getEventListener() == null) {
return; return;
}
EventListener et = webEventListener.getEventListener(); EventListener et = webEventListener.getEventListener();
log.debugf("add listener %s", et.getClass()); log.debugf("add listener %s", et.getClass());
@ -220,4 +225,33 @@ public class UndertowStarter implements ClassLoaderAware, IocAware, ServerFace,
public void depose() throws Exception { public void depose() throws Exception {
} }
// --getConf---
public int getPort() {
return conf.getInt(PROP_PORT, 8080);
}
public String getHost() {
return conf.get(PROP_HOST, "0.0.0.0");
}
public String getStaticPath() {
return conf.get(PROP_STATIC_PATH, "static");
}
public String getWebFiltersOrder() {
String filterOrder = conf.get(PROP_WEB_FILTERS_ORDER);
return filterOrder == null
? "whale,druid,shiro,nutz"
: filterOrder.replaceFirst("\\+$", ",whale,druid,shiro,nutz");
}
public String getContextPath() {
return conf.get(PROP_CONTEXT_PATH, "/");
}
public int getSessionTimeout() {
return conf.getInt(PROP_SESSION, 20) * 60;
}
} }