简体   繁体   English

Spring 3.1 WebApplicationInitializer和Embedded Jetty 8 AnnotationConfiguration

[英]Spring 3.1 WebApplicationInitializer & Embedded Jetty 8 AnnotationConfiguration

I'm trying to create a simple webapp without any XML configuration using Spring 3.1 and an embedded Jetty 8 server. 我正在尝试使用Spring 3.1和嵌入式Jetty 8服务器创建一个没有任何XML配置的简单webapp。

However, I'm struggling to get Jetty to recognise my implementaton of the Spring WebApplicationInitializer interface. 但是,我正在努力让Jetty认识到我对Spring WebApplicationInitializer接口的实现。

Project structure: 项目结构:

src
 +- main
     +- java
     |   +- JettyServer.java
     |   +- Initializer.java
     | 
     +- webapp
         +- web.xml (objective is to remove this - see below).

The Initializer class above is a simple implementation of WebApplicationInitializer : 上面的Initializer类是WebApplicationInitializer的一个简单实现:

import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.web.WebApplicationInitializer;

public class Initializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("onStartup");
    }
}

Likewise JettyServer is a simple implementation of an embedded Jetty server: 同样JettyServer是嵌入式Jetty服务器的简单实现:

import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;

public class JettyServer {

    public static void main(String[] args) throws Exception { 

        Server server = new Server(8080);

        WebAppContext webAppContext = new WebAppContext();
        webAppContext.setResourceBase("src/main/webapp");
        webAppContext.setContextPath("/");
        webAppContext.setConfigurations(new Configuration[] { new AnnotationConfiguration() });
        webAppContext.setParentLoaderPriority(true);

        server.setHandler(webAppContext);
        server.start();
        server.join();
    }
}

My understanding is that on startup Jetty will use AnnotationConfiguration to scan for annotated implementations of ServletContainerInitializer ; 我的理解是,在启动时,Jetty将使用AnnotationConfiguration来扫描ServletContainerInitializer的注释实现; it should find Initializer and wire it in... 它应该找到初始化器并将其连接到......

However, when I start the Jetty server (from within Eclipse) I see the following on the command-line: 但是,当我启动Jetty服务器(从Eclipse中)时,我在命令行上看到以下内容:

2012-11-04 16:59:04.552:INFO:oejs.Server:jetty-8.1.7.v20120910
2012-11-04 16:59:05.046:INFO:/:No Spring WebApplicationInitializer types detected on classpath
2012-11-04 16:59:05.046:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/duncan/Coding/spring-mvc-embedded-jetty-test/src/main/webapp/}
2012-11-04 16:59:05.117:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080

The important bit is this: 重要的是这个:

No Spring WebApplicationInitializer types detected on classpath

Note that src/main/java is defined as a source folder in Eclipse, so should be on the classpath. 请注意, src / main / java在Eclipse中定义为源文件夹,因此应该在类路径上。 Also note that the Dynamic Web Module Facet is set to 3.0. 另请注意,Dynamic Web Module Facet设置为3.0。

I'm sure there's a simple explanation, but I'm struggling to see the wood for the trees! 我确信这有一个简单的解释,但我很难看到树木的木头! I suspect the key is with the following line: 我怀疑关键是以下行:

...
webAppContext.setResourceBase("src/main/webapp");
...

This makes sense with a 2.5 servlet using web.xml (see below), but what should it be when using AnnotationConfiguration ? 这对于使用web.xml的2.5 servlet是有意义的(见下文),但使用AnnotationConfiguration时它应该是什么?

NB: Everything fires up correctly if I change the Configurations to the following: 注意:如果我将配置更改为以下内容,则所有内容都会正常启动:

...
webAppContext.setConfigurations(new Configuration[] { new WebXmlConfiguration() });
...

In this case it finds the web.xml under src/main/webapp and uses it to wire the servlet using DispatcherServlet and AnnotationConfigWebApplicationContext in the usual way (completely bypassing the WebApplicationInitializer implementation above). 在这种情况下,它在src / main / webapp下找到web.xml ,并使用它以常规方式使用DispatcherServletAnnotationConfigWebApplicationContext连接 servlet(完全绕过上面的WebApplicationInitializer实现)。

This feels very much like a classpath problem, but I'm struggling to understand quite how Jetty associates itself with implementations of WebApplicationInitializer - any suggestions would be most appreciated! 这感觉非常类似于类路径问题,但我很难理解Jetty如何将自己与WebApplicationInitializer的实现联系起来 - 任何建议都将非常受欢迎!

For info, I'm using the following: 有关信息,我使用以下内容:

Spring 3.1.1 Jetty 8.1.7 STS 3.1.0 Spring 3.1.1 Jetty 8.1.7 STS 3.1.0

The problem is that Jetty's AnnotationConfiguration class does not scan non-jar resources on the classpath (except under WEB-INF/classes). 问题是Jetty的AnnotationConfiguration类不扫描类路径上的非jar资源(WEB-INF / classes下除外)。

It finds my WebApplicationInitializer 's if I register a subclass of AnnotationConfiguration which overrides configure(WebAppContext) to scan the host classpath in addition to the container and web-inf locations. 如果我注册了AnnotationConfiguration的子类,它会覆盖configure(WebAppContext)以扫描除容器和web-inf位置之外的主机类路径,它会找到我的WebApplicationInitializer

Most of the sub-class is (sadly) copy-paste from the parent. 大多数子类是(遗憾地)从父级复制粘贴。 It includes: 这包括:

  • an extra parse call ( parseHostClassPath ) at the end of the configure method; configure方法结束时的额外解析调用( parseHostClassPath );
  • the parseHostClassPath method which is largely copy-paste from AnnotationConfiguration 's parseWebInfClasses ; parseHostClassPath方法,主要是从AnnotationConfigurationparseWebInfClasses复制粘贴;
  • the getHostClassPathResource method which grabs the first non-jar URL from the classloader (which, for me at least, is the file url to my classpath in eclipse). getHostClassPathResource方法从类加载器中抓取第一个非jar URL(至少对我来说,这是eclipse中我的classpath的文件url)。

I am using slightly different versions of Jetty (8.1.7.v20120910) and Spring (3.1.2_RELEASE), but I imagine the same solution will work. 我使用稍微不同版本的Jetty(8.1.7.v20120910)和Spring(3.1.2_RELEASE),但我想相同的解决方案将起作用。

Edit: I created a working sample project in github with some modifications (the code below works fine from Eclipse but not when running in a shaded jar) - https://github.com/steveliles/jetty-embedded-spring-mvc-noxml 编辑:我在github中创建了一个工作示例项目,并进行了一些修改(下面的代码在Eclipse中工作正常,但在使用阴影jar时运行时却没有) - https://github.com/steveliles/jetty-embedded-spring-mvc-noxml

In the OP's JettyServer class the necessary change would replace line 15 with: 在OP的JettyServer类中,必要的更改将替换第15行:

webAppContext.setConfigurations (new Configuration []
{
        new AnnotationConfiguration() 
        {
            @Override
            public void configure(WebAppContext context) throws Exception
            {
                boolean metadataComplete = context.getMetaData().isMetaDataComplete();
                context.addDecorator(new AnnotationDecorator(context));   

                AnnotationParser parser = null;
                if (!metadataComplete)
                {
                    if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
                    {
                        parser = createAnnotationParser();
                        parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
                        parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
                        parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
                    }
                }

                List<ServletContainerInitializer> nonExcludedInitializers = getNonExcludedInitializers(context);
                parser = registerServletContainerInitializerAnnotationHandlers(context, parser, nonExcludedInitializers);

                if (parser != null)
                {
                    parseContainerPath(context, parser);
                    parseWebInfClasses(context, parser);
                    parseWebInfLib (context, parser);
                    parseHostClassPath(context, parser);
                }                  
            }

            private void parseHostClassPath(final WebAppContext context, AnnotationParser parser) throws Exception
            {
                clearAnnotationList(parser.getAnnotationHandlers());
                Resource resource = getHostClassPathResource(getClass().getClassLoader());                  
                if (resource == null)
                    return;

                parser.parse(resource, new ClassNameResolver()
                {
                    public boolean isExcluded (String name)
                    {           
                        if (context.isSystemClass(name)) return true;                           
                        if (context.isServerClass(name)) return false;
                        return false;
                    }

                    public boolean shouldOverride (String name)
                    {
                        //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
                        if (context.isParentLoaderPriority())
                            return false;
                        return true;
                    }
                });

                //TODO - where to set the annotations discovered from WEB-INF/classes?    
                List<DiscoveredAnnotation> annotations = new ArrayList<DiscoveredAnnotation>();
                gatherAnnotations(annotations, parser.getAnnotationHandlers());                 
                context.getMetaData().addDiscoveredAnnotations (annotations);
            }

            private Resource getHostClassPathResource(ClassLoader loader) throws IOException
            {
                if (loader instanceof URLClassLoader)
                {
                    URL[] urls = ((URLClassLoader)loader).getURLs();
                    for (URL url : urls)
                        if (url.getProtocol().startsWith("file"))
                            return Resource.newResource(url);
                }
                return null;                    
            }
        },
    });

Update : Jetty 8.1.8 introduces internal changes that are incompatible with the code above. 更新 :Jetty 8.1.8引入了与上述代码不兼容的内部更改。 For 8.1.8 the following seems to work: 对于8.1.8,以下似乎有效:

webAppContext.setConfigurations (new Configuration []
    {
        // This is necessary because Jetty out-of-the-box does not scan
        // the classpath of your project in Eclipse, so it doesn't find
        // your WebAppInitializer.
        new AnnotationConfiguration() 
        {
            @Override
            public void configure(WebAppContext context) throws Exception {
                   boolean metadataComplete = context.getMetaData().isMetaDataComplete();
                   context.addDecorator(new AnnotationDecorator(context));   


                   //Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
                   AnnotationParser parser = null;
                   if (!metadataComplete)
                   {
                       //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
                       if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
                       {
                           _discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
                           _discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context));
                           _discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
                       }
                   }

                   //Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
                   //classes so we can call their onStartup() methods correctly
                   createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));

                   if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
                   {           
                       parser = createAnnotationParser();

                       parse(context, parser);

                       for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
                           context.getMetaData().addDiscoveredAnnotations(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());      
                   }

            }

            private void parse(final WebAppContext context, AnnotationParser parser) throws Exception
            {                   
                List<Resource> _resources = getResources(getClass().getClassLoader());

                for (Resource _resource : _resources)
                {
                    if (_resource == null)
                        return;

                    parser.clearHandlers();
                    for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
                    {
                        if (h instanceof AbstractDiscoverableAnnotationHandler)
                            ((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
                    }
                    parser.registerHandlers(_discoverableAnnotationHandlers);
                    parser.registerHandler(_classInheritanceHandler);
                    parser.registerHandlers(_containerInitializerAnnotationHandlers);

                    parser.parse(_resource, 
                                 new ClassNameResolver()
                    {
                        public boolean isExcluded (String name)
                        {
                            if (context.isSystemClass(name)) return true;
                            if (context.isServerClass(name)) return false;
                            return false;
                        }

                        public boolean shouldOverride (String name)
                        {
                            //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
                            if (context.isParentLoaderPriority())
                                return false;
                            return true;
                        }
                    });
                }
            }

            private List<Resource> getResources(ClassLoader aLoader) throws IOException
            {
                if (aLoader instanceof URLClassLoader)
                {
                    List<Resource> _result = new ArrayList<Resource>();
                    URL[] _urls = ((URLClassLoader)aLoader).getURLs();                      
                    for (URL _url : _urls)
                        _result.add(Resource.newResource(_url));

                    return _result;
                }
                return Collections.emptyList();                 
            }
        }
    });

I was able to resolve in an easier but more limited way by just providing explicitly to the AnnotationConfiguration the implementation class (MyWebApplicationInitializerImpl in this example) that I want to be loaded like this: 通过向AnnotationConfiguration明确提供我想要加载的实现类(MyWebApplicationInitializerImpl),我能够以更简单但更有限的方式解决:

webAppContext.setConfigurations(new Configuration[] {
    new WebXmlConfiguration(),
    new AnnotationConfiguration() {
        @Override
        public void preConfigure(WebAppContext context) throws Exception {
            MultiMap<String> map = new MultiMap<String>();
            map.add(WebApplicationInitializer.class.getName(), MyWebApplicationInitializerImpl.class.getName());
            context.setAttribute(CLASS_INHERITANCE_MAP, map);
            _classInheritanceHandler = new ClassInheritanceHandler(map);
        }
    }
});

Jetty 9.0.1 contains an enhancement which allows for scanning of annotations of non-jar resources (ie classes) on the container classpath. Jetty 9.0.1包含一个增强功能,允许在容器类路径上扫描非jar资源(即类)的注释。 See comment #5 on the following issue for how to use it: 有关如何使用它,请参阅以下问题的评论#5:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=404176#c5 https://bugs.eclipse.org/bugs/show_bug.cgi?id=404176#c5

Jan 一月

The code below did the trick in my maven project: 下面的代码完成了我的maven项目中的技巧:

public static void main(String[] args) throws Exception {
    Server server = new Server();
    ServerConnector scc = new ServerConnector(server);
    scc.setPort(Integer.parseInt(System.getProperty("jetty.port", "8080")));
    server.setConnectors(new Connector[] { scc });

    WebAppContext context = new WebAppContext();
    context.setServer(server);
    context.setContextPath("/");
    context.setWar("src/main/webapp");
    context.getMetaData().addContainerResource(new FileResource(new File("./target/classes").toURI()));
    context.setConfigurations(new Configuration[]{
            new WebXmlConfiguration(),
            new AnnotationConfiguration()
    });

    server.setHandler(context);

    try {
        System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP");
        System.out.println(String.format(">>> open http://localhost:%s/", scc.getPort()));
        server.start();
        while (System.in.available() == 0) {
            Thread.sleep(5000);
        }
        server.stop();
        server.join();
    } catch (Throwable t) {
        t.printStackTrace();
        System.exit(100);
    }

}

Based on my testing and this thread http://forum.springsource.org/showthread.php?127152-WebApplicationInitializer-not-loaded-with-embedded-Jetty I don't think it works at the moment. 基于我的测试和这个主题http://forum.springsource.org/showthread.php?127152-WebApplicationInitializer-not-loaded-with-embedded-Jetty我认为它现在不起作用。 If you look in AnnotationConfiguration.configure: 如果你查看AnnotationConfiguration.configure:

   parseContainerPath(context, parser);
   // snip comment
   parseWebInfClasses(context, parser);
   parseWebInfLib (context, parser);

it seems coupled to a war-like deployment rather than embedded. 它似乎与战争式部署相结合,而不是嵌入式。

Here is an example using Spring MVC and embedded Jetty that might be more useful: 以下是使用Spring MVC和嵌入式Jetty的示例,它可能更有用:

http://www.jamesward.com/2012/08/13/containerless-spring-mvc http://www.jamesward.com/2012/08/13/containerless-spring-mvc

It creates the Spring servlet directly rather then relying on annotations. 它直接创建Spring servlet,而不是依赖注释。

To those experiencing this lately, it appears this gets around the issue: 对于那些最近遇到这种情况的人来说,这似乎解决了这个问题:

@Component
public class Initializer implements WebApplicationInitializer {

    private ServletContext servletContext;

    @Autowired
    public WebInitializer(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @PostConstruct
    public void onStartup() throws ServletException {
        onStartup(servletContext);
    }

    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("onStartup");
    }
}

To make it work on Jetty 9 set attribute AnnotationConfiguration.CLASS_INHERITANCE_MAP on WebAppContext 要使它在JetApp 9上工作,请在WebAppContext上设置属性AnnotationConfiguration.CLASS_INHERITANCE_MAP

webAppContext.setAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP, createClassMap());

And here is how to create this map: 以下是如何创建此地图:

private ClassInheritanceMap createClassMap() {
    ClassInheritanceMap classMap = new ClassInheritanceMap();
    ConcurrentHashSet<String> impl = new ConcurrentHashSet<>();
    impl.add(MyWebAppInitializer.class.getName());
    classMap.put(WebApplicationInitializer.class.getName(), impl);
    return classMap;
}

I placed that solution on gitHub 我把这个解决方案放在gitHub上

What about just setting the context attribute that tells the scanner which things belong on the container classpath that need to be scanned? 那么只设置context属性告诉扫描器哪些东西属于需要扫描的容器类路径?

context attribute: org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern . context属性:org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern。 /servlet-api-[^/] .jar$ / servlet-api - [^ /] .jar $

It is designed to be used with jar names, but you could just match everything. 它被设计用于jar名称,但你可以匹配所有内容。

You'd need to use the WebInfConfiguration as well as the AnnotationConfiguration classes. 您需要使用WebInfConfiguration以及AnnotationConfiguration类。

cheers Jan 欢呼Jan

In our case these lines helped in Jetty startup code: 在我们的例子中,这些行有助于Jetty启动代码:

    ClassList cl = Configuration.ClassList.setServerDefault(server);
    cl.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");

Jetty 9 version of "magomarcelo" answer: Jetty 9版“magomarcelo”回答:

        context.setConfigurations(
            new org.eclipse.jetty.webapp.Configuration[] { new WebXmlConfiguration(), new AnnotationConfiguration() {
                @Override
                public void preConfigure(WebAppContext context) throws Exception {
                    final ClassInheritanceMap map = new ClassInheritanceMap();
                    final ConcurrentHashSet<String> set = new ConcurrentHashSet<>();
                    set.add(MyWebAppInitializer.class.getName());
                    map.put(WebApplicationInitializer.class.getName(), set);
                    context.setAttribute(CLASS_INHERITANCE_MAP, map);
                    _classInheritanceHandler = new ClassInheritanceHandler(map);
                }
            } });

