25個經典的Spring面試問答

ImportNew發表於2015-05-01

本人收集了一些在大家在面試時被經常問及的關於Spring的主要問題,這些問題有可能在你下次面試時就會被問到。對於本文中未提及的Spring其他模組,我會單獨分享面試的問題和答案。

歡迎大家向我推薦你在面試過程中遇到關於Spring的問題。我會把大家推薦的問題新增到下面的Spring常用面試題清單中供大家參考。

問題清單:

  1. 什麼是Spring框架?Spring框架有哪些主要模組?
  2. 使用Spring框架有什麼好處?
  3. 什麼是控制反轉(IOC)?什麼是依賴注入?
  4. 請解釋下Spring中的IOC?
  5. BeanFactory和ApplicationContext有什麼區別?
  6. 將Spring配置到你的應用中共有幾種方法?
  7. 什麼基於XML的配置?
  8. 什麼基Java的配置?
  9. 怎樣用註解的方式配置Spring?
  10. 描述Spring Bean的生命週期?
  11. 描述Spring中各種Bean的範圍?
  12. 什麼是Spring的嵌入beans?
  13. Spring框架中的單例bean是否是執行緒安全的?
  14. 請舉例說明如何用Spring注入一個Java的集合類?
  15. 請舉例說明如何在Spring的Bean中注入一個java.util.Properties?
  16. 請解釋Spring的Bean的自動生成原理?
  17. 請辨析自動生成Bean之間模組的區別?
  18. 如何開啟基於基於註解的自動寫入?
  19. 請舉例說明@Required註解?
  20. 請舉例說明@Autowired註解?
  21. 請舉例說明@Qualifier註解?
  22. 請說明構造器注入和setter方法注入之間的區別?
  23. Spring框架中不同型別event有什麼區別?
  24. FileSystemResource和ClassPathResource有何區別?
  25. 請列舉Spring框架中用了哪些設計模式?

1、什麼是Spring框架?Spring框架有哪些主要模組?

Spring框架是一個為Java應用程式的開發提供了綜合、廣泛的基礎性支援的Java平臺。Spring幫助開發者解決了開發中基礎性的問題,使得開發人員可以專注於應用程式的開發。Spring框架本身亦是按照設計模式精心打造,這使得我們可以在開發環境中安心的整合Spring框架,不必擔心Spring是如何在後臺進行工作的。

Spring框架至今已整合了20多個模組。這些模組主要被分如下圖所示的核心容器、資料訪問/整合,、Web、AOP(面向切面程式設計)、工具、訊息和測試模組。

Spring面試問答Top 25

更多資訊:Spring 框架教程

2、使用Spring框架能帶來哪些好處?

下面列舉了一些使用Spring框架帶來的主要好處:

  • Dependency Injection(DI) 方法使得構造器和JavaBean properties檔案中的依賴關係一目瞭然。
  • 與EJB容器相比較,IoC容器更加趨向於輕量級。這樣一來IoC容器在有限的記憶體和CPU資源的情況下進行應用程式的開發和釋出就變得十分有利。
  • Spring並沒有閉門造車,Spring利用了已有的技術比如ORM框架、logging框架、J2EE、Quartz和JDK Timer,以及其他檢視技術。
  • Spring框架是按照模組的形式來組織的。由包和類的編號就可以看出其所屬的模組,開發者僅僅需要選用他們需要的模組即可。
  • 要測試一項用Spring開發的應用程式十分簡單,因為測試相關的環境程式碼都已經囊括在框架中了。更加簡單的是,利用JavaBean形式的POJO類,可以很方便的利用依賴注入來寫入測試資料。
  • Spring的Web框架亦是一個精心設計的Web MVC框架,為開發者們在web框架的選擇上提供了一個除了主流框架比如Struts、過度設計的、不流行web框架的以外的有力選項。
  • Spring提供了一個便捷的事務管理介面,適用於小型的本地事物處理(比如在單DB的環境下)和複雜的共同事物處理(比如利用J他的複雜DB環境)。

