問題清單:
- 什么是Spring框架?Spring框架有哪些主要模塊?
- 使用Spring框架有什么好處?
- 什么是控制反轉(IOC)?什么是依賴注入?
- 請解釋下Spring中的IOC?
- BeanFactory和ApplicationContext有什么區(qū)別?
- 將Spring配置到你的應用中共有幾種方法?
- 什么基于XML的配置?
- 什么基Java的配置?
- 怎樣用注解的方式配置Spring?
- 描述Spring Bean的生命周期?
- 描述Spring中各種Bean的范圍?
- 什么是Spring的嵌入beans?
- Spring框架中的單例bean是否是線程安全的?
- 請舉例說明如何用Spring注入一個Java的集合類?
- 請舉例說明如何在Spring的Bean中注入一個java.util.Properties?
- 請解釋Spring的Bean的自動生成原理?
- 請辨析自動生成Bean之間模塊的區(qū)別?
- 如何開啟基于基于注解的自動寫入?
- 請舉例說明@Required注解?
- 請舉例說明@Autowired注解?
- 請舉例說明@Qualifier注解?
- 請說明構造器注入和setter方法注入之間的區(qū)別?
- Spring框架中不同類型event有什么區(qū)別?
- FileSystemResource和ClassPathResource有何區(qū)別?
- 請列舉Spring框架中用了哪些設計模式?
1、什么是Spring框架?Spring框架有哪些主要模塊?
Spring框架是一個為Java應用程序的開發(fā)提供了綜合、廣泛的基礎性支持的Java平臺。Spring幫助開發(fā)者解決了開發(fā)中基礎性的問題,使得開發(fā)人員可以專注于應用程序的開發(fā)。Spring框架本身亦是按照設計模式精心打造,這使得我們可以在開發(fā)環(huán)境中安心的集成Spring框架,不必擔心Spring是如何在后臺進行工作的。
Spring框架至今已集成了20多個模塊。這些模塊主要被分如下圖所示的核心容器、數(shù)據(jù)訪問/集成,、Web、AOP(面向切面編程)、工具、消息和測試模塊。
更多信息:Spring 框架教程。
2、使用Spring框架能帶來哪些好處?
下面列舉了一些使用Spring框架帶來的主要好處:
- Dependency Injection(DI) 方法使得構造器和JavaBean properties文件中的依賴關系一目了然。
- 與EJB容器相比較,IoC容器更加趨向于輕量級。這樣一來IoC容器在有限的內存和CPU資源的情況下進行應用程序的開發(fā)和發(fā)布就變得十分有利。
- Spring并沒有閉門造車,Spring利用了已有的技術比如ORM框架、logging框架、J2EE、Quartz和JDK Timer,以及其他視圖技術。
- Spring框架是按照模塊的形式來組織的。由包和類的編號就可以看出其所屬的模塊,開發(fā)者僅僅需要選用他們需要的模塊即可。
- 要測試一項用Spring開發(fā)的應用程序十分簡單,因為測試相關的環(huán)境代碼都已經(jīng)囊括在框架中了。更加簡單的是,利用JavaBean形式的POJO類,可以很方便的利用依賴注入來寫入測試數(shù)據(jù)。
- Spring的Web框架亦是一個精心設計的Web MVC框架,為開發(fā)者們在web框架的選擇上提供了一個除了主流框架比如Struts、過度設計的、不流行web框架的以外的有力選項。
- Spring提供了一個便捷的事務管理接口,適用于小型的本地事物處理(比如在單DB的環(huán)境下)和復雜的共同事物處理(比如利用JTA的復雜DB環(huán)境)。
3、什么是控制反轉(IOC)?什么是依賴注入?
控制反轉是應用于軟件工程領域中的,在運行時被裝配器對象來綁定耦合對象的一種編程技巧,對象之間耦合關系在編譯時通常是未知的。在傳統(tǒng)的編程方式中,業(yè)務邏輯的流程是由應用程序中的早已被設定好關聯(lián)關系的對象來決定的。在使用控制反轉的情況下,業(yè)務邏輯的流程是由對象關系圖來決定的,該對象關系圖由裝配器負責實例化,這種實現(xiàn)方式還可以將對象之間的關聯(lián)關系的定義抽象化。而綁定的過程是通過“依賴注入”實現(xiàn)的。
控制反轉是一種以給予應用程序中目標組件更多控制為目的設計范式,并在我們的實際工作中起到了有效的作用。
依賴注入是在編譯階段尚未知所需的功能是來自哪個的類的情況下,將其他對象所依賴的功能對象實例化的模式。這就需要一種機制用來激活相應的組件以提供特定的功能,所以依賴注入是控制反轉的基礎。否則如果在組件不受框架控制的情況下,框架又怎么知道要創(chuàng)建哪個組件?
在Java中依然注入有以下三種實現(xiàn)方式:
- 構造器注入
- Setter方法注入
- 接口注入
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容器的具體實現(xiàn),用來包裝和管理前面提到的各種bean。BeanFactory接口是Spring IoC 容器的核心接口。
5、BeanFactory和ApplicationContext有什么區(qū)別?
BeanFactory 可以理解為含有bean集合的工廠類。BeanFactory 包含了種bean的定義,以便在接收到客戶端請求時將對應的bean實例化。
BeanFactory還能在實例化對象的時生成協(xié)作類之間的關系。此舉將bean自身與bean客戶端的配置中解放出來。BeanFactory還包含了bean生命周期的控制,調用客戶端的初始化方法(initialization methods)和銷毀方法(destruction methods)。
從表面上看,application context如同bean factory一樣具有bean定義、bean關聯(lián)關系的設置,根據(jù)請求分發(fā)bean的功能。但application context在此基礎上還提供了其他的功能。
- 提供了支持國際化的文本消息
- 統(tǒng)一的資源文件讀取方式
- 已在監(jiān)聽器中注冊的bean的事件
以下是三種較常見的 ApplicationContext 實現(xiàn)方式:
1、ClassPathXmlApplicationContext:從classpath的XML配置文件中讀取上下文,并生成上下文定義。應用程序上下文從程序環(huán)境變量中取得。
1 | ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);
|
2、FileSystemXmlApplicationContext :由文件系統(tǒng)中的XML配置文件讀取上下文。
1 | ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);
|
3、XmlWebApplicationContext:由Web應用的XML文件讀取上下文。
6、Spring有幾種配置方式?
將Spring配置到應用開發(fā)中有以下三種方式:
- 基于XML的配置
- 基于注解的配置
- 基于Java的配置
7、如何用基于XML配置的方式配置Spring?
在Spring框架中,依賴和服務需要在專門的配置文件來實現(xiàn),我常用的XML格式的配置文件。這些配置文件的格式通常用<beans> 開頭,然后一系列的 bean 定義和專門的應用配置選項組成。
SpringXML配置的主要目的時候是使所有的Spring組件都可以用xml文件的形式來進行配置。這意味著不會出現(xiàn)其他的Spring配置類型(比如聲明的方式或基于Java Class的配置方式)
Spring的XML配置方式是使用被Spring命名空間的所支持的一系列的XML標簽來實現(xiàn)的。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注解來實現(xiàn)的。由@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應用開發(fā)中選用上述的配置的方式的話,需要用AnnotationConfigWebApplicationContext 類來讀取配置文件,可以用來配置Spring的Servlet監(jiān)聽器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版本以后開始支持用注解的方式來配置依賴注入??梢杂米⒔獾姆绞絹硖娲鶻ML方式的bean描述,可以將bean描述轉移到組件類的內部,只需要在相關類上、方法上或者字段聲明上使用注解即可。注解注入將會被容器在XML注入之前被處理,所以后者會覆蓋掉前者對于同一個屬性的處理結果。
注解裝配在Spring中是默認關閉的。所以需要在Spring文件中配置一下才能使用基于注解的裝配模式。如果你想要在你的應用程序中使用關于注解的方法的話,請參考如下的配置。
1 2 3 4 5 6 | < beans >
< context:annotation-config />
<!-- bean definitions go here -->
</ beans >
|
在 <context:annotation-config/>標簽配置完成以后,就可以用注解的方式在Spring中向屬性、方法和構造方法中自動裝配變量。
下面是幾種比較重要的注解類型:
- @Required:該注解應用于設值方法。
- @Autowired:該注解應用于有值設值方法、非設值方法、構造方法和變量。
- @Qualifier:該注解和@Autowired注解搭配使用,用于消除特定bean自動裝配的歧義。
- JSR-250 Annotations:Spring支持基于JSR-250 注解的以下注解,@Resource、@PostConstruct 和 @PreDestroy。
10、請解釋Spring Bean的生命周期?
Spring Bean的生命周期簡單易懂。在一個bean實例被初始化時,需要執(zhí)行一系列的初始化操作以達到可用的狀態(tài)。同樣的,當一個bean不在被調用時需要進行相關的析構操作,并從bean容器中移除。
Spring bean factory 負責管理在spring容器中被創(chuàng)建的bean的生命周期。Bean的生命周期由兩組回調(call back)方法組成。
- 初始化之后調用的回調方法。
- 銷毀之前調用的回調方法。
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的作用域之間有什么區(qū)別?
Spring容器中的bean可以分為5個范圍。所有范圍的名稱都是自說明的,但是為了避免混淆,還是讓我們來解釋一下:
- singleton:這種bean范圍是默認的,這種范圍確保不管接受到多少個請求,每個容器中只有一個bean的實例,單例的模式由bean factory自身來維護。
- prototype:原形范圍與單例范圍相反,為每一個bean請求提供一個實例。
- request:在請求bean范圍內會每一個來自客戶端的網(wǎng)絡請求創(chuàng)建一個實例,在請求完成以后,bean會失效并被垃圾回收器回收。
- Session:與請求范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。
- 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注入“屬性”和構造方法注入“構造參數(shù)”的方式來實現(xiàn)。
比如,在我們的應用程序中,一個Customer類引用了一個Person類,我們的要做的是創(chuàng)建一個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.mon.Customer" >
< property name = "person" >
<!-- This is inner bean -->
< bean class = "com.mon.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的線程安全和并發(fā)問題需要開發(fā)者自行去搞定。但實際上,大部分的Spring bean并沒有可變的狀態(tài)(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態(tài)的話(比如 View Model 對象),就需要自行保證線程安全。
最淺顯的解決辦法就是將多態(tài)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" >admin@nospam.com</ prop >
< prop key = "support" >support@nospam.com</ 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.mon.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文件中創(chuàng)建出一個propertiesbean,然后利用setter方法注入bean的引用。
16、請解釋Spring Bean的自動裝配?
在Spring框架中,在配置文件中設定bean的依賴關系是一個很好的機制,Spring容器還可以自動裝配合作關系bean之間的關聯(lián)關系。這意味著Spring可以通過向Bean Factory中注入的方式自動搞定bean之間的依賴關系。自動裝配可以設置在每個bean上,也可以設定在特定的bean上。
下面的XML配置文件表明了如何根據(jù)名稱將一個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、請解釋自動裝配模式的區(qū)別?
在Spring框架中共有5種自動裝配,讓我們逐一分析。
- no:這是Spring框架的默認設置,在該設置下自動裝配是關閉的,開發(fā)者需要自行在bean定義中用標簽明確的設置依賴關系。
- byName:該選項可以根據(jù)bean名稱設置依賴關系。當向一個bean中自動裝配一個屬性時,容器將根據(jù)bean的名稱自動在在配置文件中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
- byType:該選項可以根據(jù)bean類型設置依賴關系。當向一個bean中自動裝配一個屬性時,容器將根據(jù)bean的類型自動在在配置文件中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
- constructor:造器的自動裝配和byType模式類似,但是僅僅適用于與有構造器相同參數(shù)的bean,如果在容器中沒有找到與構造器參數(shù)類型一致的bean,那么將會拋出異常。
- autodetect:該模式自動探測使用構造器自動裝配或者byType自動裝配。首先,首先會嘗試找合適的帶參數(shù)的構造器,如果找到的話就是用構造器自動裝配,如果在bean內部沒有找到相應的構造器或者是無參構造器,容器就會自動選擇byTpe的自動裝配方式。
18、如何開啟基于注解的自動裝配?
要使用 @Autowired ,需要注冊 AutowiredAnnotationBeanPostProcessor ,可以有以下兩種方式來實現(xiàn):
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注解?
在產(chǎn)品級別的應用中,IoC容器可能聲明了數(shù)十萬了bean,bean與bean之間有著復雜的依賴關系。設值注解方法的短板之一就是驗證所有的屬性是否被注解是一項十分困難的操作??梢酝ㄟ^在<bean>中設置“dependency-check”來解決這個問題。
在應用程序的生命周期中,你可能不大愿意花時間在驗證所有bean的屬性是否按照上下文文件正確配置?;蛘吣銓幙沈炞C某個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注解對自動裝配何時何處被實現(xiàn)提供了更多細粒度的控制。@Autowired 注解可以像 @Required 注解、構造器一樣被用于在 bean 的設值方法上自動裝配 bean 的屬性,一個參數(shù)或者帶有任意名稱或帶有多個參數(shù)的方法。
比如,可以在設值方法上使用@Autowired 注解來替代配置文件中的 <property> 元素。當 Spring 容器在 setter 方法上找到 @Autowired 注解時,會嘗試用 byType 自動裝配。
當然我們也可以在構造方法上使用@Autowired 注解。帶有@Autowired 注解的構造方法意味著在創(chuàng)建一個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();
}
}
|
下面是沒有構造參數(shù)的配置方式:
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.mon.Customer" />
< bean id = "personA" class = "com.mon.Person" >
< property name = "name" value = "lokesh" />
</ bean >
< bean id = "personB" class = "com.mon.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.mon.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、構造方法注入和設值注入有什么區(qū)別?
請注意以下明顯的區(qū)別:
- 在設值注入方法支持大部分的依賴注入,如果我們僅需要注入int、string和long型的變量,我們不要用設值的方法注入。對于基本類型,如果我們沒有注入的話,可以為基本類型設置默認值。在構造方法注入不支持大部分的依賴注入,因為在調用構造方法中必須傳入正確的構造參數(shù),否則的話為報錯。
- 設值注入不會重寫構造方法的值。如果我們對同一個變量同時使用了構造方法注入又使用了設置方法注入的話,那么構造方法將不能覆蓋由設值方法注入的值。很明顯,因為構造方法盡在對象被創(chuàng)建時調用。
- 在使用設值注入時有可能還不能保證某種依賴是否已經(jīng)被注入,也就是說這時對象的依賴關系有可能是不完整的。而在另一種情況下,構造器注入則不允許生成依賴關系不完整的對象。
- 在設值注入時如果對象A和對象B互相依賴,在創(chuàng)建對象A時Spring會拋出s
ObjectCurrentlyInCreationException異常,因為在B對象被創(chuàng)建之前A對象是不能被創(chuàng)建的,反之亦然。所以Spring用設值注入的方法解決了循環(huán)依賴的問題,因對象的設值方法是在對象被創(chuàng)建之前被調用的。
23、Spring框架中有哪些不同類型的事件?
Spring的ApplicationContext 提供了支持事件和代碼中監(jiān)聽器的功能。
我們可以創(chuàng)建bean用來監(jiān)聽在ApplicationContext 中發(fā)布的事件。ApplicationEven t類和在ApplicationContext 接口 中處理的事件,如果一個bean實現(xiàn)了ApplicationListener 接口,當一個ApplicationEvent 被發(fā)布以后,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中標準的事件:
- 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發(fā)布。也可以在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發(fā)。
- 上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發(fā)該事件。
- 上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發(fā)該事件。
- 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發(fā)該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
- 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發(fā)該事件。
除了上面介紹的事件以外,還可以通過擴展ApplicationEvent 類來開發(fā)自定義的事件。
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" );
}
}
|
為了監(jiān)聽這個事件,還需要創(chuàng)建一個監(jiān)聽器:
1 2 3 4 5 6 7 | public class CustomEventListener implements ApplicationListener < CustomApplicationEvent >
{
@Override
public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
//handle event
}
}
|
之后通過applicationContext接口的publishEvent()方法來發(fā)布自定義事件。
1 2 | CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message" );
applicationContext.publishEvent(customEvent);
|
24、FileSystemResource和ClassPathResource有何區(qū)別?
在FileSystemResource 中需要給出spring-config.xml 文件在你項目中的相對路徑或者絕對路徑。在ClassPathResource 中spring會在ClassPath中自動搜尋配置文件,所以要把ClassPathResource 文件放在ClassPath下。
如果將spring-config.xml 保存在了src文件夾下的話,只需給出配置文件的名稱即可,因為src文件夾是默認。
簡而言之,ClassPathResource在環(huán)境變量中讀取配置文件,F(xiàn)ileSystemResource在配置文件中讀取配置文件。
25、Spring 框架中都用到了哪些設計模式?
Spring框架中使用到了大量的設計模式,下面列舉了比較有代表性的:
- 代理模式—在AOP和remoting中被用的比較多。
- 單例模式—在spring配置文件中定義的bean默認為單例模式。
- 模板方法—用來解決代碼重復的問題。比如. RestTemplate,
JmsTemplate , JpaTemplate。
- 前端控制器—Spring提供了
DispatcherServlet 來對請求進行分發(fā)。
- 視圖幫助(View Helper )—Spring提供了一系列的JSP標簽,高效宏來輔助將分散的代碼整合在視圖里。
- 依賴注入—貫穿于
BeanFactory / ApplicationContext 接口的核心理念。
- 工廠模式—BeanFactory用來創(chuàng)建對象的實例。
|