com.github.antelopeframework.launcher.TomcatBootstrap Maven / Gradle / Ivy
The newest version!
package com.github.antelopeframework.launcher;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardService;
import org.apache.catalina.core.StandardThreadExecutor;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ProtocolHandler;
import com.github.antelopeframework.util.component.AbstractLifeCycle;
/**
*
* @author yangzhi
*
*/
public class TomcatBootstrap extends AbstractLifeCycle {
private static final Logger logger = Logger.getLogger(TomcatBootstrap.class.getName());
public final static Integer DEFAULT_WEBAPP_PORT = 8080;
public final static String DEFAULT_WEBAPP_CONTEXT_PATH = "/";
public final static String DEFAULT_WEBAPP_LOCATION = "../webapp";
//~ 最基础的配置
public static final String PARAM_WEBAPP_PORT = "tomcat.webapp.port";
public static final String PARAM_WEBAPP_CONTEXT_PATH = "tomcat.webapp.context-path";
public static final String PARAM_WEBAPP_LOCATION = "tomcat.webapp.location";
//~ 线程池配置
public static final String PARAM_EXECUTOR_NAME = "tomcat.executor.name";
public static final String PARAM_EXECUTOR_NAME_PREFIX = "tomcat.executor.namePrefix";
public static final String PARAM_EXECUTOR_MAX_THREAD = "tomcat.executor.maxThreads";
public static final String PARAM_EXECUTOR_MIN_SPARE_THREADS = "tomcat.executor.minSpareThreads";
public static final String PARAM_EXECUTOR_MAX_IDLE_TIME = "tomcat.executor.maxIdleTime";
//~ 日志配置
public static final String PARAM_ACCESS_LOG_DIR = "tomcat.access-log.dir";
public static final String PARAM_ACCESS_LOG_PATTERN = "tomcat.access-log.pattern";
public static final String PARAM_ACCESS_LOG_PREFIX = "tomcat.access-log.prefix";
public static final String PARAM_ACCESS_LOG_SUFFIX = "tomcat.access-log.suffix";
public static final String PARAM_ACCESS_LOG_ROTATABLE = "tomcat.access-log.rotatable";
public final static String PARAM_WEB_EXTRA_RESOURCE_PATHS = "tomcat.extra-resource-paths";
protected final Properties tomcatConfigs;
protected Tomcat tomcatServer;
protected StandardContext ctx;
protected int defaultPort;
protected StandardThreadExecutor defaultThreadExecutor;
int listenPort = 0;
protected TomcatBootstrap() throws Exception {
tomcatConfigs = new Properties();
try {
tomcatConfigs.load(TomcatBootstrap.class.getResourceAsStream("/tomcat.properties"));
} catch (Exception e) {
}
}
@Override
public void doStart() throws Exception {
int port = intValue(tomcatConfigs, PARAM_WEBAPP_PORT, DEFAULT_WEBAPP_PORT);
ServerSocket socket = null;
try {
socket = new ServerSocket(port);
} catch (IOException e) {
logger.log(Level.SEVERE, "port " + port + " is already in use. please try another port.");
throw e;
} finally {
if (socket != null) {
socket.close();
}
}
defaultPort = port;
logger.log(Level.INFO, "Tomcat version=" + ServerInfo.getServerInfo());
tomcatServer = new Tomcat();
tomcatServer.setPort(defaultPort);
initConnectors();
ClassLoader cl = TomcatBootstrap.class.getClassLoader();
logger.log(Level.INFO, "setParentClassLoader: " + cl);
tomcatServer.getEngine().setParentClassLoader(cl);
tomcatServer.getHost().setParentClassLoader(cl);
tomcatServer.getServer().setParentClassLoader(cl);
tomcatServer.getService().setParentClassLoader(cl);
initAccessLog();
initWebApp();
StandardManager manager = new StandardManager();
manager.setPathname(null);
ctx.setManager(manager);
try {
tomcatServer.start();
tomcatServer.getServer().await();
} catch (Throwable e) {
System.exit(0);
} finally {
stop();
}
}
@Override
public void doStop() throws Exception {
try {
if (tomcatServer != null) {
if (tomcatServer.getServer() != null && tomcatServer.getServer().getState() != LifecycleState.DESTROYED) {
if (tomcatServer.getServer().getState() != LifecycleState.STOPPED) {
tomcatServer.stop();
}
}
tomcatServer.destroy();
}
} catch (Throwable e) {
e.printStackTrace();
logger.log(Level.SEVERE, e.getMessage());
}
}
protected void initConnectors() throws IOException, SocketException {
StandardService service = (StandardService) tomcatServer.getService();
//~ 默认线程池
this.defaultThreadExecutor = new StandardThreadExecutor();
this.defaultThreadExecutor.setName(stringValue(tomcatConfigs, PARAM_EXECUTOR_NAME, "tomcatThreadPool"));
this.defaultThreadExecutor.setNamePrefix(stringValue(tomcatConfigs, PARAM_EXECUTOR_NAME_PREFIX, "catalina-exec-"));
this.defaultThreadExecutor.setMaxThreads(intValue(tomcatConfigs, PARAM_EXECUTOR_MAX_THREAD, 200));
this.defaultThreadExecutor.setMinSpareThreads(intValue(tomcatConfigs, PARAM_EXECUTOR_MIN_SPARE_THREADS, 25));
this.defaultThreadExecutor.setMaxIdleTime(intValue(tomcatConfigs, PARAM_EXECUTOR_MAX_IDLE_TIME, 60000));
service.addExecutor(this.defaultThreadExecutor);
//~ 默认连接器
tomcatServer.setConnector(new Connector("HTTP/1.1"));
initDefaultConnector(service, this.defaultThreadExecutor, null);
}
protected void initAccessLog() {
String dir = stringValue(tomcatConfigs, PARAM_ACCESS_LOG_DIR, null);
if (isBlank(dir)) {
String logDir = System.getProperty("logDir");
String appName = System.getProperty("appName");
if (!isBlank(logDir) && !isBlank(appName)) {
dir = logDir + "/" + appName;
}
}
if (isBlank(dir)) {
logger.log(Level.INFO, "access log dir is empty");
return;
}
AccessLogValve al = new AccessLogValve();
File logFile = new File(dir);
if (!logFile.exists() || !logFile.isDirectory()) {
logFile.mkdirs();
}
logger.log(Level.SEVERE, "access log dir=" + logFile.getAbsolutePath());
al.setDirectory(logFile.getAbsolutePath());
String pattern = stringValue(tomcatConfigs, PARAM_ACCESS_LOG_PATTERN, "%h %l %u %t %r %s %b");
if (pattern != null) {
al.setPattern(pattern);
}
String prefix = stringValue(tomcatConfigs, PARAM_ACCESS_LOG_PREFIX, "access-log.");
if (prefix != null) {
al.setPrefix(prefix);
}
String suffix = stringValue(tomcatConfigs, PARAM_ACCESS_LOG_SUFFIX, null);
if (suffix != null) {
al.setSuffix(suffix);
}
String rotate = stringValue(tomcatConfigs, PARAM_ACCESS_LOG_ROTATABLE, "true");
if (rotate != null) {
al.setRotatable(Boolean.valueOf(rotate));
}
((StandardEngine) tomcatServer.getEngine()).addValve(al);
}
private void initDefaultConnector(StandardService service, StandardThreadExecutor executor, InetAddress loopbackAddress) {
listenPort = 0;
final Connector connector = new Connector("HTTP/1.1");
setExecutor(connector, executor);
enableCompression(connector);
connector.setPort(defaultPort);
connector.setURIEncoding("UTF-8");
connector.setUseBodyEncodingForURI(true);
if (loopbackAddress != null) {
String address = loopbackAddress.getHostAddress();
connector.setAttribute("address", address);
logger.log(Level.INFO, "bind address=" + address);
}
connector.setAttribute("bindOnInit", "true");
service.addConnector(connector);
}
protected void initWebApp() throws IOException, ServletException {
Host host = tomcatServer.getHost();
String appbase = new File(stringValue(tomcatConfigs, PARAM_WEBAPP_LOCATION, DEFAULT_WEBAPP_LOCATION)).getCanonicalPath();
host.setAppBase(appbase);
String contextPath = stringValue(tomcatConfigs, PARAM_WEBAPP_CONTEXT_PATH, "/");
ctx = (StandardContext) tomcatServer.addWebapp(contextPath, appbase);
// ctx.setLoader(new WebappLoader(Thread.currentThread().getContextClassLoader()));
String extraResourcePaths = stringValue(tomcatConfigs, PARAM_WEB_EXTRA_RESOURCE_PATHS, "");
if (extraResourcePaths != null && !"".equals(extraResourcePaths.trim())) {
String[] paths = extraResourcePaths.split(";");
for (String one : paths) {
String[] parts = one.split("=");
File additionWebResource = new File(parts[1]);
WebResourceRoot resources = new StandardRoot(ctx);
resources.addPreResources(new DirResourceSet(resources, parts[0], additionWebResource.getAbsolutePath(), "/"));
ctx.setResources(resources);
}
}
}
protected Collection getLoopbackAddresses() throws SocketException {
ArrayList addresses = new ArrayList();
Enumeration nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets)) {
if (netint.isLoopback()) {
Enumeration inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
addresses.add(inetAddress);
}
break;
}
}
return addresses;
}
protected void enableCompression(Connector connector) {
connector.setProperty("compression", "on");
connector.setProperty("compressableMimeType", "text/html,text/xml,text/plain,text/javascript,application/javascript");
}
@SuppressWarnings("rawtypes")
protected void setExecutor(Connector con, Executor executor) {
ProtocolHandler protocol = con.getProtocolHandler();
if (protocol instanceof AbstractProtocol) {
((AbstractProtocol) protocol).setExecutor(executor);;
}
}
/**
* 优先使用System.get()
*
* @param properties
* @param key
* @return
*/
protected static String stringValue(Properties properties, String key, String defaultValue) {
Object value = System.getProperty(key);
if (isBlank(value)) {
value = properties.get(key);
}
if (!isBlank(value)) {
return StringUtils.trim(value.toString());
}
return defaultValue;
}
/**
* 获取整数类型结果. 优先使用System.get().
*
* @param properties
* @param key
* @param defaultValue
* @return
*/
protected Integer intValue(Properties properties, String key, Integer defaultValue) {
String value = stringValue(properties, key, null);
Integer result = null;
try {
result = Integer.valueOf(value);
} catch (Exception e) {
result = defaultValue;
}
return result;
}
/**
* 判断字符串是否为空串(null, '', ' '均为空串).
*
* @param value
* @return
*/
protected static Boolean isBlank(Object value) {
return value == null || StringUtils.isBlank(value.toString());
}
public static void main(String[] args) throws Exception {
final TomcatBootstrap server = new TomcatBootstrap();
try {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
server.stop();
logger.info("Server stopped!");
} catch (Throwable t) {
t.printStackTrace();
logger.log(Level.SEVERE, t.getMessage());
}
synchronized (TomcatBootstrap.class) {
TomcatBootstrap.class.notify();
}
}
});
server.start();
} catch (Exception e) {
e.printStackTrace();
logger.log(Level.SEVERE, e.getMessage());
System.exit(1);
}
synchronized (TomcatBootstrap.class) {
while (server.isRunning()) {
try {
TomcatBootstrap.class.wait();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append(tomcatConfigs)
.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy