中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做網(wǎng)站掙錢不廣告有限公司

做網(wǎng)站掙錢不,廣告有限公司,湖北seo排名診斷,展廳設(shè)計(jì)軟件1、Spring整合SpringMVC 特性: 說到Spring整合SpringMVC唯一的體現(xiàn)就是父子容器: 通常我們會(huì)設(shè)置父容器(Spring)管理Service、Dao層的Bean, 子容器(SpringMVC)管理Controller的Bean .子容器可以訪問父容器的Bean, 父容器無法訪…

1、Spring整合SpringMVC

特性:

說到Spring整合SpringMVC唯一的體現(xiàn)就是父子容器:

  • 通常我們會(huì)設(shè)置父容器(Spring)管理Service、Dao層的Bean, 子容器(SpringMVC)管理Controller的Bean .
  • 子容器可以訪問父容器的Bean, 父容器無法訪問子容器的Bean。

實(shí)現(xiàn):

相信大家在SSM框架整合的時(shí)候都曾在web.xml配置過這段:

<!--spring 基于web應(yīng)用的啟動(dòng)-->
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--全局參數(shù):spring配置文件-->
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-core.xml</param-value>
</context-param>
<!--前端調(diào)度器servlet-->
<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--設(shè)置配置文件的路徑--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value>
</init-param><!--設(shè)置啟動(dòng)即加載--><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern>

但是它的作用是什么知道嗎?

0

有人可能只知道DispatcherServlet叫前端控制器,是SpringMVC處理前端請(qǐng)求的一個(gè)核心調(diào)度器

那它為什么能處理請(qǐng)求?處理之前做了什么準(zhǔn)備工作呢?又是怎么和Spring結(jié)合起來的呢?

為什么有了DispatcherServlet還要個(gè)ContextLoaderListener, 配一個(gè)不行嗎?干嘛要配倆啊?

看完本文你就會(huì)有答案!

0

還有人可能會(huì)覺得, 我現(xiàn)在都用SpringBoot開發(fā), 哪還要配這玩意.......

0

這就是典型的SpringBoot使用后遺癥,SpringBoot降低了使用難度,但是從某種程度來說,也讓初級(jí)的程序員變得更加小白,把實(shí)現(xiàn)原理都隱藏起來了而我們只管用,一旦涉及擴(kuò)展就束手無策。

那當(dāng)然我們今天不講SpringBoot,我們今天用貼近SpringBoot的方式來講SpringMVC。也就是零配置(零xml)的放式來說明SpringMVC的原理!!

此方式作為我們本文重點(diǎn)介紹,也是很多人缺失的一種方式, 其實(shí)早在Spring3+就已經(jīng)提供, 只不過我們直到SpringBoot才使用該方式進(jìn)行自動(dòng)配置, 這也是很多人從xml調(diào)到SpringBoot不適應(yīng)的原因, 因?yàn)槟闳笔Я诉@個(gè)版本。 所以我們以這種方式作為源碼切入點(diǎn)既可以理解到XML的方式又能兼顧到SpringBoot的方式 。

2、零配置SpringMVC實(shí)現(xiàn)方式:

那沒有配置就需要省略掉web.xml 怎么省略呢?

在Servlet3.0提供的規(guī)范文檔中可以找到2種方式:

  • 注解的方式
  1. @WebServlet
  2. @WebFilter
  3. @WebListener

但是這種方式不利于擴(kuò)展, 并且如果編寫在jar包中tomcat是無法感知到的。

  • SPI的方式

在Serlvet3-1的規(guī)范手冊(cè)中:就提供了一種更加易于擴(kuò)展可用于共享庫可插拔的一種方式,參見8.2.4:

也就是讓你在應(yīng)用META-INF/services 路徑下 放一個(gè) javax.servlet.ServletContainerInitailizer ——即SPI規(guī)范

SPI 我們叫他服務(wù)接口擴(kuò)展,(Service Provider Interface) 直譯服務(wù)提供商接口, 不要被這個(gè)名字唬到了, 其實(shí)很好理解的一個(gè)東西:

其實(shí)就是根據(jù)Servlet廠商(服務(wù)提供商)提供要求的一個(gè)接口, 在固定的目錄(META-INF/services)放上以接口全類名 為命名的文件, 文件中放入接口的實(shí)現(xiàn)的全類名,該類由我們自己實(shí)現(xiàn),按照這種約定的方式(即SPI規(guī)范),服務(wù)提供商會(huì)調(diào)用文件中實(shí)現(xiàn)類的方法, 從而完成擴(kuò)展。

ok 那我們知道了SPI是什么,我們是不是可以在Web應(yīng)用中,在Servlet的SPI放入對(duì)應(yīng)的接口文件:

0

放入實(shí)現(xiàn)類:

0

通過ServletContext就可以動(dòng)態(tài)注冊(cè)三大組件:以Servlet注冊(cè)為例:

public class TulingSpringServletContainerInitializer extends SpringServletContainerInitializer {@Overridepublic void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {// 通過servletContext動(dòng)態(tài)添加ServletservletContext.addServlet("spiServlet", new HttpServlet() {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("spiServlet--doGet");}}).addMapping("/spiServlet.do");}

?當(dāng)然在SpringMVC中, 這個(gè)接口文件和實(shí)現(xiàn)類都把我們實(shí)現(xiàn)好了,甚至ContextLoaderListener和DispatcherServlet都幫我們注冊(cè)好了,我們只要讓他生效,來,看看他是怎么做的:

3、實(shí)現(xiàn)基于SPI規(guī)范的SpringMVC

TulingStarterInitializer

  • 此類繼承AbstractAnnotationConfigDispatcherServletInitializer 這是個(gè)啥? 待會(huì)我們講原理來介紹
  • getRootConfigClasses 提供父容器的配置類
  • getServletConfigClasses 提供子容器的配置類
  • getServletMappings 設(shè)置DispatcherServlet的映射
public  class TulingStarterInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {/*** 方法實(shí)現(xiàn)說明:IOC 父容器的啟動(dòng)類* @author:xsls* @date:2019/7/31 22:12*/@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{RootConfig.class};}/*** 方法實(shí)現(xiàn)說明 IOC子容器配置 web容器配置* @author:xsls* @date:2019/7/31 22:12*/@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{WebAppConfig.class};}/*** 方法實(shí)現(xiàn)說明* @author:xsls* @return: 我們前端控制器DispatcherServlet的攔截路徑* @exception:* @date:2019/7/31 22:16*/@Overrideprotected String[] getServletMappings() {return new String[]{"/"};

RootConfig

  • 父容器的配置類 =以前的spring.xml
  • 掃描的包排除掉@Controller
@Configuration
@ComponentScan(basePackages = "com.tuling",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value={RestController.class,Controller.class}),@ComponentScan.Filter(type = ASSIGNABLE_TYPE,value =WebAppConfig.class ),
})
public class RootConfig {}

WebAppConfig

  • 子容器的配置類 =以前的spring-mvc.xml
  • 掃描的包:包含掉@Controller
@Configuration
@ComponentScan(basePackages = {"com.tuling"},includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {RestController.class, Controller.class})
},useDefaultFilters =false)
@EnableWebMvc   // ≈<mvc:annotation-driven/>
public class WebAppConfig implements WebMvcConfigurer{/*** 配置攔截器* @return*/@Beanpublic TulingInterceptor tulingInterceptor() {return new TulingInterceptor();}/*** 文件上傳下載的組件* @return*/@Beanpublic MultipartResolver multipartResolver() {CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();multipartResolver.setDefaultEncoding("UTF-8");multipartResolver.setMaxUploadSize(1024*1024*10);return multipartResolver;}/*** 注冊(cè)處理國(guó)際化資源的組件* @return*/
/* @Beanpublic AcceptHeaderLocaleResolver localeResolver() {AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver();return acceptHeaderLocaleResolver;}*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(tulingInterceptor()).addPathPatterns("/*");}/*** 方法實(shí)現(xiàn)說明:配置試圖解析器* @author:xsls* @exception:* @date:2019/8/6 16:23*/@Beanpublic InternalResourceViewResolver internalResourceViewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setSuffix(".jsp");viewResolver.setPrefix("/WEB-INF/jsp/");return viewResolver;}@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new MappingJackson2HttpMessageConverter());}

自己去添加個(gè)Controller進(jìn)行測(cè)試

OK, 現(xiàn)在可以訪問你的SpringMVC了

4、SPI的方式SpringMVC啟動(dòng)原理

接著我們來看看SPI方式的原理是什么:

SpringMVC 大致可以分為 啟動(dòng) 和請(qǐng)求 2大部分, 所以我們本文先研究啟動(dòng)部分

流程圖:

源碼流程

  1. 外置Tomcat啟動(dòng)的時(shí)候通過SPI 找到我們應(yīng)用中的/META-INF/service/javax.servlet.ServletContainerInitializer