3、什麼是控制反轉(IOC)?什麼是依賴注入?

控制反轉是應用於軟體工程領域中的,在執行時被裝配器物件來繫結耦合物件的一種程式設計技巧,物件之間耦合關係在編譯時通常是未知的。在傳統的程式設計方式中,業務邏輯的流程是由應用程式中的早已被設定好關聯關係的物件來決定的。在使用控制反轉的情況下,業務邏輯的流程是由物件關係圖來決定的,該物件關係圖由裝配器負責例項化,這種實現方式還可以將物件之間的關聯關係的定義抽象化。而繫結的過程是通過“依賴注入”實現的。

控制反轉是一種以給予應用程式中目標元件更多控制為目的設計正規化,並在我們的實際工作中起到了有效的作用。

依賴注入是在編譯階段尚未知所需的功能是來自哪個的類的情況下,將其他物件所依賴的功能物件例項化的模式。這就需要一種機制用來啟用相應的元件以提供特定的功能,所以依賴注入是控制反轉的基礎。否則如果在元件不受框架控制的情況下,框架又怎麼知道要建立哪個元件?

在Java中依然注入有以下三種實現方式:

  1. 構造器注入
  2. Setter方法注入
  3. 介面注入

4、請解釋下Spring框架中的IoC?

Spring中的 org.springframework.beans 包和 org.springframework.context包構成了Spring框架IoC容器的基礎。

BeanFactory 介面提供了一個先進的配置機制,使得任何型別的物件的配置成為可能。ApplicationContex介面對BeanFactory(是一個子介面)進行了擴充套件,在BeanFactory的基礎上新增了其他功能,比如與Spring的AOP更容易整合,也提供了處理message resource的機制(用於國際化)、事件傳播以及應用層的特別配置,比如針對Web應用的WebApplicationContext。

org.springframework.beans.factory.BeanFactory 是Spring IoC容器的具體實現,用來包裝和管理前面提到的各種bean。BeanFactory介面是Spring IoC 容器的核心介面。

5、BeanFactory和ApplicationContext有什麼區別?

BeanFactory 可以理解為含有bean集合的工廠類。BeanFactory 包含了種bean的定義,以便在接收到客戶端請求時將對應的bean例項化。

BeanFactory還能在例項化物件的時生成協作類之間的關係。此舉將bean自身與bean客戶端的配置中解放出來。BeanFactory還包含了bean生命週期的控制,呼叫客戶端的初始化方法(initialization methods)和銷燬方法(destruction methods)。

從表面上看,application context如同bean factory一樣具有bean定義、bean關聯關係的設定,根據請求分發bean的功能。但application context在此基礎上還提供了其他的功能。

  1. 提供了支援國際化的文字訊息
  2. 統一的資原始檔讀取方式
  3. 已在監聽器中註冊的bean的事件

以下是三種較常見的 ApplicationContext 實現方式:

1、ClassPathXmlApplicationContext:從classpath的XML配置檔案中讀取上下文,並生成上下文定義。應用程式上下文從程式環境變數中取得。

ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);

2、FileSystemXmlApplicationContext :由檔案系統中的XML配置檔案讀取上下文。

ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);

3、XmlWebApplicationContext:由Web應用的XML檔案讀取上下文。

6、Spring有幾種配置方式?

將Spring配置到應用開發中有以下三種方式:

  1. 基於XML的配置
  2. 基於註解的配置
  3. 基於Java的配置

7、如何用基於XML配置的方式配置Spring?

在Spring框架中,依賴和服務需要在專門的配置檔案來實現,我常用的XML格式的配置檔案。這些配置檔案的格式通常用<beans>開頭,然後一系列的bean定義和專門的應用配置選項組成。

SpringXML配置的主要目的時候是使所有的Spring元件都可以用xml檔案的形式來進行配置。這意味著不會出現其他的Spring配置型別(比如宣告的方式或基於Java Class的配置方式)

Spring的XML配置方式是使用被Spring名稱空間的所支援的一系列的XML標籤來實現的。Spring有以下主要的名稱空間:context、beans、jdbc、tx、aop、mvc和aso。

<beans>

    <!-- JSON Support -->
    <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
    <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>

</beans>

下面這個web.xml僅僅配置了DispatcherServlet這件最簡單的配置便能滿足應用程式配置執行時元件的需求。

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
        <servlet-name>spring</servlet-name>
            <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

8、如何用基於Java配置的方式配置Spring?

Spring對Java配置的支援是由@Configuration註解和@Bean註解來實現的。由@Bean註解的方法將會例項化、配置和初始化一個新物件,這個物件將由Spring的IoC容器來管理。@Bean宣告所起到的作用與<bean/> 元素類似。被@Configuration所註解的類則表示這個類的主要目的是作為bean定義的資源。被@Configuration宣告的類可以通過在同一個類的內部呼叫@bean方法來設定嵌入bean的依賴關係。

最簡單的@Configuration 宣告類請參考下面的程式碼:

@Configuration
public class AppConfig
{
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

對於上面的@Beans配置檔案相同的XML配置檔案如下:

<beans>
    <bean id="myService" class="com.howtodoinjava.services.MyServiceImpl"/>
</beans>

上述配置方式的例項化方式如下:利用AnnotationConfigApplicationContext 類進行例項化

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

要使用元件組建掃描,僅需用@Configuration進行註解即可:

@Configuration
@ComponentScan(basePackages = "com.howtodoinjava")
public class AppConfig  {
    ...
}

在上面的例子中,com.acme包首先會被掃到,然後再容器內查詢被@Component 宣告的類,找到後將這些類按照Sring bean定義進行註冊。

如果你要在你的web應用開發中選用上述的配置的方式的話,需要用AnnotationConfigWebApplicationContext 類來讀取配置檔案,可以用來配置Spring的Servlet監聽器ContrextLoaderListener或者Spring MVC的DispatcherServlet。

<web-app>
    <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
        instead of the default XmlWebApplicationContext -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <!-- Configuration locations must consist of one or more comma- or space-delimited
        fully-qualified @Configuration classes. Fully-qualified packages may also be
        specified for component-scanning -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.howtodoinjava.AppConfig</param-value>
    </context-param>

    <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
            instead of the default XmlWebApplicationContext -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <!-- Again, config locations must consist of one or more comma- or space-delimited
            and fully-qualified @Configuration classes -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.howtodoinjava.web.MvcConfig</param-value>
        </init-param>
    </servlet>

