日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

是时候抛弃web.xml了?

發(fā)布時間:2025/4/5 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 是时候抛弃web.xml了? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

你是否再為配置文件web.xml容易出錯而煩惱?是否為web.xml文件存放位置而不知所措?是否為web.xml為什么要這樣配?怎么才能更好的配置web.xml而煩惱?那么一種新的方式出現(xiàn)了:

spring提供了支持servlet 3+以上的編程方式,它可以替換或者和web.xml共存的方式工作。其相關(guān)類如下:

WebApplicationInitializer

  傳統(tǒng)上,我們基于web.xml這種方式來配置web應(yīng)用,而WebApplicationInitializer的實現(xiàn)支持在servlet 3.0以上的環(huán)境里通過編程的方式來配置ServletContext,這種方式既可以替換web.xml這種方式,也可以和web.xml這種方式共存。

  這種SPI的實現(xiàn)通常由SpringServletContainerInitializer來自動發(fā)現(xiàn),SpringServletContainerInitializer可以被servlet 3.0以上的容器自動啟動。詳細請參考下面的章節(jié)。示例如下:

? ?傳統(tǒng)基于xml的方式

? ? 絕大多數(shù)spring開發(fā)者構(gòu)建web應(yīng)用時需要注冊spring DispatcherServlet到WEB/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-config.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>

? ? ? ?基于編程方式的WebApplicationInitializer

下面基于WebApplicationInitializer樣式的代碼等同于DispatcherServlet的注冊邏輯:

public class MyWebAppInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext container) {XmlWebApplicationContext appContext = new XmlWebApplicationContext();appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");ServletRegistration.Dynamic dispatcher =container.addServlet("dispatcher", new DispatcherServlet(appContext));dispatcher.setLoadOnStartup(1);dispatcher.addMapping("/");}}

上面的實現(xiàn),還可以通過擴展org.springframework.web.servlet.support.AbstractDispatcherServletInitializer實現(xiàn)。

  如上所示,歸功于servlet3.0的ServletContext#addServlet方法,我們注冊一個DispatcherServlet的實例,這意味著DispatcherServlet可以如其他Object一樣,接受在應(yīng)用上下文中通過構(gòu)造器進行注入。

  這種方式不但簡單還很明了。不需要關(guān)注init-param的處理等等,僅有通常的javaBean樣式的屬性和構(gòu)造參數(shù)。可以在DispatcherServlet注入之前,盡可能的自由的創(chuàng)建spring context、使用spring context。

  絕大部分spring web組件已經(jīng)更新來支持這種注冊方式,你會發(fā)現(xiàn)DispatcherServlet、FrameworkServlet、ContextLoaderListener和DelegatingFilterProxy現(xiàn)在都支持構(gòu)造參數(shù)。

  盡管個別組件(非spring的,其他第三方的)沒有更新到支持WebApplicationInitializer的使用,它們?nèi)匀豢梢允褂谩ervlet 3.0的ServletContext api支持編碼式設(shè)置init-params,context-param等的屬性。

  基于編碼式的配置

  上例中,WEB/web.xml可以通過WebApplicationInitializer樣式的代碼完全替換掉,但真正的dispatcher-config.xml spring配置文件仍然是基于xml方式的。WebApplicationInitializer也是一個很棒的方式來進行spring的基于編程方式的配置類,詳情參考org.springframework.context.annotation.Configuration。

? ? ?下面的例子中,將使用spring的

org.springframework.web.context.support.AnnotationConfigWebApplicationContext
類來替代XmlWebApplicationContext,用戶自定義的@Configuration配置類AppConfig和DispatcherConfig來替換spring的xml文件來重構(gòu)上面的例子。這個示例也有一些超出部分,用來展示root application context的的通用配置和ContextLoaderListener的注冊:

public class MyWebAppInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext container) {// Create the 'root' Spring application contextAnnotationConfigWebApplicationContext rootContext =new AnnotationConfigWebApplicationContext();rootContext.register(AppConfig.class);// Manage the lifecycle of the root application contextcontainer.addListener(new ContextLoaderListener(rootContext));// Create the dispatcher servlet's Spring application contextAnnotationConfigWebApplicationContext dispatcherContext =new AnnotationConfigWebApplicationContext();dispatcherContext.register(DispatcherConfig.class);// Register and map the dispatcher servletServletRegistration.Dynamic dispatcher =container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));dispatcher.setLoadOnStartup(1);dispatcher.addMapping("/");}}

上面的示例的另一種實現(xiàn)方式,可以通過擴展org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer來實現(xiàn)。

注意,WebApplicationInitializer的實現(xiàn)是自動發(fā)現(xiàn)的,因此無需在你的應(yīng)用中打包。

