jetty9内嵌到应用,并在启动后加载WebApplicationInitializer,可运行jsp
声明:本文所介绍的两功能都已经测试通过。
第一步先确保你用的是java 8,并依赖需要的相关jar包,以下是用gradle进行依赖的信息:
ext {
taglibsStandardVersion = "1.2.5"
ecjVersion = "4.4.2"
apacheJspVersion = "6.9.10"
asmVersion = "5.0.1"
tomcatVersion = "8.0.30"
annotationApiVersion = "1.2"
jettySchemasVersion = "3.1"
jettyVersion = "9.3.7.v20160115"
servletApiVersion = "3.1.0"
hamcrestCoreVersion = "5.0.1"
commonsLoggingVersion = "1.2"
springVersion = "4.2.3.RELEASE"
}
dependencies {
compile("spring-web:spring-web:${springVersion}") compile("spring-aop:spring-aop:${springVersion}") compile("spring-beans:spring-beans:${springVersion}") compile("spring-context:spring-context:${springVersion}") compile("spring-expression:spring-expression:${springVersion}") compile("spring-core:spring-core:${springVersion}") compile("commons-logging:commons-logging:${commonsLoggingVersion}") compile("javax.servlet-api:javax.servlet-api:${servletApiVersion}") compile("hamcrest-core:hamcrest-core:${hamcrestCoreVersion}") compile("jetty-annotations:jetty-annotations:${jettyVersion}") compile("jetty-plus:jetty-plus:${jettyVersion}") compile("jetty-jndi:jetty-jndi:${jettyVersion}") compile("jetty-webapp:jetty-webapp:${jettyVersion}") compile("jetty-xml:jetty-xml:${jettyVersion}") compile("jetty-servlet:jetty-servlet:${jettyVersion}") compile("jetty-servlet:jetty-security:${jettyVersion}") compile("jetty-servlet:jetty-util:${jettyVersion}") compile("jetty-servlet:jetty-server:${jettyVersion}") compile("jetty-servlet:jetty-http:${jettyVersion}") compile("jetty-servlet:jetty-io:${jettyVersion}") compile("jetty-servlet:jetty-schemas:${jettySchemasVersion}") compile("apache-jsp:apache-jsp:${jettyVersion}") compile("aopalliance:aopalliance:1.0") compile("javax.annotation-api:javax.annotation-api:${annotationApiVersion}") compile("asm:asm:${asmVersion}") compile("asm-tree:asm-tree:${asmVersion}") compile("asm-commons:asm-commons:${asmVersion}") compile("jasper-apache-jsp:apache-jsp:${apacheJspVersion}") compile("apache-el:apache-el:${apacheJspVersion}") compile("ecj:ecj:${ecjVersion}") compile("taglibs-standard-spec:taglibs-standard-spec:${taglibsStandardVersion}") compile("taglibs-standard-impl:taglibs-standard-impl:${taglibsStandardVersion}")
}
1、jetty9内嵌到应用
核心类代码如下:
import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.SimpleInstanceManager; import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.annotations.ClassInheritanceHandler; import org.eclipse.jetty.annotations.ServletContainerInitializersStarter; import org.eclipse.jetty.apache.jsp.JettyJasperInitializer; import org.eclipse.jetty.jsp.JettyJspServlet; import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.log.JavaUtilLog; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.WebApplicationInitializer; import com.wangzhe.autojoin.wangfw.init.WebAppStrarUpInitializer; import com.wangzhe.autojoin.wangfw.server.Common; import com.wangzhe.autojoin.wangfw.server.ServerParam; import com.wangzhe.autojoin.wangfw.server.jetty9.test.DateServlet; import com.wangzhe.autojoin.wangfw.util.DateUtil; import com.wangzhe.autojoin.wangfw.util.ObjectUtil; import com.wangzhe.autojoin.wangfw.util.Pic2Char; /** * Example of using JSP's with embedded jetty and not requiring all of the * overhead of a WebAppContext */ public class JettyRunner { private static final Logger LOG = LoggerFactory.getLogger(JettyRunner.class); // web容器相关参数 private static final ServerParam param = new ServerParam(); public static void main(String[] args) throws Exception { printFrameWorkLog(); Common.initServerParam(args, param); LoggingUtil.config(); Log.setLog(new JavaUtilLog()); JettyRunner main = new JettyRunner(); main.start(); printStartSuccess(); main.waitForInterrupt(); } private static void printFrameWorkLog() throws IOException { String fileStr = new File("").getAbsolutePath()+"\\src\\main\\webapp\\pc\\aj.wangfw\\img\\wang_font.png"; Pic2Char.startPic2Char(fileStr); } private static void printStartSuccess() throws IOException { String fileStr = new File("").getAbsolutePath()+"\\src\\main\\webapp\\pc\\aj.wangfw\\img\\startSuccess.png"; System.out.println(); Pic2Char.startPic2Char(fileStr); } private Server server; private URI serverURI; public JettyRunner() { } public URI getServerURI() { return serverURI; } public void start() throws Exception { server = new Server(createThreadPool()); NetworkConnector connector = createConnector(); server.addConnector(connector); URI baseUri = getWebRootResourceUri(); // Set JSP to use Standard JavaC always System.setProperty("org.apache.jasper.compiler.disablejsr199", "false"); server.setHandler(getWebAppContext(baseUri, getScratchDir())); server.addConnector(connector); server.setStopAtShutdown(true); // Start Server server.start(); // Show server state // if (LOG.isDebugEnabled()) String dump = server.dump();// 输出jetty部分dump信息 LOG.info(dump.substring(dump.indexOf("> sun.misc.Launcher$AppClassLoader"))); // } this.serverURI = getServerUri(connector); } private NetworkConnector createConnector() { ServerConnector connector = new ServerConnector(server); connector.setPort(param.getPort()); connector.setHost(param.getHost()); return connector; } private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException { URL indexUri = this.getClass().getResource("" + param.getWebDir()); if (indexUri == null) { return null; } // Points to wherever /webroot/ (the resource) is return indexUri.toURI(); } /** * Establish Scratch directory for the servlet context (used by JSP * compilation) */ private File getScratchDir() throws IOException { File tempDir = new File(System.getProperty("java.io.tmpdir")); File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp"); if (!scratchDir.exists()) { if (!scratchDir.mkdirs()) { throw new IOException("Unable to create scratch directory: " + scratchDir); } } return scratchDir; } /** * Setup the basic application "context" for this application at "/" This is * also known as the handler tree (in jetty speak) */ private HandlerCollection getWebAppContext(URI baseUri, File scratchDir) { WebAppContext webappCtx = new WebAppContext(); webappCtx.setContextPath("/"); // webappCtx.setDescriptor(param.getWebDir()+"\\WEB-INF\\web.xml"); // webappCtx.setWar(param.getWebDir());//for war webappCtx.setDisplayName("auto join"); webappCtx.setTempDirectory(new File(param.getTempDir())); webappCtx.setWelcomeFiles(new String[] { param.getWebDir() + "\\index.html" });// 欢迎页面 webappCtx.setConfigurationDiscovered(true); webappCtx.setParentLoaderPriority(true); RequestLogHandler logHandler = new RequestLogHandler(); logHandler.setRequestLog(createRequestLog()); webappCtx.setAttribute("javax.servlet.context.tempdir", scratchDir); webappCtx.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$"); if (ObjectUtil.isNotEmpty(baseUri)) { webappCtx.setResourceBase(baseUri.toASCIIString());// for dir } else { webappCtx.setResourceBase(param.getWebDir()); } webappCtx.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers()); webappCtx.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager()); webappCtx.addBean(new ServletContainerInitializersStarter(webappCtx), true); webappCtx.setClassLoader(getUrlClassLoader()); webappCtx.addServlet(jspServletHolder(), "*.jsp"); // Add Application Servlets webappCtx.addServlet(DateServlet.class, "/date/"); webappCtx.addServlet(exampleJspFileMappedServletHolder(), "/test/foo/"); webappCtx.addServlet(defaultServletHolder(baseUri), "/"); setConfigurations(webappCtx); MetaData metaData = webappCtx.getMetaData(); Resource webappInitializer = Resource.newResource(WebAppStrarUpInitializer.class.getProtectionDomain().getCodeSource().getLocation()); metaData.addContainerResource(webappInitializer); HandlerCollection handlerCollection = new HandlerCollection(); GzipHandler gzipHandler = new GzipHandler(); handlerCollection.setHandlers(new Handler[] { webappCtx, logHandler, gzipHandler }); return handlerCollection; } private void setConfigurations(WebAppContext webappCtx) { webappCtx.setConfigurations(new Configuration[] { new AnnotationConfiguration() { @Override public void preConfigure(WebAppContext context) throws Exception { ClassInheritanceMap map = new ClassInheritanceMap(); ConcurrentHashSet<String> hashSet = new ConcurrentHashSet<String>(); hashSet.add(WebAppStrarUpInitializer.class.getName()); map.put(WebApplicationInitializer.class.getName(), hashSet); context.setAttribute(CLASS_INHERITANCE_MAP, map); _classInheritanceHandler = new ClassInheritanceHandler(map); } } }); } /** * Ensure the jsp engine is initialized correctly */ private List<ContainerInitializer> jspInitializers() { JettyJasperInitializer sci = new JettyJasperInitializer(); ContainerInitializer initializer = new ContainerInitializer(sci, null); List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>(); initializers.add(initializer); return initializers; } /** * Set Classloader of Context to be sane (needed for JSTL) JSP requires a * non-System classloader, this simply wraps the embedded System classloader * in a way that makes it suitable for JSP to use */ private ClassLoader getUrlClassLoader() { ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader()); // jspClassLoader=Thread.currentThread().getContextClassLoader(); // //也可以用这种方式 return jspClassLoader; } /** * Create JSP Servlet (must be named "jsp") */ private ServletHolder jspServletHolder() { ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class); holderJsp.setInitOrder(0); holderJsp.setInitParameter("logVerbosityLevel", "DEBUG"); holderJsp.setInitParameter("fork", "false"); holderJsp.setInitParameter("xpoweredBy", "false"); holderJsp.setInitParameter("compilerTargetVM", "1.7"); holderJsp.setInitParameter("compilerSourceVM", "1.7"); holderJsp.setInitParameter("keepgenerated", "true"); return holderJsp; } /** * Create Example of mapping jsp to path spec */ private ServletHolder exampleJspFileMappedServletHolder() { ServletHolder holderAltMapping = new ServletHolder(); holderAltMapping.setName("foo.jsp"); holderAltMapping.setForcedPath("/test/foo/foo.jsp"); return holderAltMapping; } /** * Create Default Servlet (must be named "default") */ private ServletHolder defaultServletHolder(URI baseUri) { ServletHolder holderDefault = new ServletHolder("default", DefaultServlet.class); if (ObjectUtil.isNotEmpty(baseUri)) { LOG.info("Base URI: " + baseUri); holderDefault.setInitParameter("resourceBase", baseUri.toASCIIString()); } else { holderDefault.setInitParameter("resourceBase", param.getWebDir()); } holderDefault.setInitParameter("dirAllowed", "true"); return holderDefault; } /** * Establish the Server URI */ private URI getServerUri(NetworkConnector connector) throws URISyntaxException { String scheme = "http"; for (ConnectionFactory connectFactory : connector.getConnectionFactories()) { if (connectFactory.getProtocol().equals("SSL-http")) { scheme = "https"; } } String host = connector.getHost(); if (host == null) { host = "localhost"; } int port = connector.getLocalPort(); serverURI = new URI(String.format("%s://%s:%d/", scheme, host, port)); LOG.info("start sucess on Server URI: " + serverURI); return serverURI; } public void stop() throws Exception { server.stop(); } /** * Cause server to keep running until it receives a Interrupt. * <p> * Interrupt Signal, or SIGINT (Unix Signal), is typically seen as a result * of a kill -TERM {pid} or Ctrl+C * * @throws InterruptedException * if interrupted */ public void waitForInterrupt() throws InterruptedException { server.join(); } public static ServerParam getParam() { return param; } private RequestLog createRequestLog() { // 记录访问日志的处理 NCSARequestLog requestLog = new NCSARequestLog(); requestLog.setFilename(param.getLogDir() + "/jetty_log" + DateUtil.formatDate(DateUtil.YYYYMMDD) + ".log"); requestLog.setRetainDays(90); requestLog.setExtended(false); requestLog.setAppend(true); // requestLog.setLogTimeZone("GMT"); requestLog.setLogTimeZone("Asia/beijing"); requestLog.setLogDateFormat("yyyy-MM-dd HH:mm:ss"); requestLog.setLogLatency(true); return requestLog; } /** * 设置线程池 * * @return */ private ThreadPool createThreadPool() { QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setMinThreads(10); threadPool.setMaxThreads(500); return threadPool; } }
2、jetty9服务器启动时加载WebApplicationInitializer
下面代码是WebApplicationInitializer的一个实现类
@Order(Integer.MIN_VALUE) // 较低的值有更高的优先级 所以这个类的优先级是最高的 public class WebAppStrarUpInitializer implements WebApplicationInitializer{ public WebAppStrarUpInitializer() { } @Override public void onStartup(ServletContext servletContext) throws ServletException { System.out.println("hello WebAppStrarUpInitializer"); } }
下面代码是从上面第一部分的JettyRunner类中抽取的部分代码,即注册WebApplicationInitializer的地方
private void setConfigurations(WebAppContext webappCtx) { webappCtx.setConfigurations(new Configuration[] { new AnnotationConfiguration() { @Override public void preConfigure(WebAppContext context) throws Exception { ClassInheritanceMap map = new ClassInheritanceMap(); ConcurrentHashSet<String> hashSet = new ConcurrentHashSet<String>(); hashSet.add(WebAppStrarUpInitializer.class.getName());//注册WebApplicationInitializer map.put(WebApplicationInitializer.class.getName(), hashSet); context.setAttribute(CLASS_INHERITANCE_MAP, map); _classInheritanceHandler = new ClassInheritanceHandler(map); } } }); }
完成代码编写后,请运行JettyRunner类的main方法,运行后请在浏览器输入localhost/index.jsp即可看到效果。如图:
参考:
https://github.com/orb15/embeddedjetty9-spring4
https://github.com/langtianya/embedded-jetty-jsp
https://github.com/yjmyzz/jetty-embed-demo
本文代码托管:https://github.com/langtianya/autojion/tree/master/module_project