    <!-- map all requests for /app/* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
</web-app>

9、怎樣用註解的方式配置Spring?

Spring在2.5版本以後開始支援用註解的方式來配置依賴注入。可以用註解的方式來替代XML方式的bean描述,可以將bean描述轉移到元件類的內部,只需要在相關類上、方法上或者欄位宣告上使用註解即可。註解注入將會被容器在XML注入之前被處理,所以後者會覆蓋掉前者對於同一個屬性的處理結果。

註解裝配在Spring中是預設關閉的。所以需要在Spring檔案中配置一下才能使用基於註解的裝配模式。如果你想要在你的應用程式中使用關於註解的方法的話,請參考如下的配置。

<beans>

   <context:annotation-config/>
   <!-- bean definitions go here -->

</beans>

在 <context:annotation-config/>標籤配置完成以後,就可以用註解的方式在Spring中向屬性、方法和構造方法中自動裝配變數。

下面是幾種比較重要的註解型別:

  1. @Required:該註解應用於設值方法。
  2. @Autowired:該註解應用於有值設值方法、非設值方法、構造方法和變數。
  3. @Qualifier:該註解和@Autowired註解搭配使用,用於消除特定bean自動裝配的歧義。
  4. JSR-250 Annotations:Spring支援基於JSR-250 註解的以下註解,@Resource、@PostConstruct 和 @PreDestroy。

10、請解釋Spring Bean的生命週期?

Spring Bean的生命週期簡單易懂。在一個bean例項被初始化時,需要執行一系列的初始化操作以達到可用的狀態。同樣的,當一個bean不在被呼叫時需要進行相關的析構操作,並從bean容器中移除。

Spring bean factory 負責管理在spring容器中被建立的bean的生命週期。Bean的生命週期由兩組回撥(call back)方法組成。

  1. 初始化之後呼叫的回撥方法。
  2. 銷燬之前呼叫的回撥方法。

Spring框架提供了以下四種方式來管理bean的生命週期事件:

  • InitializingBean和DisposableBean回撥介面
  • 針對特殊行為的其他Aware介面
  • Bean配置檔案中的Custom init()方法和destroy()方法
  • @PostConstruct和@PreDestroy註解方式

使用customInit()和 customDestroy()方法管理bean生命週期的程式碼樣例如下:

<beans>
    <bean id="demoBean" class="com.howtodoinjava.task.DemoBean"
            init-method="customInit" destroy-method="customDestroy"></bean>
</beans>

更多內容請參考:Spring生命週期Spring Bean Life Cycle。

11、Spring Bean的作用域之間有什麼區別?

Spring容器中的bean可以分為5個範圍。所有範圍的名稱都是自說明的,但是為了避免混淆,還是讓我們來解釋一下:

  1. singleton:這種bean範圍是預設的,這種範圍確保不管接受到多少個請求,每個容器中只有一個bean的例項,單例的模式由bean factory自身來維護。
  2. prototype:原形範圍與單例範圍相反,為每一個bean請求提供一個例項。
  3. request:在請求bean範圍內會每一個來自客戶端的網路請求建立一個例項,在請求完成以後,bean會失效並被垃圾回收器回收。
  4. Session:與請求範圍類似,確保每個session中有一個bean的例項,在session過期後,bean會隨之失效。
  5. global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要宣告讓所有的portlet共用全域性的儲存變數的話,那麼這全域性變數需要儲存在global-session中。

全域性作用域與Servlet中的session作用域效果相同。

更多內容請參考 : Spring Bean Scopes

12、什麼是Spring inner beans?

在Spring框架中,無論何時bean被使用時,當僅被呼叫了一個屬性。一個明智的做法是將這個bean宣告為內部bean。內部bean可以用setter注入“屬性”和構造方法注入“構造引數”的方式來實現。

比如,在我們的應用程式中,一個Customer類引用了一個Person類,我們的要做的是建立一個Person的例項,然後在Customer內部使用。

public class Customer
{
    private Person person;

    //Setters and Getters
}
public class Person
{
    private String name;
    private String address;
    private int age;

    //Setters and Getters
}

內部bean的宣告方式如下:

<bean id="CustomerBean" class="com.howtodoinjava.common.Customer">
    <property name="person">
        <!-- This is inner bean -->
        <bean class="com.howtodoinjava.common.Person">
            <property name="name" value="lokesh" />
            <property name="address" value="India" />
            <property name="age" value="34" />
        </bean>
    </property>
</bean>

13、Spring框架中的單例Beans是執行緒安全的麼?

Spring框架並沒有對單例bean進行任何多執行緒的封裝處理。關於單例bean的執行緒安全和併發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是執行緒安全的。如果你的bean有多種狀態的話(比如 View Model 物件),就需要自行保證執行緒安全。

最淺顯的解決辦法就是將多型bean的作用域由“singleton”變更為“prototype”。

14、請舉例說明如何在Spring中注入一個Java Collection?

Spring提供了以下四種集合類的配置元素:

  • <list> :   該標籤用來裝配可重複的list值。
  • <set> :    該標籤用來裝配沒有重複的set值。
  • <map>:   該標籤可用來注入鍵和值可以為任何型別的鍵值對。
  • <props> : 該標籤支援注入鍵和值都是字串型別的鍵值對。

下面看一下具體的例子:

<beans>

   <!-- Definition for javaCollection -->
   <bean id="javaCollection" class="com.howtodoinjava.JavaCollection">

      <!-- java.util.List -->
      <property name="customList">
        <list>
           <value>INDIA</value>
           <value>Pakistan</value>
           <value>USA</value>
           <value>UK</value>
        </list>
      </property>

     <!-- java.util.Set -->
     <property name="customSet">
        <set>
           <value>INDIA</value>
           <value>Pakistan</value>
           <value>USA</value>
           <value>UK</value>
        </set>
      </property>

     <!-- java.util.Map -->
     <property name="customMap">
        <map>
           <entry key="1" value="INDIA"/>
           <entry key="2" value="Pakistan"/>
           <entry key="3" value="USA"/>
           <entry key="4" value="UK"/>
        </map>
      </property>

      <!-- java.util.Properties -->
    <property name="customProperies">
        <props>
            <prop key="admin">admin@nospam.com</prop>
            <prop key="support">support@nospam.com</prop>
        </props>
    </property>

   </bean>

</beans>

15、如何向Spring Bean中注入一個Java.util.Properties?

第一種方法是使用如下面程式碼所示的<props> 標籤:

<bean id="adminUser" class="com.howtodoinjava.common.Customer">

    <!-- java.util.Properties -->
    <property name="emails">
        <props>
            <prop key="admin">admin@nospam.com</prop>
            <prop key="support">support@nospam.com</prop>
        </props>
    </property>

</bean>

也可用”util:”名稱空間來從properties檔案中建立出一個propertiesbean,然後利用setter方法注入bean的引用。

16、請解釋Spring Bean的自動裝配?

在Spring框架中,在配置檔案中設定bean的依賴關係是一個很好的機制,Spring容器還可以自動裝配合作關係bean之間的關聯關係。這意味著Spring可以通過向Bean Factory中注入的方式自動搞定bean之間的依賴關係。自動裝配可以設定在每個bean上,也可以設定在特定的bean上。

下面的XML配置檔案表明瞭如何根據名稱將一個bean設定為自動裝配:

<bean id="employeeDAO" class="com.howtodoinjava.EmployeeDAOImpl" autowire="byName" />

除了bean配置檔案中提供的自動裝配模式,還可以使用@Autowired註解來自動裝配指定的bean。在使用@Autowired註解之前需要在按照如下的配置方式在Spring配置檔案進行配置才可以使用。

<context:annotation-config />

也可以通過在配置檔案中配置AutowiredAnnotationBeanPostProcessor 達到相同的效果。

<bean class ="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

配置好以後就可以使用@Autowired來標註了。

@Autowired
public EmployeeDAOImpl ( EmployeeManager manager ) {
    this.manager = manager;
}

17、請解釋自動裝配模式的區別?

在Spring框架中共有5種自動裝配,讓我們逐一分析。

  1. no:這是Spring框架的預設設定,在該設定下自動裝配是關閉的,開發者需要自行在bean定義中用標籤明確的設定依賴關係。
  2. byName:該選項可以根據bean名稱設定依賴關係。當向一個bean中自動裝配一個屬性時,容器將根據bean的名稱自動在在配置檔案中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
  3. byType:該選項可以根據bean型別設定依賴關係。當向一個bean中自動裝配一個屬性時,容器將根據bean的型別自動在在配置檔案中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
  4. constructor:造器的自動裝配和byType模式類似,但是僅僅適用於與有構造器相同引數的bean,如果在容器中沒有找到與構造器引數型別一致的bean,那麼將會丟擲異常。
  5. autodetect該模式自動探測使用構造器自動裝配或者byType自動裝配。首先,首先會嘗試找合適的帶引數的構造器,如果找到的話就是用構造器自動裝配,如果在bean內部沒有找到相應的構造器或者是無參構造器,容器就會自動選擇byTpe的自動裝配方式。

18、如何開啟基於註解的自動裝配?

要使用 @Autowired,需要註冊 AutowiredAnnotationBeanPostProcessor,可以有以下兩種方式來實現:

1、引入配置檔案中的<bean>下引入 <context:annotation-config>

<beans>
    <context:annotation-config />
</beans>

2、在bean配置檔案中直接引入AutowiredAnnotationBeanPostProcessor

<beans>
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
</beans>

19、請舉例解釋@Required annotation?

在產品級別的應用中,IoC容器可能宣告瞭數十萬了bean,bean與bean之間有著複雜的依賴關係。設值註解方法的短板之一就是驗證所有的屬性是否被註解是一項十分困難的操作。可以通過在<bean>中設定“dependency-check”來解決這個問題。

在應用程式的生命週期中,你可能不大願意花時間在驗證所有bean的屬性是否按照上下文檔案正確配置。或者你寧可驗證某個bean的特定屬性是否被正確的設定。即使是用“dependency-check”屬性也不能很好的解決這個問題,在這種情況下,你需要使用@Required 註解。

需要用如下的方式使用來標明bean的設值方法。

public class EmployeeFactoryBean extends AbstractFactoryBean<Object>
{
    private String designation;

    public String getDesignation() {
        return designation;
    }

    @Required
    public void setDesignation(String designation) {
        this.designation = designation;
    }

    //more code here
}

RequiredAnnotationBeanPostProcessor是Spring中的後置處理用來驗證被@Required 註解的bean屬性是否被正確的設定了。在使用RequiredAnnotationBeanPostProcesso來驗證bean屬性之前,首先要在IoC容器中對其進行註冊:

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />

但是如果沒有屬性被用 @Required 註解過的話,後置處理器會丟擲一個BeanInitializationException 異常。

20、請舉例解釋@Autowired註解?

@Autowired註解對自動裝配何時何處被實現提供了更多細粒度的控制。@Autowired註解可以像@Required註解、構造器一樣被用於在bean的設值方法上自動裝配bean的屬性,一個引數或者帶有任意名稱或帶有多個引數的方法。

比如,可以在設值方法上使用@Autowired註解來替代配置檔案中的 <property>元素。當Spring容器在setter方法上找到@Autowired註解時,會嘗試用byType 自動裝配。

當然我們也可以在構造方法上使用@Autowired 註解。帶有@Autowired 註解的構造方法意味著在建立一個bean時將會被自動裝配,即便在配置檔案中使用<constructor-arg> 元素。

public class TextEditor {
   private SpellChecker spellChecker;

   @Autowired
   public TextEditor(SpellChecker spellChecker){
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }

   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

下面是沒有構造引數的配置方式:

<beans>

   <context:annotation-config/>

   <!-- Definition for textEditor bean without constructor-arg  -->
   <bean id="textEditor" class="com.howtodoinjava.TextEditor">
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.howtodoinjava.SpellChecker">
   </bean>

</beans>

21、請舉例說明@Qualifier註解?

@Qualifier註解意味著可以在被標註bean的欄位上可以自動裝配。Qualifier註解可以用來取消Spring不能取消的bean應用。

下面的示例將會在Customer的person屬性中自動裝配person的值。

public class Customer
{
    @Autowired
    private Person person;
}

下面我們要在配置檔案中來配置Person類。

<bean id="customer" class="com.howtodoinjava.common.Customer" />

<bean id="personA" class="com.howtodoinjava.common.Person" >
    <property name="name" value="lokesh" />
</bean>

<bean id="personB" class="com.howtodoinjava.common.Person" >
    <property name="name" value="alex" />
</bean>

Spring會知道要自動裝配哪個person bean麼?不會的,但是執行上面的示例時,會丟擲下面的異常:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
    No unique bean of type [com.howtodoinjava.common.Person] is defined:
        expected single matching bean but found 2: [personA, personB]

要解決上面的問題,需要使用 @Quanlifier註解來告訴Spring容器要裝配哪個bean:

public class Customer
{
    @Autowired
    @Qualifier("personA")
    private Person person;
}

22、構造方法注入和設值注入有什麼區別?

請注意以下明顯的區別:

  1. 在設值注入方法支援大部分的依賴注入,如果我們僅需要注入int、string和long型的變數,我們不要用設值的方法注入。對於基本型別,如果我們沒有注入的話,可以為基本型別設定預設值。在構造方法注入不支援大部分的依賴注入,因為在呼叫構造方法中必須傳入正確的構造引數,否則的話為報錯。
  2. 設值注入不會重寫構造方法的值。如果我們對同一個變數同時使用了構造方法注入又使用了設定方法注入的話,那麼構造方法將不能覆蓋由設值方法注入的值。很明顯,因為構造方法盡在物件被建立時呼叫。
  3. 在使用設值注入時有可能還不能保證某種依賴是否已經被注入,也就是說這時物件的依賴關係有可能是不完整的。而在另一種情況下,構造器注入則不允許生成依賴關係不完整的物件。
  4. 在設值注入時如果物件A和物件B互相依賴,在建立物件A時Spring會丟擲sObjectCurrentlyInCreationException異常,因為在B物件被建立之前A物件是不能被建立的,反之亦然。所以Spring用設值注入的方法解決了迴圈依賴的問題,因物件的設值方法是在物件被建立之前被呼叫的。

23、Spring框架中有哪些不同型別的事件?

Spring的ApplicationContext 提供了支援事件和程式碼中監聽器的功能。

我們可以建立bean用來監聽在ApplicationContext 中釋出的事件。ApplicationEvent類和在ApplicationContext介面中處理的事件,如果一個bean實現了ApplicationListener介面,當一個ApplicationEvent 被髮布以後,bean會自動被通知。

public class AllApplicationEventListener implements ApplicationListener < ApplicationEvent >
{
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent)
    {
        //process event
    }
}

Spring 提供了以下5中標準的事件:

  1. 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時釋出。也可以在呼叫ConfigurableApplicationContext 介面中的refresh()方法時被觸發。
  2. 上下文開始事件(ContextStartedEvent):當容器呼叫ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
  3. 上下文停止事件(ContextStoppedEvent):當容器呼叫ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
  4. 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。
  5. 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

除了上面介紹的事件以外,還可以通過擴充套件ApplicationEvent 類來開發自定義的事件。

public class CustomApplicationEvent extends ApplicationEvent
{
    public CustomApplicationEvent ( Object source, final String msg )
    {
        super(source);
        System.out.println("Created a Custom event");
    }
}

為了監聽這個事件,還需要建立一個監聽器:

public class CustomEventListener implements ApplicationListener < CustomApplicationEvent >
{
    @Override
    public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
        //handle event
    }
}

之後通過applicationContext介面的publishEvent()方法來發布自定義事件。

CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message");
applicationContext.publishEvent(customEvent);

24、FileSystemResource和ClassPathResource有何區別?

FileSystemResource 中需要給出spring-config.xml檔案在你專案中的相對路徑或者絕對路徑。在ClassPathResource中spring會在ClassPath中自動搜尋配置檔案,所以要把ClassPathResource 檔案放在ClassPath下。

如果將spring-config.xml儲存在了src資料夾下的話,只需給出配置檔案的名稱即可,因為src資料夾是預設。

簡而言之,ClassPathResource在環境變數中讀取配置檔案,FileSystemResource在配置檔案中讀取配置檔案。

25、Spring 框架中都用到了哪些設計模式

Spring框架中使用到了大量的設計模式,下面列舉了比較有代表性的:

  • 代理模式—在AOP和remoting中被用的比較多。
  • 單例模式—在spring配置檔案中定義的bean預設為單例模式。
  • 模板方法—用來解決程式碼重複的問題。
  • 比如. RestTemplateJmsTemplateJpaTemplate。
  • 前端控制器—Srping提供了DispatcherServlet來對請求進行分發。
  • 檢視幫助(View Helper )—Spring提供了一系列的JSP標籤,高效巨集來輔助將分散的程式碼整合在檢視裡。
  • 依賴注入—貫穿於BeanFactory / ApplicationContext介面的核心理念。
  • 工廠模式—BeanFactory用來建立物件的例項。

相關文章