如何在Java中注册一个Servlet

2023/05/12

一、简介

本文将概述如何在 Jakarta EE 和 Spring Boot 中注册 servlet。具体来说,我们将研究两种在 Jakarta EE 中注册 Java Servlet 的方法——一种使用web.xml文件,另一种使用注解。然后我们将使用 XML 配置、Java 配置并通过可配置属性在 Spring Boot 中注册 servlet。

可以在此处找到一篇关于 servlet 的精彩介绍性文章。

2. 在 Jakarta EE 中注册 Servlet

让我们来看看在 Jakarta EE 中注册 servlet 的两种方法。首先,我们可以通过web.xml注册一个 servlet 。或者,我们可以使用 Jakarta EE @WebServlet注解。

2.1. 通过web.xml

在 Jakarta EE 应用程序中注册 servlet 的最常见方法是将其添加到web.xml文件中:

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
    <servlet-name>Example</servlet-name>
    <servlet-class>com.baeldung.Example</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Example</servlet-name>
    <url-pattern>/Example</url-pattern>
</servlet-mapping>

如你所见,这涉及两个步骤:(1) 将我们的 servlet 添加到servlet标记,确保还指定 servlet 所在类的源路径,以及 (2) 指定 servlet 将公开的 URL 路径在url-pattern标签中。

Jakarta EE web.xml文件通常位于WebContent/WEB-INF中。

2.2. 通过注解

现在让我们在自定义 servlet 类上使用@WebServlet注解注册我们的 servlet。这消除了server.xml中的 servlet 映射和web.xml中的 servlet 注册的需要:

@WebServlet(
  name = "AnnotationExample",
  description = "Example Servlet Using Annotations",
  urlPatterns = {"/AnnotationExample"}
)
public class Example extends HttpServlet {	
 
    @Override
    protected void doGet(
      HttpServletRequest request, 
      HttpServletResponse response) throws ServletException, IOException {
 
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<p>Hello World!</p>");
    }
}

上面的代码演示了如何将该注解直接添加到 servlet。该 servlet 仍可在与以前相同的 URL 路径中使用。

3.在Spring Boot中注册Servlets

现在我们已经展示了如何在 Jakarta EE 中注册 servlet,让我们来看看在 Spring Boot 应用程序中注册 servlet 的几种方法。

3.1. 程序化注册

Spring Boot 支持 Web 应用程序的 100% 编程配置。

首先,我们将实现WebApplicationInitializer接口,然后实现 WebMvcConfigurer接口,它允许你覆盖预设的默认值,而不必指定每个特定的配置设置,从而节省你的时间并允许你使用几个经过验证的真实设置-开箱即用。

让我们看一个示例WebApplicationInitializer实现:

public class WebAppInitializer implements WebApplicationInitializer {
 
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext ctx
          = new AnnotationConfigWebApplicationContext();
        ctx.register(WebMvcConfigure.class);
        ctx.setServletContext(container);

        ServletRegistration.Dynamic servlet = container.addServlet(
          "dispatcherExample", new DispatcherServlet(ctx));
        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
     }
}

接下来我们来实现WebMvcConfigurer 接口:

@Configuration
public class WebMvcConfigure implements WebMvcConfigurer {

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver
          = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(
      DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/")
          .addResourceLocations("/resources/").setCachePeriod(3600)
          .resourceChain(true).addResolver(new PathResourceResolver());
    }
}

上面我们明确指定了 JSP servlet 的一些默认设置,以支持.jsp视图和静态资源服务。

3.2. XML配置

在 Spring Boot 中配置和注册 servlet 的另一种方法是通过web.xml:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/dispatcher.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

用于在 Spring 中指定配置的web.xml与 Jakarta EE 中的类似。在上面,你可以看到我们如何通过servlet标记下的属性指定更多参数。

这里我们使用另一个XML来完成配置:

<beans ...>
    
    <context:component-scan base-package="com.baeldung"/>

    <bean 
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

请记住,你的 Spring web.xml通常位于src/main/webapp/WEB-INF中。

3.3. 结合 XML 和程序化注册

让我们将 XML 配置方法与 Spring 的编程配置相结合:

public void onStartup(ServletContext container) throws ServletException {
   XmlWebApplicationContext xctx = new XmlWebApplicationContext();
   xctx.setConfigLocation('classpath:/context.xml');
   xctx.setServletContext(container);

   ServletRegistration.Dynamic servlet = container.addServlet(
     "dispatcher", new DispatcherServlet(ctx));
   servlet.setLoadOnStartup(1);
   servlet.addMapping("/");
}

我们还配置调度程序 servlet:

<beans ...>

    <context:component-scan base-package="com.baeldung"/>
    <bean class="com.baeldung.configuration.WebAppInitializer"/>
</beans>

3.4. Bean注册

我们还可以使用ServletRegistrationBean以编程方式配置和注册我们的 servlet 。下面我们将这样做以注册一个HttpServlet(它实现了javax.servlet.Servlet接口):

@Bean
public ServletRegistrationBean exampleServletBean() {
    ServletRegistrationBean bean = new ServletRegistrationBean(
      new CustomServlet(), "/exampleServlet/");
    bean.setLoadOnStartup(1);
    return bean;
}

这种方法的主要优点是它使你能够将多个 servlet 以及不同种类的 servlet 添加到你的 Spring 应用程序。

我们将使用一个更简单的HttpServlet子类实例,而不是仅仅使用DispatcherServlet,它是一种更具体的HttpServlet ,也是我们在 3.1 节中探索的WebApplicationInitializer编程配置方法中最常用的一种,它公开了四个基本的HttpRequest操作通过四个函数:doGet()、doPost()、doPut()和doDelete(),就像在 Jakarta EE 中一样。

请记住,HttpServlet 是一个抽象类(因此无法实例化)。不过,我们可以轻松地创建一个自定义扩展:

public class CustomServlet extends HttpServlet{
    ...
}

4. 使用属性注册 Servlet

另一种虽然不常见的配置和注册 servlet 的方法是使用通过PropertyLoader、PropertySource或PropertySources实例对象加载到应用程序中的自定义属性文件。

这提供了一种中间类型的配置和以其他方式自定义application.properties的能力,这为非嵌入式 servlet 提供了很少的直接配置。

4.1. 系统属性方法

我们可以将一些自定义设置添加到我们的application.properties文件或另一个属性文件中。让我们添加一些设置来配置我们的DispatcherServlet:

servlet.name=dispatcherExample
servlet.mapping=/dispatcherExampleURL

让我们将自定义属性加载到我们的应用程序中:

System.setProperty("custom.config.location", "classpath:custom.properties");

现在我们可以通过以下方式访问这些属性:

System.getProperty("custom.config.location");

4.2. 自定义属性方法

让我们从custom.properties文件开始:

servlet.name=dispatcherExample
servlet.mapping=/dispatcherExampleURL

然后我们可以使用普通的 Property Loader:

public Properties getProperties(String file) throws IOException {
  Properties prop = new Properties();
  InputStream input = null;
  input = getClass().getResourceAsStream(file);
  prop.load(input);
  if (input != null) {
      input.close();
  }
  return prop;
}

现在我们可以将这些自定义属性作为常量添加到我们的WebApplicationInitializer实现中:

private static final PropertyLoader pl = new PropertyLoader(); 
private static final Properties springProps
  = pl.getProperties("custom_spring.properties"); 

public static final String SERVLET_NAME
  = springProps.getProperty("servlet.name"); 
public static final String SERVLET_MAPPING
  = springProps.getProperty("servlet.mapping");

然后我们可以使用它们来配置我们的调度程序 servlet:

ServletRegistration.Dynamic servlet = container.addServlet(
  SERVLET_NAME, new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping(SERVLET_MAPPING);

这种方法的优点是不需要.xml维护,但具有易于修改的配置设置,不需要重新部署代码库。

4.3. PropertySource方法_

完成上述任务的更快方法是使用 Spring 的PropertySource,它允许访问和加载配置文件。

PropertyResolver是由ConfigurableEnvironment实现的接口,它使应用程序属性在 servlet 启动和初始化时可用:

@Configuration 
@PropertySource("classpath:/com/yourapp/custom.properties") 
public class ExampleCustomConfig { 
    @Autowired 
    ConfigurableEnvironment env; 

    public String getProperty(String key) { 
        return env.getProperty(key); 
    } 
}

上面,我们将依赖项自动装配到类中并指定自定义属性文件的位置。然后我们可以通过调用传入字符串值的函数getProperty()来获取显着属性。

4.4. PropertySource 程序化方法

我们可以将上述方法(涉及获取属性值)与下面的方法(允许我们以编程方式指定这些值)结合起来:

ConfigurableEnvironment env = new StandardEnvironment(); 
MutablePropertySources props = env.getPropertySources(); 
Map map = new HashMap(); map.put("key", "value"); 
props.addFirst(new MapPropertySource("Map", map));

我们已经创建了一个将键链接到值的映射,然后将该映射添加到PropertySources以根据需要启用调用。

5. 注册嵌入式 Servlet

最后,我们还将了解 Spring Boot 中嵌入式 servlet 的基本配置和注册。

嵌入式 servlet 提供完整的 Web 容器(Tomcat、Jetty 等)功能,而无需单独安装或维护 Web 容器。

你可以为简单的实时服务器部署添加所需的依赖项和配置,只要此类功能得到轻松、紧凑和快速的支持。

我们将只关注如何执行此 Tomcat,但可以对 Jetty 和替代方案采用相同的方法。

让我们在pom.xml中指定嵌入式 Tomcat 8 Web 容器的依赖项:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
     <artifactId>tomcat-embed-core</artifactId>
     <version>8.5.11</version>
</dependency>

现在让我们添加成功将 Tomcat 添加到Maven 在构建时生成的.war所需的标签:

<build>
    <finalName>embeddedTomcatExample</finalName>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>appassembler-maven-plugin</artifactId>
            <version>2.0.0</version>
            <configuration>
                <assembleDirectory>target</assembleDirectory>
                <programs>
                    <program>
                        <mainClass>launch.Main</mainClass>
                        <name>webapp</name>
                    </program>
            </programs>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

如果你使用的是 Spring Boot,则可以将 Spring 的spring-boot-starter-tomcat依赖项添加到你的pom.xml中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

5.1. 通过属性注册

Spring Boot 支持通过application.properties配置大多数可能的 Spring 设置。在将必要的嵌入式 servlet 依赖项添加到你的pom.xml之后,你可以使用几个这样的配置选项来自定义和配置你的嵌入式 servlet:

server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServlet 
server.jsp-servlet.registered=true
server.port=8080
server.servlet-path=/

以上是一些可用于配置DispatcherServlet和静态资源共享的应用程序设置。嵌入式 servlet、SSL 支持和会话的设置也可用。

配置参数确实太多,无法在此处列出,但你可以在Spring Boot 文档中查看完整列表。

5.2. 通过 YAML 配置

同样,我们可以使用 YAML 配置我们的嵌入式 servlet 容器。这需要使用专门的 YAML 属性加载器——YamlPropertySourceLoader——它公开我们的 YAML 并使其中的键和值可在我们的应用程序中使用。

YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
PropertySource<?> yamlProps = sourceLoader.load("yamlProps", resource, null);

5.3. 通过 TomcatEmbeddedServletContainerFactory 进行编程配置

嵌入式 servlet 容器的编程配置可以通过EmbeddedServletContainerFactory的子类实例实现。例如,你可以使用TomcatEmbeddedServletContainerFactory来配置嵌入式 Tomcat servlet。

TomcatEmbeddedServletContainerFactory包装org.apache.catalina.startup.Tomcat对象,提供额外的配置选项:

@Bean
public ConfigurableServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcatContainerFactory
      = new TomcatServletWebServerFactory();
    return tomcatContainerFactory;
}

然后我们可以配置返回的实例:

tomcatContainerFactory.setPort(9000);
tomcatContainerFactory.setContextPath("/springboottomcatexample");

这些特定设置中的每一个都可以使用前面描述的任何方法进行配置。

我们也可以直接访问和操作org.apache.catalina.startup.Tomcat对象:

Tomcat tomcat = new Tomcat();
tomcat.setPort(port);
tomcat.setContextPath("/springboottomcatexample");
tomcat.start();

六,总结

在本文中,我们回顾了在 Jakarta EE 和 Spring Boot 应用程序中注册 Servlet 的几种方法。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章