1. 簡介
本文將提供對如何在 Jakarta EE 和 Spring Boot 中註冊 Servlet 的概述。 尤其是,我們將探討兩種在 Jakarta EE 中註冊 Java Servlet 的方法:一種使用 web.xml 文件,另一種使用註解。 此外,我們還將使用 XML 配置、Java 配置和可配置屬性在 Spring Boot 中註冊 Servlet。
關於 Servlet 的優秀入門文章可以在這裏找到。
2. 在 Jakarta EE 中註冊 Servlet
讓我們回顧一下在 Jakarta EE 中註冊 Servlet 的兩種方法。第一種方法是使用 <em >web.xml</em > 文件進行註冊。 另一種方法是使用 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) 在 url-pattern 標籤中指定 servlet 將暴露的 URL 路徑。
Jakarta EE 中的 web.xml 文件通常位於 WebContent/WEB-INF。
2.2. 通過註解進行註冊
現在,我們使用 <em @WebServlet</em> 註解在自定義 Servlet 類上註冊 Servlet。 這消除了在 <em server.xml</em> 中進行 Servlet 映射以及在 <em web.xml</em> 中註冊 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 中註冊 Servlet
現在我們已經展示瞭如何在 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 視圖和靜態資源服務。
3.2. XML 配置
通過 <em >web.xml</em >> 也是一種配置和註冊servlet的方式。
<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("/");
}讓我們也配置dispatcher servlet:
<beans ...>
<context:component-scan base-package="com.baeldung"/>
<bean class="com.baeldung.configuration.WebAppInitializer"/>
</beans>3.4. 通過 Bean 註冊
我們可以使用 <em >ServletRegistrationBean</em> 編程方式配置和註冊我們的 Servlet。下面我們將使用它來註冊一個 <em >HttpServlet</em> (它實現了 <em >javax.servlet.Servlet</em> 接口):
@Bean
public ServletRegistrationBean exampleServletBean() {
ServletRegistrationBean bean = new ServletRegistrationBean(
new CustomServlet(), "/exampleServlet/*");
bean.setLoadOnStartup(1);
return bean;
}這種方法的優勢在於,它允許您向 Spring 應用程序添加多個 Servlet 以及不同類型的 Servlet。
與其僅僅利用 DispatcherServlet,這是一種更具體的 HttpServlet,並且在我們在第 3.1 節中探索的程序化 Web 應用程序初始化器中被廣泛使用,我們將會使用一個更簡單的 HttpServlet 子類實例,該實例通過四個函數來暴露四種基本 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");我們還可以利用它們來,例如配置我們的DispatcherServlet:
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 在構建時產生的 <em>.war</em> 文件中:
<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 支持通過 <em >application.properties</em >> 配置大部分可能的 Spring 設置。 在將必要的嵌入式 Servlet 依賴添加到你的 <em >pom.xml</em >> 後,你可以使用多種配置選項自定義和配置你的嵌入式 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 屬性加載器——<em >YamlPropertySourceLoader</em>——它會暴露我們的 YAML 並使其中的鍵和值可供在我們的應用程序中使用。
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
PropertySource<?> yamlProps = sourceLoader.load("yamlProps", resource, null);5.3. 通過 TomcatEmbeddedServletContainerFactory 進行程序化配置
通過對 EmbeddedServletContainerFactory 的子類實例進行配置,可以實現嵌入式 Servlet 容器的程序化配置。例如,可以使用 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();6. 結論
在本文中,我們回顧了在 Jakarta EE 和 Spring Boot 應用程序中註冊 Servlet 的幾種方法。