For Jetty 9, if you have webjars, the solution provided does not work straight away as those Jars need to be on the classpath and the JAR contents need to be available as resources for your webapp. 对于Jetty 9,如果你有webjars,提供的解决方案不会立即生效,因为这些Jars需要在类路径上,并且JAR内容需要作为webapp的资源。 So, for that to work together with webjars, the config would have to be: 因此,为了与webjars一起工作,配置必须是:

context.setExtraClasspath(pathsToWebJarsCommaSeparated);
context.setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, ".*\\.jar$");
context.setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, ".*\\.jar$");
context.setConfigurations(
        new org.eclipse.jetty.webapp.Configuration[] { 
        new WebInfConfiguration(), new MetaInfConfiguration(),
        new AnnotationConfiguration() {
            @Override
            public void preConfigure(WebAppContext context) throws Exception {
                final ClassInheritanceMap map = new ClassInheritanceMap();
                final ConcurrentHashSet<String> set = new ConcurrentHashSet<>();
                set.add(MyWebAppInitializer.class.getName());
                map.put(WebApplicationInitializer.class.getName(), set);
                context.setAttribute(CLASS_INHERITANCE_MAP, map);
                _classInheritanceHandler = new ClassInheritanceHandler(map);
            }
        } });

The order here is important ( WebInfConfiguration has to come before MetaInf ). 这里的顺序很重要( WebInfConfiguration必须在MetaInf之前 )。

Solution that worked for me and does not involve scanning, but uses WebApplicationInitializer class that you provide. 解决方案对我有用,不涉及扫描,但使用您提供的WebApplicationInitializer类。 Jetty version: 9.2.20 码头版本:9.2.20

public class Main {

public static void main(String... args) throws Exception {
    Properties properties = new Properties();
    InputStream stream = Main.class.getResourceAsStream("/WEB-INF/application.properties");
    properties.load(stream);
    stream.close();
    PropertyConfigurator.configure(properties);

    WebAppContext webAppContext = new WebAppContext();
    webAppContext.setResourceBase("resource");
    webAppContext.setContextPath(properties.getProperty("base.url"));
    webAppContext.setConfigurations(new Configuration[] {
        new WebXmlConfiguration(),
        new AnnotationConfiguration() {
            @Override
            public void preConfigure(WebAppContext context) {
                ClassInheritanceMap map = new ClassInheritanceMap();
                map.put(WebApplicationInitializer.class.getName(), new ConcurrentHashSet<String>() {{
                    add(WebInitializer.class.getName());
                    add(SecurityWebInitializer.class.getName());
                }});
                context.setAttribute(CLASS_INHERITANCE_MAP, map);
                _classInheritanceHandler = new ClassInheritanceHandler(map);
            }
        }
    });

    Server server = new Server(Integer.parseInt(properties.getProperty("base.port")));
    server.setHandler(webAppContext);
    server.start();
    server.join();
}
}

The source (in russian) of this code snippet is here: https://habrahabr.ru/post/255773/ 这段代码的来源(俄语)在这里: https//habrahabr.ru/post/255773/

did a simple maven project to demonstrate how it can be done cleanly. 做了一个简单的maven项目来演示如何干净利落地完成它。

    public class Console {
    public static void main(String[] args) {
        try {
            Server server = new Server(8080);

            //Set a handler to handle requests.
            server.setHandler(getWebAppContext());

            //starts to listen at 0.0.0.0:8080
            server.start();
            server.join();
        } catch (Exception e) {
            log.error("server exited with exception", e);
        }
    }

    private static WebAppContext getWebAppContext() {
        final WebAppContext webAppContext = new WebAppContext();

        //route all requests via this web-app.
        webAppContext.setContextPath("/");

        /*
         * point to location where the jar into which this class gets packaged into resides.
         * this could very well be the target directory in a maven development build.
         */
        webAppContext.setResourceBase("directory_where_the_application_jar_exists");

        //no web inf for us - so let the scanning know about location of our libraries / classes.
        webAppContext.getMetaData().setWebInfClassesDirs(Arrays.asList(webAppContext.getBaseResource()));

        //Scan for annotations (servlet 3+)
        final AnnotationConfiguration configuration = new AnnotationConfiguration();
        webAppContext.setConfigurations(new Configuration[]{configuration});

        return webAppContext;
    }
}

and that's all - the spring WebApplicationInitializer that you use will get detected without explicitly letting jetty server know about the existence of such an app initializer. 而这就是全部 - 您使用的Spring WebApplicationInitializer将被检测到,而不会明确地让jetty服务器知道这样的应用程序初始化程序的存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM