如何让Jetty扫描class路径下的Maven依赖jar文件?
How can I get Jetty to scan the Maven dependency jar files in the class path?
Eclipse 自动将所有 Maven 依赖项添加到 class 路径。
从 Eclipse 启动时,如何让 Jetty 扫描 class 路径上的 jar 文件以查找 Web 片段?
打包后放入webapp/WEB-INF/lib/*.jar,扫描成功
Server server = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/myapp");
webapp.setBaseResource(Resource.newResource(new File("webapp")));
//
webapp.setConfigurations(new Configuration[] { //
new AnnotationConfiguration(), // @WebServlet, @WebListener...
new WebXmlConfiguration(), // webapp/WEB-INF/web.xml
new WebInfConfiguration(), // ?
new MetaInfConfiguration(), // ?
new FragmentConfiguration(), // e.g. zkwebfragment-9.6.0.1.jar!/META-INF/web-fragment.xml
});
if(RUNNING_FROM_IDE)
{
// add project classes to classpath (e.g. target/classes)
webapp.getMetaData().setWebInfClassesDirs(Arrays.asList(Resource.newResource(MyAppMainClass.class.getProtectionDomain().getCodeSource().getLocation())));
// how to add maven dependencies?
// webapp.getMetaData().addWebInfJar(???);
}
server.setHandler(webapp);
server.start();
我让它以某种方式工作。仍然想知道是否有更标准的方法来实现这一点:
// launching from IDE: manually add WEB-INF/classes and WEB-INF/lib/*.jar entries
webapp.getMetaData().setWebInfClassesDirs(Arrays.asList(Resource.newResource(MyAppMainClass.class.getProtectionDomain().getCodeSource().getLocation())));
for(URL url : ((URLClassLoader) MyAppMainClass.class.getClassLoader()).getURLs()) {
if(url.getPath().endsWith(".jar")) {
webapp.getMetaData().addWebInfJar(Resource.newResource(url));
}
}
我也找到了MavenWebInfConfiguration in the jetty-maven-plugin。我使用:
((WebAppClassLoader) webapp.getClassLoader()).addClassPath(...)
不要手动设置配置,这是第一个错误。
你的努力基本上破坏了配置,因为你没有尊重原来的默认配置,或者微妙的订单要求。
这是错误的方式,直接设置 webapp 配置。
webapp.setConfigurations(new Configuration[] { //
new AnnotationConfiguration(), // @WebServlet, @WebListener...
new WebXmlConfiguration(), // webapp/WEB-INF/web.xml
new WebInfConfiguration(), // ?
new MetaInfConfiguration(), // ?
new FragmentConfiguration(), // e.g. zkwebfragment-9.6.0.1.jar!/META-INF/web-fragment.xml
});
这是正确的方法,通过调整默认配置列表
在服务器级别。
Configuration.ClassList classlist = Configuration.ClassList
.setServerDefault(server);
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
这应该够了。
您可以在服务器转储上看到默认配置顺序。
server.setDumpAfterStart(true);
server.start();
// and then on the output (see your logger) ...
| | | +> Configurations Servlet Dump WebApp@4c163e3 size=5
| | | | +> org.eclipse.jetty.webapp.WebInfConfiguration@5e403b4a
| | | | +> org.eclipse.jetty.webapp.WebXmlConfiguration@5117dd67
| | | | +> org.eclipse.jetty.webapp.MetaInfConfiguration@5be49b60
| | | | +> org.eclipse.jetty.webapp.FragmentConfiguration@2931522b
| | | | +> org.eclipse.jetty.webapp.JettyWebXmlConfiguration@7674b62c
| | | +> Handler attributes Servlet Dump WebApp@4c163e3 size=3
此转储功能很有用,因为它可能会告诉您 $HOME/.m2/repository
jar 文件不存在于 Web 应用程序自己的 class 路径中。
| | | +> WebAppClassLoader{Servlet Dump WebApp}@5fb759d6
| | | | +> URLs size=1
| | | | | +> file:/tmp/jetty-0_0_0_0-8080-ROOT_war-_-any-15598896298108484560/webapp/WEB-INF/classes/
如果您在此处没有看到您的 Maven 存储库文件,那么是时候配置您的 WebAppContext.setExtraClasspath(String)
以在启动您的 web 应用程序之前包含它们。
另一个需要注意的功能是用于识别扫描哪些内容(class 文件)的 2 个扫描正则表达式。一种用于网络应用程序 classes,一种用于服务器 classes。这两个都是相关的
用于发现 servlet 规范中的任何内容,无论是带注释的侦听器、带注释的 servlet、web 片段、servlet 容器初始化程序、jsp 级别详细信息、websocket 级别详细信息等)
如果您想配置它们,它们都被设置为 WebAppContext.setAttribute(String key, String value)
上的属性。
默认情况下,这些值为空,表示扫描所有 jar。
// This one controls server/container level discovery.
// An example of limited scanning would be
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"
".*/[^/]*servlet-api-[^/]*\.jar$|.*[^/]*jstl-.*\.jar$|.*/[^/]*taglibs.*\.jar$");
// This one controls webapp specific discovery.
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern"
".*/[^/]*foo-[^/]*\.jar$|.*/[^/]*bar.*\.jar$");
这方面的一个例子是...
您有一个网络应用...
WEB-INF/lib/
foo-api-1.2.3.jar
foo-1.2.3.jar
bar-0.9.jar
boo-1.0.jar
并定义了 webapp 扫描...
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern",
".*/.*foo-api-[^/]\.jar$|./.*bar-[^/]\.jar$|./.*wibble[^/]*\.jar$");
然后将匹配并扫描以下文件:
WEB-INF/lib/
foo-api-1.2.3.jar
bar-0.9.jar
根据 Joakim 的回答,我现在有:
Server server = new Server(port);
Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server);
classlist.addAfter(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/myapp");
webapp.setBaseResource(Resource.newResource(new File(isRunningFromIde ? "./webapp" : "/path/to/webapp").getCanonicalFile()));
webapp.setWelcomeFiles(new String[] { "index.html" });
// webapp.setInitParameter(..., ...));
// webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", "");
// webapp.setAttribute("org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern", "");
if(isRunningFromIde)
{
List<String> extraClassPath = new ArrayList<>();
// target/classes
extraClassPath.add(Paths.get(MyAppMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toString());
// maven dependencies
for(URL url : ((URLClassLoader) MyAppMain.class.getClassLoader()).getURLs()) {
if(url.getPath().endsWith(".jar")) {
extraClassPath.add(Paths.get(url.toURI()).toString());
}
}
webapp.setExtraClasspath(extraClassPath.stream().collect(Collectors.joining(";")));
}
server.setHandler(webapp);
server.setDumpAfterStart(true);
server.start();
多亏了服务器转储提示,我想我现在也明白了为什么我得到 。 WebAppClassLoader 和 AppClassLoader 都包含相同的条目。 IDE 由于上面的额外类路径而启动。 docker 容器可能是因为我用 java -cp <webapp>/WEB-INF/lib/* MyAppMain.class
.
启动它
| +> WebAppClassLoader{403716510}@1810399e
| | +> URLs size=41
| | | +> file:<maven-repo-or-webapp-dir>/WEB-INF/lib/zk-9.6.0.1.jar
| | | ...
| | +> sun.misc.Launcher$AppClassLoader@4e0e2f2a
| | | +> URLs size=41
| | | | +> file:<maven-repo-or-webapp-dir>/WEB-INF/lib/zk-9.6.0.1.jar
| | | | ...
尝试 3(也基于 Joakim 的回答):设置 ContainerIncludeJarPattern 以扫描已经在 class 路径上的所有内容。无需任何额外的 class 路径修改。
Server server = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/test");
webapp.setBaseResource(Resource.newResource(new File("webapp").getCanonicalFile()));
// https://www.eclipse.org/jetty/documentation/jetty-9/index.html#configuring-webapps
// order apparently important
webapp.setConfigurations(new Configuration[] { //
new WebInfConfiguration(), //
new WebXmlConfiguration(), //
new MetaInfConfiguration(), //
new FragmentConfiguration(), //
new AnnotationConfiguration(), //
});
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*");
server.setHandler(webapp);
server.setDumpAfterStart(true);
server.start();
我的其他问题似乎与 ZK 相关,所以我为此开始 。
Eclipse 自动将所有 Maven 依赖项添加到 class 路径。
从 Eclipse 启动时,如何让 Jetty 扫描 class 路径上的 jar 文件以查找 Web 片段?
打包后放入webapp/WEB-INF/lib/*.jar,扫描成功
Server server = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/myapp");
webapp.setBaseResource(Resource.newResource(new File("webapp")));
//
webapp.setConfigurations(new Configuration[] { //
new AnnotationConfiguration(), // @WebServlet, @WebListener...
new WebXmlConfiguration(), // webapp/WEB-INF/web.xml
new WebInfConfiguration(), // ?
new MetaInfConfiguration(), // ?
new FragmentConfiguration(), // e.g. zkwebfragment-9.6.0.1.jar!/META-INF/web-fragment.xml
});
if(RUNNING_FROM_IDE)
{
// add project classes to classpath (e.g. target/classes)
webapp.getMetaData().setWebInfClassesDirs(Arrays.asList(Resource.newResource(MyAppMainClass.class.getProtectionDomain().getCodeSource().getLocation())));
// how to add maven dependencies?
// webapp.getMetaData().addWebInfJar(???);
}
server.setHandler(webapp);
server.start();
我让它以某种方式工作。仍然想知道是否有更标准的方法来实现这一点:
// launching from IDE: manually add WEB-INF/classes and WEB-INF/lib/*.jar entries
webapp.getMetaData().setWebInfClassesDirs(Arrays.asList(Resource.newResource(MyAppMainClass.class.getProtectionDomain().getCodeSource().getLocation())));
for(URL url : ((URLClassLoader) MyAppMainClass.class.getClassLoader()).getURLs()) {
if(url.getPath().endsWith(".jar")) {
webapp.getMetaData().addWebInfJar(Resource.newResource(url));
}
}
我也找到了MavenWebInfConfiguration in the jetty-maven-plugin。我使用:
((WebAppClassLoader) webapp.getClassLoader()).addClassPath(...)
不要手动设置配置,这是第一个错误。
你的努力基本上破坏了配置,因为你没有尊重原来的默认配置,或者微妙的订单要求。
这是错误的方式,直接设置 webapp 配置。
webapp.setConfigurations(new Configuration[] { //
new AnnotationConfiguration(), // @WebServlet, @WebListener...
new WebXmlConfiguration(), // webapp/WEB-INF/web.xml
new WebInfConfiguration(), // ?
new MetaInfConfiguration(), // ?
new FragmentConfiguration(), // e.g. zkwebfragment-9.6.0.1.jar!/META-INF/web-fragment.xml
});
这是正确的方法,通过调整默认配置列表 在服务器级别。
Configuration.ClassList classlist = Configuration.ClassList
.setServerDefault(server);
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
这应该够了。
您可以在服务器转储上看到默认配置顺序。
server.setDumpAfterStart(true);
server.start();
// and then on the output (see your logger) ...
| | | +> Configurations Servlet Dump WebApp@4c163e3 size=5
| | | | +> org.eclipse.jetty.webapp.WebInfConfiguration@5e403b4a
| | | | +> org.eclipse.jetty.webapp.WebXmlConfiguration@5117dd67
| | | | +> org.eclipse.jetty.webapp.MetaInfConfiguration@5be49b60
| | | | +> org.eclipse.jetty.webapp.FragmentConfiguration@2931522b
| | | | +> org.eclipse.jetty.webapp.JettyWebXmlConfiguration@7674b62c
| | | +> Handler attributes Servlet Dump WebApp@4c163e3 size=3
此转储功能很有用,因为它可能会告诉您 $HOME/.m2/repository
jar 文件不存在于 Web 应用程序自己的 class 路径中。
| | | +> WebAppClassLoader{Servlet Dump WebApp}@5fb759d6
| | | | +> URLs size=1
| | | | | +> file:/tmp/jetty-0_0_0_0-8080-ROOT_war-_-any-15598896298108484560/webapp/WEB-INF/classes/
如果您在此处没有看到您的 Maven 存储库文件,那么是时候配置您的 WebAppContext.setExtraClasspath(String)
以在启动您的 web 应用程序之前包含它们。
另一个需要注意的功能是用于识别扫描哪些内容(class 文件)的 2 个扫描正则表达式。一种用于网络应用程序 classes,一种用于服务器 classes。这两个都是相关的 用于发现 servlet 规范中的任何内容,无论是带注释的侦听器、带注释的 servlet、web 片段、servlet 容器初始化程序、jsp 级别详细信息、websocket 级别详细信息等)
如果您想配置它们,它们都被设置为 WebAppContext.setAttribute(String key, String value)
上的属性。
默认情况下,这些值为空,表示扫描所有 jar。
// This one controls server/container level discovery.
// An example of limited scanning would be
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"
".*/[^/]*servlet-api-[^/]*\.jar$|.*[^/]*jstl-.*\.jar$|.*/[^/]*taglibs.*\.jar$");
// This one controls webapp specific discovery.
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern"
".*/[^/]*foo-[^/]*\.jar$|.*/[^/]*bar.*\.jar$");
这方面的一个例子是...
您有一个网络应用...
WEB-INF/lib/
foo-api-1.2.3.jar
foo-1.2.3.jar
bar-0.9.jar
boo-1.0.jar
并定义了 webapp 扫描...
webappContext.setAttribute(
"org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern",
".*/.*foo-api-[^/]\.jar$|./.*bar-[^/]\.jar$|./.*wibble[^/]*\.jar$");
然后将匹配并扫描以下文件:
WEB-INF/lib/
foo-api-1.2.3.jar
bar-0.9.jar
根据 Joakim 的回答,我现在有:
Server server = new Server(port);
Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server);
classlist.addAfter(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/myapp");
webapp.setBaseResource(Resource.newResource(new File(isRunningFromIde ? "./webapp" : "/path/to/webapp").getCanonicalFile()));
webapp.setWelcomeFiles(new String[] { "index.html" });
// webapp.setInitParameter(..., ...));
// webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", "");
// webapp.setAttribute("org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern", "");
if(isRunningFromIde)
{
List<String> extraClassPath = new ArrayList<>();
// target/classes
extraClassPath.add(Paths.get(MyAppMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toString());
// maven dependencies
for(URL url : ((URLClassLoader) MyAppMain.class.getClassLoader()).getURLs()) {
if(url.getPath().endsWith(".jar")) {
extraClassPath.add(Paths.get(url.toURI()).toString());
}
}
webapp.setExtraClasspath(extraClassPath.stream().collect(Collectors.joining(";")));
}
server.setHandler(webapp);
server.setDumpAfterStart(true);
server.start();
多亏了服务器转储提示,我想我现在也明白了为什么我得到 java -cp <webapp>/WEB-INF/lib/* MyAppMain.class
.
| +> WebAppClassLoader{403716510}@1810399e
| | +> URLs size=41
| | | +> file:<maven-repo-or-webapp-dir>/WEB-INF/lib/zk-9.6.0.1.jar
| | | ...
| | +> sun.misc.Launcher$AppClassLoader@4e0e2f2a
| | | +> URLs size=41
| | | | +> file:<maven-repo-or-webapp-dir>/WEB-INF/lib/zk-9.6.0.1.jar
| | | | ...
尝试 3(也基于 Joakim 的回答):设置 ContainerIncludeJarPattern 以扫描已经在 class 路径上的所有内容。无需任何额外的 class 路径修改。
Server server = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/test");
webapp.setBaseResource(Resource.newResource(new File("webapp").getCanonicalFile()));
// https://www.eclipse.org/jetty/documentation/jetty-9/index.html#configuring-webapps
// order apparently important
webapp.setConfigurations(new Configuration[] { //
new WebInfConfiguration(), //
new WebXmlConfiguration(), //
new MetaInfConfiguration(), //
new FragmentConfiguration(), //
new AnnotationConfiguration(), //
});
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*");
server.setHandler(webapp);
server.setDumpAfterStart(true);
server.start();
我的其他问题似乎与 ZK 相关,所以我为此开始