Spring專業網站
http://www.springframework.com/
Spring 社區
http://www.thespringexperience.com
SourceForge Spring項目網址
http://sourceforge.net/projects/springframework/
Spring論壇
http://forum.springframework.org/
Spring郵件列表
http://sourceforge.net/mail/?group_id=73357
Spring Confluence
http://opensource.atlassian.com/confluence/spring
Introducing to Spring Framework
http://www.theserverside.com/articles/article.tss?l=SpringFramework
CKNY's Very Quick Wiki
http://ckny.eatj.com/wiki/jsp/Wiki?Spring
Spring中文資源
Spring中文論壇
http://spring.jactiongroup.net
Introducing to Spring Framework(中文版)
http://spring.jactiongroup.net/viewtopic.php?t=453
Spring開發指南
http://www.xiaxin.net/Spring_Dev_Guide.rar
Spring相關個人
Rod Johnson,Spring之父
個人介紹:http://www.springframework.com/people/rod.html
blog:http://blog.springframework.com/rod/
Juergen Hoeller,Spring協同創始人
個人介紹:http://www.springframework.com/people/juergen.html
blog:http://blog.springframework.com/juergen/
Bruce Tate,知名Java/Spring圖書作者
個人介紹:http://www.springframework.com/people/bruce.html
blog:http://today.java.net/pub/au/186
Colin Sampaleanu,Spring核心成員
個人介紹:http://www.springframework.com/people/colin.html
blog:http://blog.exis.com/colin/
Keith Donald,Spring核心成員,Spring Rich Client Project的創建者
個人介紹:http://www.springframework.com/people/keith.html
blog:http://jroller.com/page/kdonald
Alef Arendsen
個人介紹:http://www.springframework.com/people/alef.html
Spring Live,《Spring Live》作者的Blog
http://jroller.com/page/raible
Craig's stack trace,《Spring in action》作者的blog
http://jroller.com/page/habuma
Spring子項目
Spring Rich Client Project
http://sourceforge.net/projects/spring-rich-c
Spring IDE for Eclipse
http://www.springframework.org/spring-ide/eclipse/
Spring相關項目
Spring For .NET
http://www.springframework.net/
Acegi Security System
http://acegisecurity.sourceforge.net/
JSF-Spring
http://jsf-spring.sourceforge.net/
Spring-Validator
http://sourceforge.net/projects/js-validation/
?2. form-beans元素
該元素主要用來配置表單驗證的類。它包含如下屬性:
1. classname:一般用得少,指定和form-bean無素對應的配置類,默認為org.apache.struts.config.FormBeanConfig,如果自定義,則必須擴展FormBeanConfig類。可有可無。
2. name:ActionForm Bean的惟一標識。必須。
3. type:ActionForm的完整類名。必須。
如下所示:
<form-beans>
<form-bean
name="Loign"
type="com.ha.login">
</form-bean>
</form-beans>
如果是動態Action FormBean,還必須配置form-bean元素的form-property子元素。它包含四個屬性,上面三個,還有一個initial 元素:以字符串的形式設置表單字段的初始值,如果沒有設置該屬性,則是基本類型為0,如果是對象則為null。可有可無。如下所示:
<form-beans>
<form-bean
name="Loign"
type="com.ha.login">
<form-property name="ok"? type="java.lang.String"/>
<form-property name="oks"? type="java.lang.String"/>
<form-property name="okss"? type="java.lang.Integer" initial="20"/>
</form-bean>
</form-beans>
?3. global-exceptions元素
該元素主要配置異常處理,它的exception子元素代表全局的異常配置。struts采取配置的方式來處理異常。它用來設置java異常和異常處理類org.apache.struts.action.ExceptionHandler之間的映射。它有七個屬性,如下所示:
1. className:指定和exception元素對應的配置類,默認為:org.apache.struts.config.ExceptionConfig。可有可無。
2. Handler:指定異常得理類,默認為:org.apache.struts.action.ExceptionHandler。可有可無
3. key:指定在Resource Bundle中描述該異常的消息key
4. path:指定當異常發生時的轉發路徑。
5. scope:指定ActionMessages實例的存放范圍,可選值包括:request和session,默認為request。可有可無。
6. type:指定所需處理異常類的名字,必須。
7. bundle:指定Resource Bundle
如下所示:
<global-exceptions>
<exception
key="global.error.invalidlogin"
path="/error.jsp"
scope="request"
type="com.hn.tree"
/>
</global-exceptions>
?4. global-forwards元素
該元素主要用來聲明全局的轉發關系,它具有以下四個屬性:
1. className:和forward元素對應的配置類,默認為:org.apache.struts.action.ActionForward。可有可無。
2. contextRelative:此項為true時,表時path屬性以"/"開頭,相對于當前上下文的URL,默認為false.可有可無。
3. name:轉發路徑的邏輯名.必填。
4. path:轉發或重定向的URL,當contextRelative=false時,URL路徑相對于當前應用(application),當為ture時,表示URL路徑相對于當前上下文(context)。
5.? redirect:當此項為ture時,表示執行重定向操作。當此項為false時表示轉向操作。默認為false。
如下所示:
<global-forwards>
<forward? name="forms1" ?path="/a.do"/>
<forward? name="forms2" ?path="/nb.jsp"/>
<global-forwards>
?5. action-mappings元素
描述從特定的請求路徑到相應的Action類的映射。它具有以下幾個屬性:
1. attribute:設置和Action關聯的ActionForm Bean在request和session范圍內的key。如:Form Bean存在于request范圍內,此項設為“myBenas”,則在request.getAttribute("myBenas")就可以返回該Bean的實例。
2. classsName:和action元素對應的配置元素,默認為:org.apache.struts.action.ActionMapping.
3. forward:轉發的URL路徑。
4. include:指定包含的URL路徑。
5. input:輸入表單的URL路徑,當表單驗證失敗時,將把請求轉發到該URL。
6. name:指定和Action關聯的Action FormBean的名字,該名字必須在Form-Bean定義過。
7. path:指定訪問Action的路徑,以“/”開頭,無擴展名。
8. parameter:指定Actgion的配置參數,在Action類的execute()方法中,可以調用ActionMapping對象的getParameter()方法來讀取該配置參數。
9. roles:指定允許調用該Action的安全角色,多個角色之間用,隔開,在處理請求時,RequestProcessor會根據該配置項來決定用戶是否有權限調用Action權限。
10. scope:指定ActionForm Bean的存在范圍,可選取為request和session,默認為session。
11. type:指定Action類的完整類名。
12. unknown:如果此項為true,表示可以處理用戶發出的所有無效的Action URL,默認為false;
13. validate:指定是否要調用Action FormBean的validate方法,默認值為ture.
注:forward、include、type屬性只能選中其中一項。
如下:
<action path="/search"
type="zxj.okBean"
name="a1"
scope="request"
validate="true"
input="/b.jsp">
<forward name="tig" path="/aa.jsp"/>
</action>
注:此中的forward是指局部的轉發路徑。global-forwards表示全局的轉發路徑。
?6. controller元素
該元素用于配置ActionServlet。它具有以下屬性。
1. bufferSize:指定上載文件的輸入緩沖大小,可選,默認為4096
2. className:指定和controller元素對應的配置類,默認為org.apache.struts.config.ControllerConfig
3. conentType:字符編碼,如果在Action和JSP網頁中設置了,則覆蓋該設置。
4. locale:指定是否把Locale對象保存到當前用戶的session中,默認值為false.
5. processorClass:指定負責請求的java類完整路徑。
6. tempDir:指定處理文件的臨時工作目錄,如果此項沒有設置,將采用Servlet容器為web應用分配的臨時工作目錄。
7. nochache:如果為true:在響應結果中將加入特定的頭參數:Pragma,Cache-Control和Expise,防止頁面被保存在客戶端的瀏覽器中,默認為false
如下:
<controller
contentType="text/html;charset="UTF-8""
locale="true"
processorClass="con.ok"/>
?7. message-resources元素
主要配置本地化消息文本,它具有以下屬性。
1. className:和message-resources元素對應的配置類,默認為org.apache.struts.config.MessageResourcesConfig。
2. factory:指定消息資源的工廠類,默認為:org.apache.struts.util.PropertyMessageResourcesFactory類
3. key:指定Resource Bundle存放的ServletContext對象中時采用的屬性Key,默認由Globals.MESSAGES_KEY定義的字符串常量,只允許一個Resource Bundle采用默認的屬性Key。
4. null:指定MessageSources類如何處理未知消息的key,如果為true,則返回空字符串,如果為false,則返回相關字串,默認為false
5. prameter:指定MessageSources的資源文件名,如果為:a.b.ApplicationResources,則實際對應的文件路徑為:WEB-INF/classes/a/b/ApplicationResources.properties.
如:
<message-resources null="false" parameter="defaultResource"/>
<message-resources key="num1" null="false" parameter="test"/>
訪問為:
<bean:message? key="zxj"/>
<bean:message? key="zxj"? bundle="num1"/>
其中,zxj表法,messagesource資源文件中的一個字符串。
?8. plugin-in元素
配置Struts的插件,屬性如下:
1.?className:指定的Struts插件類,必須實現org.apache.struts.action.PlugiIn接口。如:
<plug-in
className="a.b.c.">
<set-property property="xxx" value="/WEB-INF/aa.xml"??/>
</plug-in>
?后記,多模塊的配置,可以供多個應用應用不同的struts-config.xml
一個典型的攔截器框架至少應該包括三個部分:
1、可聲明的攔截點;
2、靈活的攔截器序列;
3、對攔截對象的代理封裝;
攔截點可以基于具體的應用環境去靈活申明,這點可以參考Cocoon里的Pipeline。這里不用多說,大家看了后續的攔截點的定義代碼就一目了然了。關于攔截器的具體定義,也在隨后的部分提供,這里首先探討被攔截對象的代理的實現機制。
所謂代理,就是對被攔截對象的一個包裝,通過該包裝類,可以非常自然的對被包裝對象添加我們自定義的行為,比如調用攔截器進行攔截操作。
我們來看AOP的代理接口的定義:
-----------------------------
Sunny目前提供了兩種代理的實現方式:
1、基于Java的動態代理,原理大家可以到java.sun.com站點上去研究一番;
2、基于Cglib的字節碼映射的方式,這點大家也可以關注Cglig來找到具體的答案。
需要說明的是,這兩種代理各自有不同的應用域,某些情況是不能通用的。基于Java的動態代理要求被代理對象必須基于接口編程,即每個被代理對象有一個明確的接口。而基于Cglib的代理則不在此限制。
下面貼出源代碼:
----------------------------------------
packageorg.sunny.core.aop; importjava.lang.reflect.Method; importnet.sf.cglib.proxy.MethodInterceptor; importnet.sf.cglib.proxy.Enhancer; importnet.sf.cglib.proxy.MethodProxy; importorg.sunny.exception.SunnyException; importorg.sunny.cfg.PltMessage; importorg.sunny.core.aop.interceptor.InterceptorUtil; importjava.util.List; /** *采用Cglib代理的方式實現攔截器機制。需要注意的是: *由于目前EJB的實現方式是采用靜態-動態Stub的實現。Cgblib在這種對象的代理生成上有一 *些問題,(EJB的Object的Stub是一個Finnal的類,不能完成代理),因此,如果系統采用EJB作為 *業務邏輯,則攔截器引擎只能使用: *< code> *org.sunny.blaccess.impl.DynanicProxyReactor *< /code> *Copyright:Copyright(c)2005 *< p>Company:Sunny虛擬開發組< /p> *@author高雁冰({@linkmailto:haiger@163.com}) *@version1.5 */ publicclassCglibProxyimplementsMethodInterceptor,AopProxy { ????privateObjectdelegate;//被代理的業務對象 ????privateEnhancerenhancer=newEnhancer(); ????privateInterceptorUtilinterceptorUtil; ???? ????/** ????*設置該動態代理需要代理的對象 ????*@paramdelegate具體被代理的對象(實例) ????*/ ????publicvoidsetDelegate(Objectdelegate) ????{ ????????this.delegate=delegate; ????} ???? ????/** ????*設置該代理類需要處理的所有攔截器。 ????*@paraminterceptors攔截器集合 ????*/ ????publicvoidsetInterceptors(Listinterceptors) ????{ ????????interceptorUtil=newInterceptorUtil(interceptors); ????} ???? ????/** ????*獲取通過該動態代理處理后的業務代理對象 ????*@return該代理處理后的代理業務對象 ????*@throwsSunnyException ????*/ ????publicObjectgetProxy()throwsSunnyException ????{ ????????if(null==delegate) ????????{ ????????????thrownewSunnyException(PltMessage.getInstance().getMessage( ????????????"BLA_IMPL_DELEGATE_NOT_SET")); ????????} ????????if(-1!=delegate.getClass().getName().indexOf("$$")) ????????{ ????????????enhancer.setSuperclass(delegate.getClass().getSuperclass()); ????????????}else ????????????{ ????????????????enhancer.setSuperclass(delegate.getClass()); ????????????} ????????????enhancer.setCallback(this); ????????????returnenhancer.create(); ????????} ???????? ????????/** ????????*實現對業務邏輯方法的具體攔截操作。在該操作里,可以在業務邏輯方法調用前后或者拋出異常的 ????????*時候添加自己的控制,這里則選擇執行系統配置的攔截器。 ????????*@paramo被代理對象 ????????*@parammethod訪問的具體方法 ????????*@paramargs方法輸入參數 ????????*@paramproxy方法代理 ????????*@return方法執行結果 ????????*@throwsjava.lang.Throwable ????????*/ ????????publicObjectintercept(Objecto,Methodmethod,Object[]args,MethodProxyproxy) ????????throwsThrowable ????????{ ????????????//調用所有的攔截器,對方法行為進行攔截操作 ????????????interceptorUtil.before(delegate,method,args); ???????????? ????????????//具體業務邏輯方法的調用 ????????????Objectresult=null; ????????????try ????????????{ ????????????????result=proxy.invokeSuper(o,args); ????????????}catch(Throwablee) ????????????{ ????????????????//對日志進行攔截操作 ????????????????interceptorUtil.exception(delegate,method,args,e); ????????????} ???????????? ????????????//業務邏輯調用完成,對結果進行攔截操作 ????????????interceptorUtil.after(delegate,method,args,result); ???????????? ????????????returnresult; ????????} ???????? |
1 | <bean id="quartzSchedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" scope="singleton"> <!-- set quartz scheduler factory configuration location --> <!-- <property name="configLocation" value="" /> --> <!-- 系統會在啟動時加載 --> <property name="autoStartup" value="true" /> </bean> <bean id="taskManage" class="com.sumit.task.TaskManage" scope="singleton"> <property name="taskDAO" ref="taskDao" /> <property name="scheduler" ref="quartzSchedulerFactory" /> </bean> |
1 | JobDetail job = new JobDetail(taskName, Scheduler.DEFAULT_GROUP,DefaultQuartzJob.class); JobDataMap jobDataMap = job.getJobDataMap(); //根據PUT不同的TASK而運行不同的任務 jobDataMap.put("Task", task); job.setDurability(true); scheduler.addJob(job, true); |
1 | publicclass DefaultQuartzJob implements Job { ? privatestatic Logger logger = Logger.getLogger(DefaultQuartzJob.class); ? publicvoid execute(JobExecutionContext ctx) throws JobExecutionException { JobDataMap jobDataMap = ctx.getJobDetail().getJobDataMap(); TaskTO task = (TaskTO) jobDataMap.get("Task"); ? Task entryTask = task.getEntryTask(); ? if (entryTask == null) { logger .error("Task " + task.getName() + " couldn't be initialized!"); return; } ? TaskContext taskContext = new DefaultTaskContext(); ? // 將觸發任務的Trigger中所有的參數添加到上下文中 JobDataMap triggerDataMap = ctx.getTrigger().getJobDataMap(); String[] keys = triggerDataMap.getKeys(); if (keys != null) {for (int i = 0; i < keys.length; i++) { Object obj = triggerDataMap.get(keys[i]); if (obj instanceof String[]) { String [] data=(String[]) obj; if(data.length>0){ taskContext.setParameter(keys[i], data[0]); }}elseif(obj instanceof String){ taskContext.setParameter(keys[i], (String)obj); }}}try{// 為任務時間執行次數加1 TaskManage tm = (TaskManage) triggerDataMap .get(TaskManage.TASKMANAGE_ATTRIBUTE_NAME); tm.addTriggerExecuteTimes(triggerDataMap .getString(TaskManage.TRIGGER_ATTRIBUTE_NAME)); }catch (TaskException e) { logger.error( "catch exception while process task " + task.getName(), e); }try{//根據實例化不同的TASK而運行不同的任務 entryTask.process(taskContext); }catch (TaskException e) { logger.error( "catch exception while process task " + task.getName(), e); }}} |
1 | /** * 定時任務的基本接口 */publicinterface Task { ? /** * 任務執行 * * @param request * 請求參數 * @param response * 返回參數 * @param cxt * @roseuid 4535938002AC */publicvoid process(TaskContext cxt) throws TaskException; ? /** * 任務名稱 * * @return java.lang.String * @roseuid 453DB0AB01B5 */public String getName(); } |
1 | scheduler.deleteJob(taskName, Scheduler.DEFAULT_GROUP); |
1 | if (TRIGGER_CRON.equals(triggerType)) {//創建CRONTRIGGER trigger = new CronTrigger(triggerName, Scheduler.DEFAULT_GROUP, taskName, Scheduler.DEFAULT_GROUP, validStartTime, validEndTime, triggerPattern); trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING); }else{//創建SIMPLETRIGGER trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, taskName, Scheduler.DEFAULT_GROUP, validStartTime, validEndTime, repeatCount, repeatInterval); trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT); } ? try{//添加trigger到scheduler scheduler.scheduleJob(trigger); logger.debug("trigger " + trigger.getName() + " have been loaded to scheduler!"); }catch (SchedulerException e) { logger.error("Catch exception " + e.getMessage() + " while adding trigger " + triggerName + " into scheduler", e); thrownew TaskException("0096", "Catch exception " + e.getMessage() + " while adding trigger " + triggerName + " into scheduler", e); } ? |
1 | try{ scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); }catch (SchedulerException e) { logger.error("Catch exception " + e.getMessage() + " while remove trigger " + triggerName + " from scheduler", e); thrownew TaskException("0096", "Catch exception " + e.getMessage() + " while removing trigger " + triggerName + " from scheduler", e); |
1 | <context-param> <param-name>webAppRootKey</param-name> <param-value>task.root</param-value> </context-param> <!-- 定義SPRING配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/taskContext*.xml</param-value> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> </context-param> <!-- 定義LOG4J監聽器 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> ? <!-- 定義SPRING監聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> |
1 | publicclass ContextLoaderListener implements ServletContextListener { ? private ContextLoader contextLoader; ? /** * Initialize the root web application context. *///當WEB上下文初始化時,系統會調用此方法publicvoid contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); ? //監聽到WEB上下文初始化的時候執行SPRING上下文contextLoader的初始化工作 this.contextLoader.initWebApplicationContext(event.getServletContext()); } ? /** * Create the ContextLoader to use. Can be overridden in subclasses. * @return the new ContextLoader */protected ContextLoader createContextLoader() {returnnew ContextLoader(); } ? /** * Return the ContextLoader used by this listener. */public ContextLoader getContextLoader() {return contextLoader; } ? /** * Close the root web application context. */publicvoid contextDestroyed(ServletContextEvent event) {if (this.contextLoader != null) { this.contextLoader.closeWebApplicationContext(event.getServletContext()); }} ? } |
1 | public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { ? if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {thrownew IllegalStateException( "Cannot initialize context because there is already a root application context ? present - " +"check whether you have multiple ContextLoader* definitions in your web.xml!"); } ? long startTime = System.currentTimeMillis(); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } servletContext.log("Loading Spring root WebApplicationContext"); ? try{// Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); ? // Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown. ? //創建web上下文 this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ? if (logger.isInfoEnabled()) { logger.info("Using context class [" + this.context.getClass().getName() + "] for root WebApplicationContext"); }if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext [" + this.context + "] as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); }if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ? ms");} ? return this.context; }catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; }catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; }} |
1 | protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {//獲得需要實例化的CONTEXT類名,在web.xml中有設置,如果沒有設置,那么為空 String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) {try{return ClassUtils.forName(contextClassName); }catch (ClassNotFoundException ex) {thrownew ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); }}//如果在spring web.xml中沒有設置context類位置,那么取得默認contextelse{//取得defaultStrategies配置文件中的WebApplicationContext屬性 contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try{return ClassUtils.forName(contextClassName); }catch (ClassNotFoundException ex) {thrownew ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); }}} |
1 | privatestaticfinal Properties defaultStrategies; ? static{// Load default strategy implementations from properties file.// This is currently strictly internal and not meant to be customized// by application developers.try{//設置classpath為contextLoader同級目錄 ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); //加載該目錄下的所有properties文件 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); }catch (IOException ex) {thrownew IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); }} |
1 | # Default WebApplicationContext implementation classfor ContextLoader. # Used as fallback when no explicit context implementation has been specified as context-param. # Not meant to be customized by application developers. ? #默認的WebApplicationContext為org.springframework.web.context.support.XmlWebApplicationContext org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext |
1 | publicclass XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { ? /** Default config location for the root context */ ? //配置了默認的spring配置文件publicstaticfinal String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; ? //配置文件默認BUILD路徑publicstaticfinal String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; ? //配置文件默認后綴名publicstaticfinal String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; ? /** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions *///獲得bean配置protectedvoid loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {//從BEAN工廠獲得一個XmlBeanDefinitionReader 來讀取SPRING配置文件 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); ? //設置beanDefinitionReader服務于當前CONTEXT// resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); ? // Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); //讀取配置文件 loadBeanDefinitions(beanDefinitionReader); } ? /** * Initialize the bean definition reader used for loading the bean * definitions of this context. Default implementation is empty. * <p>Can be overridden in subclasses, e.g. for turning off XML validation * or using a different XmlBeanDefinitionParser implementation. * @param beanDefinitionReader the bean definition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass */protectedvoid initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {} ? /** * Load the bean definitions with the given XmlBeanDefinitionReader. * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method; * therefore this method is just supposed to load and/or register bean definitions. * <p>Delegates to a ResourcePatternResolver for resolving location patterns * into Resource instances. * @throws org.springframework.beans.BeansException in case of bean registration errors * @throws java.io.IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver *///讀取配置文件protectedvoid loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) {for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); }}} ? /** * The default location for the root context is "/WEB-INF/applicationContext.xml", * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" * (like for a DispatcherServlet instance with the servlet-name "test"). *///獲得默認的ConfigLocationsprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {returnnew String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + ? DEFAULT_CONFIG_LOCATION_SUFFIX}; }else{returnnew String[] {DEFAULT_CONFIG_LOCATION}; }} |
1 | publicint loadBeanDefinitions(String location) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) {thrownew BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } ? if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try{//根據配置文件讀取相應配置 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); }return loadCount; }catch (IOException ex) {thrownew BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); }}else{// Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); }return loadCount; }} |
1 | public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern); }else{// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); }}else{// Only look for a pattern after a prefix here// (to not get fooled by a pattern symbol in a strange prefix).int prefixEnd = locationPattern.indexOf(":") + 1; if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern); }else{// a single resource with the given namereturnnew Resource[] {getResourceLoader().getResource(locationPattern)}; }}} |
1 | protected Resource[] findPathMatchingResources(String locationPattern) throws IOException { String rootDirPath = determineRootDir(locationPattern); String subPattern = locationPattern.substring(rootDirPath.length()); Resource[] rootDirResources = getResources(rootDirPath); //collectionFactory初始化一個set容量為16 Set result = CollectionFactory.createLinkedSetIfPossible(16); for (int i = 0; i < rootDirResources.length; i++) { Resource rootDirResource = rootDirResources[i]; if (isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); }else{ result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); }}if (logger.isDebugEnabled()) { logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result); }return (Resource[]) result.toArray(new Resource[result.size()]); } |
1 | publicvoid refresh() throws BeansException {if (ObjectUtils.isEmpty(getConfigLocations())) {//設置configLocations為默認的getDefaultConfigLocations() setConfigLocations(getDefaultConfigLocations()); } super.refresh(); } |
1 | publicvoid refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) { this.startupTime = System.currentTimeMillis(); ? synchronized (this.activeMonitor) { this.active = true; } ? // Tell subclass to refresh the internal bean factory. refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); ? // Tell the internal bean factory to use the context's class loader. beanFactory.setBeanClassLoader(getClassLoader()); ? // Populate the bean factory with context-specific resource editors. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); ? // Configure the bean factory with context semantics. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); ? // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); ? // Invoke factory processors registered with the context instance.for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) { BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next(); factoryProcessor.postProcessBeanFactory(beanFactory); } ? if (logger.isInfoEnabled()) {if (getBeanDefinitionCount() == 0) { logger.info("No beans defined in application context [" + getDisplayName() + "]"); }else{ logger.info(getBeanDefinitionCount() + " beans defined in application context [" + ? getDisplayName() + "]"); }} ? try{// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(); ? // Register bean processors that intercept bean creation. registerBeanPostProcessors(); ? // Initialize message source for this context. initMessageSource(); ? // Initialize event multicaster for this context. initApplicationEventMulticaster(); ? // Initialize other special beans in specific context subclasses. onRefresh(); ? // Check for listener beans and register them. registerListeners(); ? // Instantiate singletons this late to allow them to access the message source. beanFactory.preInstantiateSingletons(); ? // Last step: publish corresponding event. publishEvent(new ContextRefreshedEvent(this)); } ? catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources. beanFactory.destroySingletons(); throw ex; }}} |