Spring面試問答Top 25

本人收集了一些在大家在面試時被經常問及的關於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 框架教程

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的環境下)和複雜的共同事物處理(比如利用JTA的複雜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配置文件中讀取上下文,並生成上下文定義。應用程序上下文從程序環境變量中取得。

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

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

1
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。

1
2
3
4
5
6
7
8
9
<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,這件最簡單的配置便能滿足應用程序配置運行時組件的需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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 聲明類請參考下面的代碼:

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig
{
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

對於上面的@Beans配置文件相同的XML配置文件如下:

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

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

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

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

1
2
3
4
5
@Configuration
@ComponentScan(basePackages = "com.howtodoinjava")
public class AppConfig  {
    ...
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<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文件中配置一下才能使用基於註解的裝配模式。如果你想要在你的應用程序中使用關於註解的方法的話,請參考如下的配置。

1
2
3
4
5
6
<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生命週期的代碼樣例如下:

1
2
3
4
<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內部使用。

1
2
3
4
5
6
public class Customer
{
    private Person person;
 
    //Setters and Getters
}
1
2
3
4
5
6
7
8
public class Person
{
    private String name;
    private String address;
    private int age;
 
    //Setters and Getters
}

內部bean的聲明方式如下:

1
2
3
4
5
6
7
8
9
10
<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> : 該標籤支持注入鍵和值都是字符串類型的鍵值對。

下面看一下具體的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<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">[email protected]</prop>
            <prop key="support">[email protected]</prop>
        </props>
    </property>
 
   </bean>
 
</beans>

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

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

1
2
3
4
5
6
7
8
9
10
11
<bean id="adminUser" class="com.howtodoinjava.common.Customer">
 
    <!-- java.util.Properties -->
    <property name="emails">
        <props>
            <prop key="admin">[email protected]</prop>
            <prop key="support">[email protected]</prop>
        </props>
    </property>
 
</bean>

也可用”util:”命名空間來從properties文件中創建出一個propertiesbean,然後利用setter方法注入bean的引用。

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

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

下面的XML配置文件表明瞭如何根據名稱將一個bean設置爲自動裝配:

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

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

1
<context:annotation-config />

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

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

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

1
2
3
4
@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>

1
2
3
<beans>
    <context:annotation-config />
</beans>

2、在bean配置文件中直接引入AutowiredAnnotationBeanPostProcessor

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

19、請舉例解釋@Required註解?

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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容器中對其進行註冊:

1
<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> 元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
   }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
<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的值。

1
2
3
4
5
public class Customer
{
    @Autowired
    private Person person;
}

下面我們要在配置文件中來配置Person類。

1
2
3
4
5
6
7
8
9
<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麼?不會的,但是運行上面的示例時,會拋出下面的異常:

1
2
3
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:

1
2
3
4
5
6
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會自動被通知。

1
2
3
4
5
6
7
8
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 類來開發自定義的事件。

1
2
3
4
5
6
7
8
public class CustomApplicationEvent extends ApplicationEvent
{
    public CustomApplicationEvent ( Object source, final String msg )
    {
        super(source);
        System.out.println("Created a Custom event");
    }
}

爲了監聽這個事件,還需要創建一個監聽器:

1
2
3
4
5
6
7
public class CustomEventListener implements ApplicationListener < CustomApplicationEvent >
{
    @Override
    public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
        //handle event
    }
}

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

1
2
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。
  • 前端控制器—Spring提供了DispatcherServlet來對請求進行分發。
  • 視圖幫助(View Helper )—Spring提供了一系列的JSP標籤,高效宏來輔助將分散的代碼整合在視圖裏。
  • 依賴注入—貫穿於BeanFactory / ApplicationContext接口的核心理念。
  • 工廠模式—BeanFactory用來創建對象的實例。

更多內容 : Best practices for writing spring configuration files

原文鏈接: howtodoinjava 翻譯: ImportNew.com 一直在路上
譯文鏈接: http://www.importnew.com/15851.html
轉載請保留原文出處、譯者和譯文鏈接。]
發佈了55 篇原創文章 · 獲贊 17 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章