spring知識點整理-第一篇

1、@Autowired與@Resource前端

 相同點:均可以用來裝配bean. 均可以寫在字段上,或寫在setter方法上。       java

不一樣點:1.@Autowired 默認按類型裝配(這個註解是屬業spring的),默認狀況下必需要求依賴對象必須存在,若是要容許null值,能夠設置它的required屬性爲false,如:@Autowired(required=false);若是咱們想使用名稱裝配能夠結合@Qualifier註解進行使用 。程序員

2.@Resource 默認安裝名稱進行裝配(這個註解屬於J2EE的),名稱能夠經過name屬性進行指定,若是沒有指定name屬性,當註解寫在字段上時,默認取字段名進行安裝名稱查找,若是註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。可是須要注意的是,若是name屬性一旦指定,就只會按照名稱進行裝配。推薦使用:@Resource註解在字段上,這樣就不用寫setter方法了,而且這個註解是屬於J2EE的,減小了與spring的耦合。注意:若是沒有指定name屬性,而且按照默認的名稱仍然找不到依賴對象時,@Resourve註解會回退到按類型裝配。但一旦指定了name屬性,就只能按照名稱裝配了。web

代碼:spring

@Resource(name="testService")  
private TestService testService;

2、spring bean的做用域分爲如下五種:sql

一、singleton(默認模式):單例,指一個bean容器中只存在一份。編程

二、prototype:每次請求(每次使用)建立新的實例,destroy方式不生效。設計模式

三、request:每次http請求建立一個實例且僅在當前request內有效。session

四、session:同上,每次http請求建立,當前session中有效。mvc

五、global session:基於portlet的web中有效(portlet定義了global sessio),若是在web中,同session。

代碼:

a.xml的配置

<!-- 設置bean的做用域scope屬性值爲prototype,默認爲singleton,能夠不設置scope屬性 -->
<bean name="beanScope" class="com.jsun.test.springDemo.BeanScope" scope="prototype"></bean>

b.annotation註解方式

//註冊bean
@Component("beanScope") 
//設置bean的做用域範圍爲singleton
@Scope("singleton")  
public class BeanScope {

}

3、spring bean的生命週期

一、xml文件中配置bean的init-method屬性和destroy-method屬性

<bean name="beanScope" class="com.jsun.test.springDemo.BeanScope" 
init-method="init_m" destroy-method="destroy_m"></bean>

同時須要注意的是:若是bean中配置init-method和init-destroy屬性,那麼在bean類中必須提供對應的初始化和銷燬方法,不然將拋出初始化異常:Exception encountered during context initialization 。若是配置全局的,在<beans></beans>上進行配置。

二、實現

org.springframework.beans.factory.DisposableBean/org.springframework.beans.factory.InitializingBean接口,覆蓋實現afterPropertiesSet()和destroy()方法.

public class BeanScope implements InitializingBean,DisposableBean {

    public BeanScope(){
        System.out.println("BeanScope 實例化");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("實現接口InitializingBean afterPropertiesSet()初始化");

    }

    @Override
    public void destroy() throws Exception {
        System.out.println("實現接口DisposableBean destroy()銷燬");

    }
}

注:若是配置了bean的init-method和init-destroy屬性(或同時配置全局的default-init-method和default-destroy-method屬性),並實現了上述的初始化和銷燬接口,接口的初始化和銷燬方法將先於配置的初始化和銷燬方法。

三、註解配置方式

在指定方法上加上@PostConstruct或@PreDestroy註解來指定該方法做爲初始化或銷燬方法來使用。

public class BeanScope{

    public BeanScope(){
        System.out.println("BeanScope bean 實例化");
    }

    //添加@PostConstruct註解,指定當前方法做爲初始化方法
    @PostConstruct
    public void init(){
        System.out.println("@PostConstruct註解 初始化");
    }

    //添加@PreDestroy註解,指定當前方法做爲銷燬方法
    @PreDestroy
    public void destroy(){
        System.out.println("@PreDestroy註解 銷燬");
    }
}

4、bean的做用域與生命週期之間的關係以及初始化時機

一、初始化bean實例是時機與bean做用域的關係

(1)、當scope=singleton,即默認狀況,會在容器初始化時實例化、初始化。但若是指定bean節點的lazy-init=」true」,來延遲bean的實例化、初始化,當第一次獲取bean時纔會初始化bean。

(2)、當scope=prototype時,也會延遲初始化bean,至關於設置lazy-init=」true」,即第一次請求該bean時才初始化(如調用getBean()方法時);而且當spring容器關閉時,destroy()銷燬方法也不會被調用。

緣由:對於prototype做用域的bean,有一點很是重要,那就是Spring不能對一個prototype bean的整個生命週期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype實例後,將它交給客戶端,隨後就對該prototype實例漠不關心了。無論何種做用域,容器都會調用全部對象的初始化生命週期回調方法。但對prototype而言,任何配置好的析構生命週期回調方法都將不會被調用。

5、InitializingBean的做用

InitializingBean接口爲bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在初始化bean的時候會執行該方法。

import org.springframework.beans.factory.InitializingBean;
public class TestInitializingBean implements InitializingBean{
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("ceshi InitializingBean");        
    }
    public void testInit(){
        System.out.println("ceshi init-method");        
    }
}

在spring初始化bean的時候,若是該bean是實現了InitializingBean接口,而且同時在配置文件中指定了init-method,系統則是先調用afterPropertiesSet方法,而後在調用init-method中指定的方法。

總結

1:spring爲bean提供了兩種初始化bean的方式,實現InitializingBean接口,實現afterPropertiesSet方法,或者在配置文件中同過init-method指定,兩種方式能夠同時使用。

2:實現InitializingBean接口是直接調用afterPropertiesSet方法,比經過反射調用init-method指定的方法效率相對來講要高點。可是init-method方式消除了對spring的依賴。

3:若是調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。

6、ApplicationContextAware、ApplicationListener的做用和關於spring中Aware結尾接口介紹

一、首先來介紹以Aware爲結尾接口

Spring中提供一些Aware結尾相關接口,像是BeanFactoryAware、 BeanNameAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。實現這些 Aware接口的Bean在被實例化 以後,能夠取得一些相對應的資源,例如實現BeanFactoryAware的Bean在實例化後,Spring容器將會注入BeanFactory的實例,而實現ApplicationContextAware的Bean,在Bean被實例化後,將會被注入 ApplicationContext的實例等等。經過重寫setter方法,當前bean被實例化後實現相關實例的注入。

//實現BeanNameAware接口,並重寫setBeanName()方法,讓Bean獲取本身在BeanFactory配置中的名字
//(根據狀況是id或者name)
//實現ApplicationContextAware接口,並重寫setApplicationContext()方法
public class MyApplicationContext implements BeanNameAware,ApplicationContextAware{
    private String beanName;

    //注入的beanName即爲MyApplicationContext在BeanFactory配置中的名字(根據狀況是id或者name)
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
        System.out.println("MyApplicationContext beanName:"+beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        //經過重寫的接口方法,獲取spring容器實例context,進而獲取容器中相關bean資源
        System.out.println(context.getBean(this.beanName).hashCode());

    }

}

注意:除了經過實現Aware結尾接口獲取spring內置對象,也能夠經過@Autowired註解直接注入相關對象,(若是須要用到靜態方法中,如工具方法,仍是採用實現接口的方式).

二、ApplicationContextAware、ApplicationListener的做用

什麼是ApplicationContext? 
它是Spring的核心,Context咱們一般解釋爲上下文環境,可是理解成容器會更好些。 
ApplicationContext則是應用的容器。Spring把Bean(object)放在容器中,須要用就經過get方法取出來。

ApplicationEvent

是個抽象類,裏面只有一個構造函數和一個長整型的timestamp。
ApplicationListener

是一個接口,裏面只有一個onApplicationEvent方法。因此本身的類在實現該接口的時候,要實裝該方法。若是在上下文中部署一個實現了ApplicationListener接口的bean,那麼每當在一個ApplicationEvent發佈到 ApplicationContext時,這個bean獲得通知。其實這就是標準的Oberver設計模式。

其中ApplicationContextAware接口能夠實現咱們在初始化bean的時候給bean注入ApplicationConxt(Spring上下文對象)對象。ApplicationContextAware接口提供了publishEvent方法,實現了Observe(觀察者)設計模式的傳播機制,實現了對bean的傳播。經過ApplicationContextAware咱們能夠把系統中全部ApplicationEvent傳播給系統中全部的ApplicationListener。所以,咱們只須要構造好咱們本身的ApplicationEvent和ApplicationListener,就能夠在系統中實現相應的監聽器。

資料:http://blog.csdn.net/u011955252/article/details/52900690

7、BeanDefinition、PropertyEditorSupport的做用

1.BeanDefinition

將Bean的定義信息存儲到這個BeanDefinition相應的屬性中,後面對Bean的操做就直接對BeanDefinition進行,例如拿到這個BeanDefinition後,能夠根據裏面的類名、構造函數、構造函數參數,使用反射進行對象建立。BeanDefinition是一個接口,是一個抽象的定義,實際使用的是其實現類,如ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition等。BeanDefinition繼承了AttributeAccessor,說明它具備處理屬性的能力;BeanDefinition繼承了BeanMetadataElement,說明它能夠持有Bean元數據元素,做用是能夠持有XML文件的一個bean標籤對應的Object。

詳細解讀的流程資料:http://blog.51cto.com/dba10g/1726519

二、PropertyEditorSupport

經過繼承JDK 中的 java.beans.PropertyEditorSupport 類來實現本身的編輯器類 ,該類用於實現將String 類型轉換成您須要的數據類型。而後咱們只須要在Spring 的容器中對這個編輯器進行有效的「註冊」即可以實現Spring 在裝配Bean 時自動的將String 類型轉換成咱們自定義的類型。

如何編輯本身的PropertyEditor,其實須要瞭解一點java.beans包的知識,在該包中,有一個 java.beans.PropertyEditor的接口,它定義了一套接口方法(12個),即經過這些方法如何將一個String變成內部的一個對 象,這兩個方法是比較重要的: 
     a)setValue(Object value) 直接設置一個對象
     b)setAsText(String text) 經過一個字符串來構造對象,通常在此方法中解析字符串,將構造一個類對象,調用setValue(Object)來完成屬性對象設置操做。 
  2)實現全部的接口方法是麻煩的,java.beans.PropertyEditorSupport 適時登場,通常狀況下,咱們經過擴展這個方便類便可。好比轉換時間格式:

import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;

import org.jflame.toolkit.util.DateHelper;
import org.springframework.util.StringUtils;

/**
 * 多日期格式轉換器<p>
 * 默認支持格式:"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss","yyyy年MM月dd日","yyyyMMddHHmmss"
 * 
 *
 */
public class MyCustomDateEditor extends PropertyEditorSupport {
	
	private final DateFormat defaultDateFormat;
	
	public MyCustomDateEditor(){
		defaultDateFormat=null;
	}
	
	/**
	 * 構造函數,指定特定格式DateFormat
	 * @param dateFormat
	 */
	public MyCustomDateEditor(DateFormat dateFormat) {
		this.defaultDateFormat = dateFormat;
	}
	
	/**
	 * Parse the Date from the given text, using the specified DateFormat.
	 */
	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		if (!StringUtils.hasText(text)) {
			setValue(null);
		}
		else {
			try {
				//未指定固定格式器,使用全部支持格式處理
				if(defaultDateFormat==null){
					setValue(DateHelper.parseDate(text, DateHelper.formats));
				}else{
					setValue(this.defaultDateFormat.parse(text));
				}
			}
			catch (ParseException ex) {
				throw new IllegalArgumentException("Could not parse date: " + ex.getMessage(), ex);
			}
		}
	}

	/**
	 * Format the Date as String, using the specified DateFormat.
	 */
	@Override
	public String getAsText() {
		Date value = (Date) getValue();
		String dateStr = "";
		if (value != null) {
			if (defaultDateFormat == null) {
				if (value instanceof java.sql.Date) {
					dateStr = DateHelper.format(value, DateHelper.CN_YYYY_MM_DD);
				} else {
					dateStr = DateHelper.format(value, DateHelper.YYYY_MM_DD_HH_mm_ss);
				}
			} else {
				dateStr = this.defaultDateFormat.format(value);
			}
		}
		return dateStr;
	}
}

8、@Configuration註解、@Bean註解的使用

   一、@Configuration註解、@Bean註解

 Spring中爲了減小xml中配置,能夠聲明一個配置類(例如SpringConfig)來對bean進行配置。

咱們須要在用於指定配置信息的類上加上 @Configuration 註解,以明確指出該類是 Bean 配置的信息源。而且 Spring 對標註 Configuration 的類有以下要求: 

      (a) 配置類不能是 final 的;

      (b)配置類不能是本地化的,亦即不能將配置類定義在其餘類的方法內部;

      (c)配置類必須有一個無參構造函數。

@Configuration //在類上配置註解
public class BookStoreDaoConfig{  
@Bean   //在方法上配置註解
public UserDao userDao(){
   return new UserDaoImpl();//配置類必須有一個無參構造函數
}  
@Bean  
public BookDao bookDao(){
   return new BookDaoImpl();
}  
}

注意:Spring 在解析到以上文件時,將識別出標註 @Bean 的全部方法,執行之,並將方法的返回值 ( 這裏是 UserDaoImpl 和 BookDaoImpl 對象 ) 註冊到 IoC 容器中。默認狀況下,Bean 的名字即爲方法名。

a.@Bean 具備如下四個屬性:  

name -- 指定一個或者多個 Bean 的名字。這等價於 XML 配置中 的 name 屬性。

initMethod -- 容器在初始化完 Bean 以後,會調用該屬性指定的方法。這等價於 XML 配置中 的 init-method 屬性。

destroyMethod -- 該屬性與 initMethod 功能類似,在容器銷燬 Bean 以前,會調用該屬性指定的方法。這等價於 XML 配置中 的 destroy-method 屬性。

autowire -- 指定 Bean 屬性的自動裝配策略,取值是 Autowire 類型的三個靜態屬性。

      1. Autowire.BY_NAME,

       2.Autowire.BY_TYPE,

       3.Autowire.NO。

與 XML 配置中的 autowire 屬性的取值相比,這裏少了 constructor,這是由於 constructor 在這裏已經沒有意義了。@Bean 沒有直接提供指定做用域的屬性,能夠經過 @Scope 來實現該功能。

b.@Configuration註解

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Component  
public @interface Configuration {  
String value() default "";  

9、@Value和<util:properties>的使用

資料:http://blog.csdn.net/wangshfa/article/details/26674839

10、spring中的父子容器

spring總的上下文容器有父子之分,父容器和子容器。 父容器對子容器可見,子容器對父容器不可見 。

父子容器的主要用途是上下文隔離。以spring和SpringMVC爲例子。須要先熟悉spring是怎樣在web容器中啓動起來的。spring的啓動過程其實就是其IoC容器的啓動過程,對於web程序,IoC容器啓動過程便是創建上下文的過程。

spring的啓動過程:

  1. 首先,對於一個web應用,其部署在web容器中,web容器提供其一個全局的上下文環境,這個上下文就是ServletContext,其爲後面的spring IoC容器提供宿主環境;

  2. 其次,在web.xml中會提供有contextLoaderListener。在web容器啓動時,會觸發容器初始化事件,此時contextLoaderListener會監聽到這個事件,其contextInitialized方法會被調用,在這個方法中,spring會初始化一個啓動上下文,這個上下文被稱爲根上下文,即WebApplicationContext,這是一個接口類,確切的說,其實際的實現類是XmlWebApplicationContext。這個就是spring的IoC容器,其對應的Bean定義的配置由web.xml中的context-param標籤指定。在這個IoC容器初始化完畢後,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE爲屬性Key,將其存儲到ServletContext中,便於獲取;

  3. 再次,contextLoaderListener監聽器初始化完畢後,開始初始化web.xml中配置的Servlet,這個servlet能夠配置多個,以最多見的DispatcherServlet爲例,這個servlet其實是一個標準的前端控制器,用以轉發、匹配、處理每一個servlet請求。DispatcherServlet上下文在初始化的時候會創建本身的IoC上下文,用以持有spring mvc相關的bean。在創建DispatcherServlet本身的IoC上下文時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取以前的根上下文(即WebApplicationContext)做爲本身上下文的parent上下文。有了這個parent上下文以後,再初始化本身持有的上下文。這個DispatcherServlet初始化本身上下文的工做在其initStrategies方法中能夠看到,大概的工做就是初始化處理器映射、視圖解析等。這個servlet本身持有的上下文默認實現類也是mlWebApplicationContext。初始化完畢後,spring以與servlet的名字相關(此處不是簡單的以servlet名爲Key,而是經過一些轉換,具體可自行查看源碼)的屬性爲屬性Key,也將其存到ServletContext中,以便後續使用。這樣每一個servlet就持有本身的上下文,即擁有本身獨立的bean空間,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些bean。

何爲父子上下文呢?

父上下文:

使用listener監聽器來加載配置文件,以下:

<listener>   

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>   

</listener>


Spring 會建立一個WebApplicationContext上下文,稱爲父上下文(父容器),保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

可使用Spring提供的工具類取出上下文對象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

子上下文:

使用Spring MVC 來處理攔截相關的請求時,會配置DispatchServlet:

<servlet>

    <servlet-name>dispatcherServlet</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet

    </servlet-class>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/applicationContext-mvc.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>dispatcherServlet</servlet-name>

    <url-pattern>/</url-pattern>

</servlet-mapping>


每一個DispatchServlet會有一個本身的上下文,稱爲子上下文,它也保存在 ServletContext中,key 是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名稱。當一 個Request對象產生時,會把這個子上下文對象(WebApplicationContext)保存在Request對象中,key是 DispatcherServlet.class.getName() + ".CONTEXT"。

可使用工具類取出上下文對象:RequestContextUtils.getWebApplicationContext(request);

父上下文(父容器)和子上下文(子容器)的訪問權限:

子上下文能夠訪問父上下文中的bean,可是父上下文不能夠訪問子上下文中的bean。

父上下文使用與否

方案一,傳統型:

父上下文容器中保存數據源、服務層、DAO層、事務的Bean。

子上下文容器中保存Mvc相關的Action的Bean.

事務控制在服務層。

因爲父上下文容器不能訪問子上下文容器中內容,事務的Bean在父上下文容器中,沒法訪問子上下文容器中內容,就沒法對子上下文容器中Action進行AOP(事務)。

固然,作爲「傳統型」方案,也沒有必要這要作。

方案二,激進型:

Java世界的「面向接口編程」的思想是正確的,但在增刪改查爲主業務的系統裏,Dao層接口,Dao層實現類,Service層接口,Service層實現類,Action父類,Action。再加上衆多的O(vo\po\bo)和jsp頁面。寫一個小功能 七、8個類就寫出來了。 開發者說我就是想接點私活兒,和PHP,ASP搶搶飯碗,但我又是Java程序員。最好的結果是大項目能作好,小項目能作快。因此「激進型」方案就出現了-----沒有接口、沒有Service層、還能夠沒有衆多的O(vo\po\bo)。那沒有Service層事務控制在哪一層?只好上升的Action層。

本文不想說這是否是正確的思想,我想說的是Spring不會限制你這樣作。

因爲有了父子上下文,你將沒法實現這一目標。解決方案是隻使用子上下文容器,不要父上下文容器 。因此數據源、服務層、DAO層、事務的Bean、Action的Bean都放在子上下文容器中。就能夠實現了,事務(註解事務)就正常工做了。這樣纔夠激進。

總結:不使用listener監聽器來加載spring的配置文件,只使用DispatcherServl

11、@DependsOn註解的做用

相關文章
相關標籤/搜索