0

  1. 調(diào)用SpringServletContainerInitializer.onStartUp()

0

    1. 調(diào)用onStartUp()前會(huì)先找到@HandlesTypes(WebApplicationInitializer.class) 所有實(shí)現(xiàn)了WebApplicationInitializer的類,傳入到OnStartup的webAppInitializerClasses參數(shù)中,并傳入Servlet上下文對(duì)象。
    2. 重點(diǎn)關(guān)注這組類:他們組成了父子容器

0

  1. 找到所有WebApplicationInitializer的實(shí)現(xiàn)類后, 不是接口、不是抽象則通過反射進(jìn)行實(shí)例化(所以,你會(huì)發(fā)現(xiàn)內(nèi)部實(shí)現(xiàn)類都是抽象的,你想讓其起作用我們必須添加一個(gè)自定義實(shí)現(xiàn)類,在下文提供我的自定義實(shí)現(xiàn)類)
  2. 調(diào)用所有上一步實(shí)例化后的對(duì)象的onStartup方法

0

0

1. 首先來到AbstractDispatcherServletInitializer#onStartup再執(zhí)行super.onStartup(servletContext);

@Override
public void onStartup(ServletContext servletContext) throws ServletException {//實(shí)例化我們的spring root上下文super.onStartup(servletContext);//注冊(cè)我們的DispatcherServlet   創(chuàng)建我們spring web 上下文對(duì)象registerDispatcherServlet(servletContext);

?創(chuàng)建父容器——ContextLoaderListener

2.父類AbstractContextLoaderInitializer#onStartup執(zhí)行registerContextLoaderListener(servletContext);

  1. createRootApplicationContext()該方法中會(huì)創(chuàng)建父容器
    1. 該方法是抽象方法,實(shí)現(xiàn)類是AbstractAnnotationConfigDispatcherServletInitializer
      1. 調(diào)用getRootConfigClasses();方法獲取父容器配置類(此抽象方法在我們自定義的子類中實(shí)現(xiàn)提供我們自定義的映射路徑 )
      2. 創(chuàng)建父容器,注冊(cè)配置類

0

  1. 會(huì)創(chuàng)建ContextLoaderListener并通過ServletContext注冊(cè)

0

看完大家是不是感覺跟我們XML的配置ContextLoaderListener對(duì)上了:

0

創(chuàng)建子容器——DispatcherServlet

3.回到AbstractDispatcherServletInitializer#onStartup再執(zhí)行registerDispatcherServlet(servletContext);

0

registerDispatcherServlet方法說明:

  1. 調(diào)用createServletApplicationContext創(chuàng)建子容器
    1. 該方法是抽象方法,實(shí)現(xiàn)類是AbstractAnnotationConfigDispatcherServletInitializer
      1. 創(chuàng)建子容器(下圖很明顯不多介紹)
      2. 調(diào)用抽象方法:getServletConfigClasses();獲得配置類(此抽象方法在我們自定義的子類中實(shí)現(xiàn)提供我們自定義的配置類 )
      3. 配置類除了可以通過ApplicationContext()構(gòu)造函數(shù)的方式傳入 , 也可以通過這種方式動(dòng)態(tài)添加,不知道了吧~

0

  1. 調(diào)用createDispatcherServlet(servletAppContext);創(chuàng)建DispatcherServlet
  2. 設(shè)置啟動(dòng)時(shí)加載:registration.setLoadOnStartup(1);
  3. 調(diào)用抽象方法設(shè)置映射路徑:getServletMappings()(此抽象方法在我們自定義的子類中實(shí)現(xiàn)提供我們自定義的映射路徑 )

看完大家是不是感覺跟我們XML的配置DispatcherServlet對(duì)上了

0

4.?初始化ContextLoaderListener

0

ContextLoaderListener加載過程比較簡(jiǎn)單:

外置tomcat會(huì)幫我們調(diào)用ContextLoaderListener#contextInitialized 進(jìn)行初始化

  1. xml的方式下會(huì)判斷容器為空時(shí)創(chuàng)建父容器
  2. 在里面會(huì)調(diào)用父容器的refresh方法加載
  3. 將父容器存入到Servlet域中供子容器使用

0

5. 初始化DispatcherServlet

0

可以看到流程比ContextLoaderListener流程更多

外置tomcat會(huì)幫我們調(diào)用DispatcherServlet#init()? ?進(jìn)行初始化--->重點(diǎn)關(guān)注:initWebApplicationContext方法

  1. getWebApplicationContext(getServletContext())獲得父容器(從之前的Servlet域中拿到)
  2. cwac.setParent(rootContext);給子容器設(shè)置父容器
  3. 調(diào)用configureAndRefreshWebApplicationContext(cwac);

0

    1. 注冊(cè)一個(gè)監(jiān)聽器(該監(jiān)聽會(huì)初始化springmvc所需信息)
      1. ContextRefreshedEvent可以看到該監(jiān)聽器監(jiān)聽的是容器refreshed事件, 會(huì)在finishRefresh中發(fā)布
    2. 刷新容器

0

當(dāng)執(zhí)行refresh 即加載ioc容器 完了會(huì)調(diào)用finishRefresh():

  1. publishEvent(new ContextRefreshedEvent(this));發(fā)布ContextRefreshedEvent事件
  2. 觸發(fā)上面的ContextRefreshListener監(jiān)聽器:

---->FrameworkServlet.this.onApplicationEvent(event);

-------->onRefresh(event.getApplicationContext());

-------------->initStrategies(context);

protected void initStrategies(ApplicationContext context) {//初始化我們web上下文對(duì)象的 用于文件上傳下載的解析器對(duì)象initMultipartResolver(context);//初始化我們web上下文對(duì)象用于處理國(guó)際化資源的initLocaleResolver(context);//主題解析器對(duì)象初始化initThemeResolver(context);//初始化我們的HandlerMappinginitHandlerMappings(context);//實(shí)例化我們的HandlerAdaptersinitHandlerAdapters(context);//實(shí)例化我們處理器異常解析器對(duì)象initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);//給DispatcherSerlvet的ViewResolvers處理器initViewResolvers(context);initFlashMapManager(context);

這里面的每一個(gè)方法不用太細(xì)看, 就是給SpringMVC準(zhǔn)備初始化的數(shù)據(jù), 為后續(xù)SpringMVC處理請(qǐng)求做準(zhǔn)備

基本都是從容器中拿到已經(jīng)配置的Bean(RequestMappingHandlerMapping、RequestMappingHandlerAdapter、HandlerExceptionResolver )放到dispatcherServlet中做準(zhǔn)備:

0

0

0

...

但是這些Bean又是從哪來的呢?? 來來來, 回到我們的WebAppConfig

我們使用的一個(gè)@EnableWebMvc

  1. 導(dǎo)入了DelegatingWebMvcConfiguration@Import(DelegatingWebMvcConfiguration.class)
  2. DelegatingWebMvcConfiguration的父類就配置了這些Bean
  3. 而且我告訴你SpringBoot也是用的這種方式,

0

總結(jié)

  1. Tomcat在啟動(dòng)時(shí)會(huì)通過SPI注冊(cè) ContextLoaderListener和DispatcherServlet對(duì)象
    1. 同時(shí)創(chuàng)建父子容器
      1. 分別創(chuàng)建在ContextLoaderListener初始化時(shí)創(chuàng)建父容器設(shè)置配置類
      2. 在DispatcherServlet初始化時(shí)創(chuàng)建子容器 即2個(gè)ApplicationContext實(shí)例設(shè)置配置類
  2. Tomcat在啟動(dòng)時(shí)執(zhí)行ContextLoaderListener和DispatcherServlet對(duì)象的初始化方法, 執(zhí)行容器refresh進(jìn)行加載
  3. 在子容器加載時(shí) 創(chuàng)建SpringMVC所需的Bean和預(yù)準(zhǔn)備的數(shù)據(jù):(通過配置類+@EnableWebMvc配置(DelegatingWebMvcConfiguration)——可實(shí)現(xiàn)WebMvcConfigurer進(jìn)行定制擴(kuò)展)
    1. RequestMappingHandlerMapping,它會(huì)處理@RequestMapping 注解
    2. RequestMappingHandlerAdapter,則是處理請(qǐng)求的適配器,確定調(diào)用哪個(gè)類的哪個(gè)方法,并且構(gòu)造方法參數(shù),返回值。
    3. HandlerExceptionResolver 錯(cuò)誤視圖解析器
    4. addDefaultHttpMessageConverters 添加默認(rèn)的消息轉(zhuǎn)換器(解析json、解析xml)
    5. 等....
  4. 子容器需要注入父容器的Bean時(shí)(比如Controller中需要@Autowired Service的Bean); 會(huì)先從子容器中找,沒找到會(huì)去父容器中找: 詳情見AbstractBeanFactory#doGetBean方法

?

/** * 一般情況下,只有Spring 和SpringMvc整合的時(shí)才會(huì)有父子容器的概念, * 作用:* 比如我們的Controller中注入Service的時(shí)候,發(fā)現(xiàn)我們依賴的是一個(gè)引用對(duì)象,那么他就會(huì)調(diào)用getBean去把service找出來* 但是當(dāng)前所在的容器是web子容器,那么就會(huì)在這里的 先去父容器找*/
BeanFactory parentBeanFactory = getParentBeanFactory();
//若存在父工廠,且當(dāng)前的bean工廠不存在當(dāng)前的bean定義,那么bean定義是存在于父beanFacotry中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {//獲取bean的原始名稱String nameToLookup = originalBeanName(name);//若為 AbstractBeanFactory 類型,委托父類處理if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {//  委托給構(gòu)造函數(shù) getBean() 處理return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// 沒有 args,委托給標(biāo)準(zhǔn)的 getBean() 處理return parentBeanFactory.getBean(nameToLookup, requiredType);}

http://www.risenshineclean.com/news/64305.html

相關(guān)文章:

  • 網(wǎng)站設(shè)計(jì)合同模板網(wǎng)站優(yōu)化技巧
  • 廣州好的做網(wǎng)站公司互聯(lián)網(wǎng)營(yíng)銷培訓(xùn)
  • wordpress插件看訪問者數(shù)量關(guān)鍵詞優(yōu)化策略
  • 買網(wǎng)站需要注意什么游戲推廣員怎么做
  • 邢臺(tái)網(wǎng)站建設(shè)與制作官網(wǎng)排名優(yōu)化方案
  • 做網(wǎng)站前期框架圖站長(zhǎng)工具查詢官網(wǎng)
  • 保亭整站優(yōu)化網(wǎng)絡(luò)營(yíng)銷公司排名
  • 做可動(dòng)模型的網(wǎng)站網(wǎng)站關(guān)鍵詞挖掘
  • 鄭州網(wǎng)站建設(shè)網(wǎng)絡(luò)推廣seo優(yōu)化與推廣招聘
  • cnzz 網(wǎng)站域名怎么填營(yíng)銷策略的概念
  • 我做網(wǎng)站了網(wǎng)絡(luò)推廣方法有幾種
  • 免費(fèi)空間測(cè)試網(wǎng)站信陽網(wǎng)絡(luò)推廣公司
  • 數(shù)字營(yíng)銷 h5 網(wǎng)站開發(fā)正規(guī)推廣賺傭金的平臺(tái)
  • 徐匯網(wǎng)站建設(shè)推廣免費(fèi)網(wǎng)絡(luò)營(yíng)銷方式
  • 外貿(mào)公司網(wǎng)站如何做推廣百度頁面推廣
  • 樂清門戶網(wǎng)今日最新信息seo培訓(xùn)公司
  • 常州網(wǎng)站制作市場(chǎng)百度競(jìng)價(jià)
  • 綦江網(wǎng)站建設(shè)公司su搜索引擎優(yōu)化
  • 做合法的海外購網(wǎng)站需要什么手續(xù)網(wǎng)站維護(hù)公司
  • 如何做網(wǎng)站內(nèi)鏈網(wǎng)頁模板建站系統(tǒng)
  • 尋找鄭州網(wǎng)站優(yōu)化公司網(wǎng)絡(luò)推廣網(wǎng)站程序
  • 做的網(wǎng)站怎么讓百度收索時(shí)搜優(yōu)化設(shè)計(jì)方法
  • 歐美做同志網(wǎng)站有哪些百度地圖疫情實(shí)時(shí)動(dòng)態(tài)
  • 合肥做網(wǎng)站優(yōu)化公司蘇州seo門戶網(wǎng)
  • 國(guó)內(nèi)好看的網(wǎng)站設(shè)計(jì)湖南網(wǎng)站托管
  • 做網(wǎng)站之前要安裝什么百度知道灰色詞代發(fā)收錄
  • 網(wǎng)站 電信已備案 聯(lián)通seo怎么做新手入門
  • b2c網(wǎng)站的特點(diǎn)北京百度推廣開戶
  • 建網(wǎng)站的目的做網(wǎng)站的軟件有哪些
  • 網(wǎng)站建設(shè)夢(mèng)幻創(chuàng)意百度指數(shù)搜索熱度大學(xué)