Ⅰ web.xml配置spring容器出Error listenerStart錯怎麼解決
看看驅動對不對,還有資料庫連接
Ⅱ EasyExcel的監聽器不能被spring管理
在使用EasyExcel中的讀取excel時,需要使用到監聽器,但是在Listener監聽器中無法使用Spring容器的@Resource或者@Autowired 註解的方法注入bean,因為,在web Server容器中,無論是Servlet,Filter,還是Listener都不是Spring容器管理的,因此我們都無法在這些類中直接使用Spring註解的方式來注入我們需要的對象。在這里,Servlet的整個生命周期都是由Servlet容器來處理的。如果把它硬放到Spring容器中去創建,Servlet對象是可被Spring容器建出來,但Servlet容器可能跟本就不知道這個Servlet是否存在,因為不在它自己的容器中。所以,servlet交給web server來管理,不要交給spring管理。
Ⅲ 從源碼理解總結web容器、spring容器、spring mvc容器三者關系
本篇,我打算從springMVC項目的web.xml的配置文件入手,通過部分源碼逐步去理解解釋三個容器的關系以及調用順序,因為是基於我個人的理解,可能有所不足。
一般web.xml文件里會有如下兩段配置信息:
我們先了解下web.xml,以下引用自 《web.xml文件是什麼?有什麼用?--詳解》 :
然後結合我們上面的web.xml中關於spring和spring mvc的配置信息來進入話題:
首先,啟動web容器的時,會先生成對應項目的ServelContent對象,這個是每個項目的上下文,這個ServelContent可以管理所有的servlet,並將我們web.xml中設置的<context-param>內容作為鍵值對交給這個對象。
然後載入<listener>標簽內容,這個時候就會產生org.springframework.web.context.ContextLoaderListener。
spring的這個 ContextLoaderListener 在接下來的過程中很重要,我們來看一下源碼
首先,可以看出它繼承了ContextLoader類,並實現了ServletContextListener介面。
這里再直接引用他人的結論 《Spring中ContextLoaderListener作用》
好了,人家說法中回到我們的起點了,我們基本都被人告知「ContextLoaderListener的作用是創建並初始化spring容器」
那我們就可以深入進去看看,到底哪裡做了這一步:
首先,我們知道了ServletContextListene是ServletContext的監聽者,監聽器的響應動作就是在伺服器啟動時contextInitialized會被調用,關閉的時候contextDestroyed被調用,這個好理解,那我們就來看一下ContextLoaderListener重寫的contextInitialized方法到底做了什麼。
我們再進入觀察initWebApplicationContext方法細看
我因為自己消化過一遍,直接給出關鍵位置的方法說明——
1、首先是278行:創建了WebApplicationContext,我們可以理解為spring容器的殼子有了
2、其次是288和289行:對ApplicationContext載入了配置文件,並設置servletContext為WebApplicationContext的parent,到這一步,可以理解為我們的spring容器也就差不多成型了
3、接下來是294行:把ApplicationContext對象以鍵值對的形式存到servletContext中,這一步很關鍵,就是因為servletContext中存在這個鍵值對,所以其他內部成員可以通過servletContext訪問到ApplicationContext,當然也能使用其管理的bean,而spring mvc則沒有這樣存在servletContext,所以我覺得正是這一步決定了子容器springmvc可以取用父容器內的bean,反著則不然。
接下來直到輪到我們的springmvc容器<servlet>標簽內容
會生成控制org.springframework.web.servlet.DispatcherServlet,這是一個前端控制器,主要的內容我之前也有一篇文章做過自我記錄
《Spring MVC的工作機制簡單理解》
我們可以看到設置的
<load-on-startup>1</load-on-startup>
這個標簽大概意思就是:
1、load-on-startup 元素標記容器是否應該在web應用程序啟動的時候就載入這個servlet,(實例化並調用其init()方法)。
2、它的值必須是一個整數,表示servlet被載入的先後順序。
3、如果該元素的值為負數或者沒有設置,則容器會當Servlet被請求時再載入。
4、如果值為正整數或者0時,表示容器在應用啟動時就載入並初始化這個servlet,值越小,servlet的優先順序越高,就越先被載入。值相同時,容器就會自己選擇順序來載入。
在DispatcherServlet的時候就根據springMVC容器容器的配置文件生成。
比如我這邊就是
那順序確定了,我們再看一下spring和spring mvc的父子關系哪裡確定:
我們可以從下面3個截圖看到dispatcherServlet的繼承關系,同時,init方法用的是dispatcherServlet父類的父類的方法。
重點在於initServletBean()方法,經過追蹤,我們找到該方法的最終實現又是在dispatcherServlet的父類FrameworkServlet中
其中涉及父子關系的實際是在219行的initWebApplicationContext()方法
initWebApplicationContext()方法主要用於創建或刷新WebApplicationContext實例,並對Servlet功能所使用的變數進行初始化。
從238行源碼就可以看到,它獲得ContextLoaderListener中初始化的rootContext,
在246行設置了父子關系的引用,也就是從這一點我們看到了spring和springMVC的父子關系!
並且,可以看到這只是一條單向的引用,spring中沒有引用直接指向springMVC,也就是子類能找到父類,然而父類都不知道這個子類,父子容器之間內部對象調用關系更明了。
再通過構造函數和Servlet的contextAttribute屬性查找ServletContext來進行webApplicationContext實例的初始化,最終。
這個方法內263行源碼onRefresh(wac)方法是FrameworkServlet提供的模板方法,在子類,也就是我們的DispatcherServlet的onRefresh()方法中進行了重寫。而在onRefresh()方法中調用了initStrategies()方法來完成初始化工作,初始化Spring MVC的9個組件。
1、Tomcat在啟動時給每個Web應用創建一個全局的上下文環境,這個上下文就是ServletContext,其為後面的Spring容器提供環境。
2、Tomcat在啟動過程中觸發容器初始化事件,Spring的ContextLoaderListener會監聽到這個事件,它的contextInitialized方法會被調用,在這個方法中,Spring會初始化全局的Spring根容器,這個就是Spring的IoC容器,IoC容器初始化完畢後,Spring將其存儲到ServletContext中,便於以後來獲取。
3、Tomcat在啟動過程中還會掃描Servlet,一個Web應用中的Servlet可以有多個,以SpringMVC中的DispatcherServlet為例,這個Servlet實際上是一個標準的前端控制器,用以轉發、匹配、處理每個Servlet請求。
4、Servlet會在容器啟動時載入或延遲載入(根據啟動級別設置數字)。延遲載入時,當第一個請求達到時,serlet容器發現對應Servlet還沒有被實例化,就調用Servlet的init方法。
在spring MVC里
DispatcherServlet在初始化的時候會建立自己的容器,叫做SpringMVC 容器,用來持有Spring MVC相關的Bean。同時,Spring MVC還會通過ServletContext拿到Spring根容器,並將Spring根容器設為SpringMVC容器的父容器,請注意,Spring MVC容器可以訪問父容器中的Bean,但是父容器不能訪問子容器的Bean, 也就是說Spring根容器不能訪問SpringMVC容器里的Bean。
說的通俗點就是,在Controller里可以訪問Service對象,但是在Service里不可以訪問Controller對象。
Ⅳ spring框架通過web容器來啟動的類
如下即為啟動spring的測試類,初始化spring上下文環境即可啟動spring,web項目只是把初始化spring上下文環境轉移到了web.xml里。
Action:
import org.apache.log4j.Logger;import org.springframework.context.support.;public class Action { private static Logger logger = Logger.getLogger(DisposeAction.class); private static String[] contexts = { "applicationContext.xml" }; public static void main(String[] args) { logger.info("[i] : preDispose Server start ... "); ctx = new (contexts); //SpringBeanManager.initContext(ctx); logger.info("[i] : preDispose Server start ok ... "); }}
Ⅳ spring是不是必須在web容器中才能跑
Web應用當然要在Web容器中應用啦,呵呵,但是測試什麼的,有框架可以模擬的,其他的都可以讀出applicationContext.xml的配置來應用的啊
Ⅵ web容器啟動初始化完 SpringIOC 實例化完bean 項目啟動完成,關於實例化問題
Class.forName("beanClassName"); 這個跟spring ioc木有關系了!因為這個是java語言反射的特性!就像男人就是陽性!如果你木有記錯的話應該知道Java默認一個空構造函數!就是根據這個來反射得到bean實例!
大量的框架都是使用了這個特性才支持了動態裝載一個class來完成了,對象最大化管理!但是反射消耗性能也是比較高的!
種方式是:光熱轉換(太陽能熱水器);光電轉換(太
Ⅶ Spring容器啟動流程
通過AbstractApplicationContext#refresh()提供了在載入完配置文件後的啟動過程。以SpringBoot的Web環境來看啟動過程(文末有spring容器的啟動過程及區別)
1.prepareRefresh():由於在此時還沒有載入servlet容器,所以servletContext=null,servletConfig=null,還沒有進行初始化propertySource,添加了幾個ApplicationListeners。
2.obtainFreshBeanFactory():創建BeanFactory,即DefaultListableBeanFactory
3.prepareBeanFactory():對DefaultListableBeanFactory進行屬性填充。如:添加類載入器,添加BeanPostProcessor等等。
4.postProcessBeanFactory():在上面prepareBeanFactory()公共的之後,提供子類的特殊處理,注冊特殊的後處理器,此處為的具體實現。
5.():主要是掃描包,注冊成BeanDefinition,對類配置的信息解析成BeanDefinition的屬性。然後執行實現了BeanFactoryPostProcessor介面的bean的postProcessBeanFactory()方法。
對於類型的BeanFactoryPostProcessor,執行
類型的processor,檢查包名是否異常
獲取類型為並且是PriorityOrdered優先排序類型的beanDefinition
上面獲取postProcessorNames的具體實現如下
調用剛獲取到的currentRegistryProcessor列表中的bean的()方法
獲取到啟動類
對啟動類開始進行解析,包裝成SourceClass,開始解析
獲取到需要掃描的包信息,開始進行解析
解析是否有includeFilters,excludeFilters,lazyInit等屬性,解析basePackage,basePackageClasses配置,如果沒有,則根據啟動類的包名獲取,最終獲得需要掃描的包。
解析包下所有beanDefinition,遍歷並逐個解析。 如果實現了AnnotatedBeanDefinition介面,解析是否有lazy,Primary,DependsOn,Role,Description等註解並對beanDefinition進行相應屬性設置。 檢查是否在beanDefinitionMap中,如果不存在則將beanDefinition注冊到beanDefinitionMap中。
對獲取到的包下的beanDefinition進行遍歷處理。處理是否import,ImportResource,Bean註解,處理實現的介面。
處理完類型的bean之後,處理之前注冊的處理器,前兩個處理器沒做任何處理,第三個處理器,對目前載入的所有的beanDefinition進行處理。如果是啟動類,生成代理類並替換原來的beanClass
獲取實現了BeanFactoryPostProcessor介面的類,去除了上面已經解析過的,根據是否排序進行分類,然後按照PriorityOrdered,Ordered,nonOrdered以此執行。
6.registerBeanPostProcessors():獲取實現了BeanPostProcessor的bean,並根據是否實現order介面進行排序,並按順序注冊到beanPostProcessors中。
7.initMessageSource():
8.():注冊事件廣播器
9.onRefresh():獲取ServletWebServerFactory(tomcatServletWebServerFactory),創建TomcatWebServer,然後initServletPropertySources
創建TomcatWebServer之後獲取需要初始化的servlet,filter
將servlet添加到servletContext中
將filter添加到servletContext中
10.registerListeners():在事件廣播器中注冊監聽器,注冊監聽器name,如果earlyApplicationEvents存在,則廣播事件。
11.():實例化bean
先進行實例化之前的操作,再實例化bean。
如果有實現, 則執行
根據實例化策略進行實例化(這里是cglib)包裝成BeanWrapper
實例化之後執行後處理
執行postProcessProperties
屬性設置,在中進行依賴注入
是否實現BeanNameAware,BeanClassLoaderAware,BeanFactoryAware等介面
init之前
調用自定義的init方法,在中處理
如果實現了InitializingBean,執行afterPropertiesSet()方法
然後執行init之後的方法
12.finishRefresh():主要做的事情是啟動tomcat,並發布事件
逐個listener去匹配事件
以下為spring環境啟動與web環境啟動的相同和不同:
1.prepareRefresh():區別在於initPropertySources()的實現不同,spring上下文為,web上下文AnnotationConfig
2.obtainFreshBeanFactory():相同
3.prepareBeanFactory():相同
4.postProcessBeanFactory():spring使用的AbstractApplicationContext的默認處理,沒有提供實現,web提供了實現注冊了特殊的處理器
5.():相同
6.registerBeanPostProcessors():相同
7.initMessageSource():相同
8.():相同
9.onRefresh():spring什麼都沒做,使用的AbstractApplicationContext的默認實現,web提供了創建web容器的過程
10.registerListeners():相同
11.():相同
12.finishRefresh():spring主要做的事情是發布事件,web容器多了一步啟動web容器
綜上:web環境和spring環境啟動容器流程基本相同,spring默認使用AbstractApplicationContext的實現,web多了properties解析,注冊特殊處理器,創建webServer和啟動webServer的過程。
Ⅷ 1.IDEA明明已經導入了jar包為什麼還是提示找不到類
首先找到出錯的位置,查看是否可以進到哪個類當中。
比如在web容器和Spring容器在整合的時候要使用org.springframework.web.context.ContextLoaderListener這個類來在Web容器啟動時啟動Spring容器,有時候會報錯這不到這個類,此時可以在web.xml中Ctrl+滑鼠左鍵,看看是否可以進入到這個類當中,如果不能說明沒有真的引入。
如果可以進入,說明類的路徑沒毛病,如果用的tomcat,刪掉後重新部署,最後重新編譯,編譯完成後進入tomcat部署項目的文件夾查看對應項目的classes文件夾中有沒有你項目編譯後產生的相關文件,都有的話,重新試一下。
方法一:在項目名稱上右鍵,選擇MAVEN,然後點擊reimport即可。
方法二:左上角點擊file,選擇Invalidate Caches/Restart,然後點擊左邊第一個按鍵即可。我的項目中此問題得以解決。
方法三:使用方法一後,再右上角點擊 toggle offline mode
方法四:將maven倉庫所在包當中的,提示缺的jar包刪除,然後在maven當中再次引用,或者換個版本,或者換個版本後在換回原來的版本。
一般通過以上幾個方法都可以解決。
Ⅸ web容器怎麼啟動spring
在應用程序web.xml中做了以下配置信息時,當啟動Web容器時就會自動載入Spring容器。
[java] view plainprint?
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>