  WebApplicationInitializer執(zhí)行順序

WebApplicationInitializer的實現(xiàn)可以通過@order來注解也可以通過實現(xiàn)spring的org.springframework.core.Ordered接口,如果這樣,就根據(jù)優(yōu)先級去觸發(fā)。spring為用戶提供了一種在servlet container初始化時保證執(zhí)行順序的機制。使用這種特性的應(yīng)用場景比較罕見,因為典型的應(yīng)用通常在一個單獨的WebApplicationInitializer中集中所有的容器初始化。

? 附加說明

  web.xml版本信息

? WEB/web.xml和WebApplicationInitializer不是相斥的。例如web.xml可以注冊一個servlet,WebApplicationInitializer可以注冊另外一個servlet。一個WebApplicationInitializer甚至可以通過方法如ServletContext#getServletRegistration(String)來修改web.xml中的注冊信息。然而,若應(yīng)用中出現(xiàn)web.xml,它的version屬性必須設(shè)置成3.0或者以上,否則ServletContainerInitializer將會在servlet容器啟動時被忽略啟動。

  tomcat下映射到"/"

? ?apache tomcat映射它內(nèi)部的DefaultServlet到"/",并且當(dāng)tomcat版本小于7.0.14時,這個映射屬性不能通過編碼重寫。7.0.15解決了這個問題。重寫"/"映射已經(jīng)在glassFish3.1中進行了驗證確認。

public interface WebApplicationInitializer {/*** Configure the given {@link ServletContext} with any servlets, filters, listeners* context-params and attributes necessary for initializing this web application. See* examples {@linkplain WebApplicationInitializer above}.* @param servletContext the {@code ServletContext} to initialize* @throws ServletException if any call against the given {@code ServletContext}* throws a {@code ServletException}*/void onStartup(ServletContext servletContext) throws ServletException;}

1?SpringServletContainerInitializer

  和傳統(tǒng)基于web.xml的方式不同,servlet 3.0?ServletContainerInitializer 使用spring的WebApplicationInitializer來支持對servlet container的基于編程的配置支持。

 工作機制

  假定spring-web模塊的jar都出現(xiàn)在classpath上,在容器啟動時,servlet 3.0兼容的容器將會加載類,并初始化,然后觸發(fā)它的onStartup方法。Jar服務(wù)Api 方法ServiceLoader#load(class)發(fā)現(xiàn)spring-web模塊的META-INF/services/javax.servlet.ServletContainerInitializer服務(wù)提供配置文件,詳情參考http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider

  和web.xml共用

  一個web應(yīng)用在啟動階段選擇限制classpath 掃描的servlet container的數(shù)量的方式有兩種,一種通過web.xml的屬性metadata-complete,它控制server注解的掃描。另一種是通過web.xml中的absolute-ordering屬性,它控制哪些web片段(例如jar文件)允許servletContainerInitializer掃描。當(dāng)使用這些特色,springServletContainerInitializer通過增加spring_web到web.xml的命名片段中來啟用這些,如下所示:

<absolute-ordering><name>some_web_fragment</name><name>spring_web</name></absolute-ordering>

?與spring的WebApplicationInitializer的關(guān)系

spring的WebApplicationInitializer spi僅僅包含了一個方法WebApplicationInitializer#onStartup(ServletContext),類似于ServletContainerInitializer#onStartup(Set, ServletContext)。SpringServletContainerInitializer負責(zé)初始化并對用戶定義的WebApplicationInitializer代理servletContext。然后負責(zé)讓每個WebApplicationInitializer去做servletContext初始化的具體工作。代理的精確過程描述在下文的onStartup方法。

?

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer {/*** Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}* implementations present on the application classpath.* <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},* Servlet 3.0+ containers will automatically scan the classpath for implementations* of Spring's {@code WebApplicationInitializer} interface and provide the set of all* such types to the {@code webAppInitializerClasses} parameter of this method.* <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,* this method is effectively a no-op. An INFO-level log message will be issued notifying* the user that the {@code ServletContainerInitializer} has indeed been invoked but that* no {@code WebApplicationInitializer} implementations were found.* <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,* they will be instantiated (and <em>sorted</em> if the @{@link* org.springframework.core.annotation.Order @Order} annotation is present or* the {@link org.springframework.core.Ordered Ordered} interface has been* implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}* method will be invoked on each instance, delegating the {@code ServletContext} such* that each instance may register and configure servlets such as Spring's* {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},* or any other Servlet API componentry such as filters.* @param webAppInitializerClasses all implementations of* {@link WebApplicationInitializer} found on the application classpath* @param servletContext the servlet context to be initialized* @see WebApplicationInitializer#onStartup(ServletContext)* @see AnnotationAwareOrderComparator*/@Overridepublic void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());}catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}

?

轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/6491067.html

總結(jié)

以上是生活随笔為你收集整理的是时候抛弃web.xml了?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。