原文出處: 朱小廝css
Spring由7個模塊組成:前端
Sping的容器能夠分爲兩種類型
1. BeanFactory:(org.springframework.beans.factory.BeanFactory接口定義)是最簡答的容器,提供了基本的DI支持。最經常使用的BeanFactory實現就是XmlBeanFactory類,它根據XML文件中的定義加載beans,該容器從XML文件讀取配置元數據並用它去建立一個徹底配置的系統或應用。
2. ApplicationContext應用上下文:(org.springframework.context.ApplicationContext)基於BeanFactory之上構建,並提供面向應用的服務。java
1
|
ApplicationContext context =
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
|
Inversion of Control, 通常分爲兩種類型:依賴注入DI(Dependency Injection)和依賴查找(Dependency Lookup).依賴注入應用比較普遍。web
Spring IOC扶着建立對象,管理對象(DI),裝配對象,配置對象,而且管理這些對象的整個生命週期。spring
優勢:把應用的代碼量降到最低。容器測試,最小的代價和最小的侵入性使鬆散耦合得以實現。IOC容器支持加載服務時的餓漢式初始化和懶加載。
DI依賴注入是IOC的一個方面,是個一般的概念,它有多種解釋。這概念是說你不用牀架對象,而只須要描述它如何被建立。你不在代碼裏直接組裝你的組件和服務,可是要在配置文件裏描述組件須要哪些服務,以後一個IOC容器輔助把他們組裝起來。
IOC的注入方式:1. 構造器依賴注入;2. Setter方法注入。數據庫
id
name
class
init-method:Bean實例化後會馬上調用的方法
destory-method:Bean從容器移除和銷燬前,會調用的方法
factory-method:運行咱們調用一個指定的靜態方法,從而代替構造方法來建立一個類的實例。
scope:Bean的做用域,包括singleton(默認),prototype(每次調用都建立一個實例), request,session, global-session(注意spring中的單例bean不是線程安全的)
autowired:自動裝配 byName, byType, constructor, autodetect(首先闡釋使用constructor自動裝配,若是沒有發現與構造器相匹配的Bean時,Spring將嘗試使用byType自動裝配)apache
default-init-method
default-destory-method
default-autowire:默認爲none,應用於Spring配置文件中的全部Bean,注意這裏不是指Spring應用上下文,由於你能夠定義多個配置文件編程
1) 建立Bean的實例(factory-method, autowireConstrutor)
2) 屬性注入(autowireByName, autowireByType)
3) 初始化Bean
3.1 激活Aware方法:(invokeAwaresMethods)Spring中提供了一些Aware相關接口,好比BeanNameAware, BeanFactoryAware, ApplicationContextAware等,實現這些Aware接口的bean在被初始化以後,能夠取得一些相對應的資源。設計模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private
void
invokeAwareMethods(
final
String beanName,
final
Object bean){
if
(bean
instanceof
Aware)
{
if
(bean
instanceof
BeanNameAware){
((BeanNameAware) bean).setBeanName(beanName);
}
if
(bean
instanceof
BeanClassLoaderAware){
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if
(bean
instanceof
BeanFactoryAware){
((BeanFactoryAware) bean).setBeanFactory(AbstactAutowire CapableBeanFactory.
this
);
}
}
}
|
3.2 處理器的應用(BeanPostProcessor接口):調用客戶自定義初始化方法前以及調用自定義初始化方法後分別會調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用戶能夠根據本身的業務需求進行響應的處理。
3.3 激活自定義的init方法(init-method & 自定義實現InitializingBean接口)安全
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
|
protected
Object initializeBean(
final
String beanName,
final
Object bean, RootBeanDefinetion mbd){
if
(System.getSecurityManager() !=
null
){
AccessController.doPrivileged(
new
PrivilegedAction<Object>(){
@Override
public
Object run()
{
invokeAwareMethods(beanName,bean);
return
null
;
}
});
}
else
{
//對特殊的bean處理:Aware, BeanClassLoaderAware, BeanFactoryAware
invokeAwareMethods(beanName,bean);
}
Object wrappedBean = bean;
if
(mbd ==
null
!! !mbd.isSynthetic()){
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wappedBean,beanName);
}
try
{
invokeInitMethods(beanName, wappedBean, mbd);
}
catch
(Throwable ex){
throw
new
BeanCreationException((mbd !=
null
? mbd.getResourceDescription():
null
),beanName,
"Invocation of init method failed"
,ex);
}
if
(mbd ==
null
|| !mbd.isSynthetic()){
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return
wappedBean;
}
|
4) 使用Bean。 駐留在應用的上下文中,直到該應用上下文被銷燬。
5) 銷燬(destory-mthod & 實現DisposableBean接口)
Or represent like this:
1. Bean的構造
2. 調用setXXX()方法設置Bean的屬性
3. 調用BeanNameAware的setBeanName()
4. 調用BeanFactoryAware的setBeanFactory()方法
5. 調用BeanPostProcessor的postProcessBeforeInitialization()方法
6. 調用InitializingBean的afterPropertiesSet()方法
7. 調用自定義的初始化方法
8. 調用BeanPostProcessor類的postProcessAfterInitialization()方法
9. 調用DisposableBean的destroy()方法
10. 調用自定義的銷燬方法
1
|
<property name=
"xxx"
><
null
/></property>
|
有助於減小甚至消除配置<property>和<constructor-arg>元素,讓Spring自動識別如何裝配Bean的依賴關係。<context:annotation-config/>
與之對應的是:自動檢測(autodiscovery),比自動裝配更近了一步,讓Spring可以自動識別哪些類須要被配置成SpringBean,從而減小對<bean>元素的使用。<context:component-scan>
Spring容器默認禁用註解裝配。最簡單的開啓方式<context:annotation-config/>。
Spring支持的幾種不一樣的用於自動裝配的註解:
@Autowired具備強契約特徵,其所標註的屬性或參數必須是可裝配的。若是沒有Bean能夠裝配到@Autowired所標註的屬性或參數中,自動裝配就會失敗,拋出NoSuchBeanDefinitionException.
屬性不必定非要裝配,null值也是能夠接受的。在這種場景下能夠經過設置@Autowired的required屬性爲false來配置自動裝配是可選的,如:
1
2
|
@Autowired
(required=
false
)
private
Object obj;
|
注意required屬性能夠用於@Autowired註解所使用的任意地方。可是當使用構造器裝配時,只有一個構造器能夠將@Autowired的required屬性設置爲true。其餘使用@Autowired註解所標註的構造器只能將required屬性設置爲false。此外,當使用@Autowired標註多個構造器時,Spring就會從全部知足裝配條件的構造器中選擇入參最多的那個構造器。
可使用@Qualifier明確指定要裝配的Bean.以下:
1
2
3
|
@Autowired
@Qualifier
(
"objName"
)
private
Object obj;
|
1
2
3
4
|
@Target
({ElementType.FIELF, ElementType.PARAMETER, ElementType.TYPE})
@Retention
(RetentionPolicy.RUNTIME)
@Qualifier
public
@Interface
SpecialQualifier{}
|
此時,能夠經過自定義的@SpecialQualifier註解來代替@Qualifier來標註,也能夠和@Autowired一塊兒使用:
1
2
3
|
@Autowired
@SpecialQualifier
private
Object obj;
|
此時,Spring會把自動裝配的範圍縮小到被@SpecialQualifier標註的Bean中。若是被@SpecialQualifier標註的Bean有多個,咱們還能夠經過自定義的另外一個限定器@SpecialQualifier2來進一步縮小範圍。
Spring的@Autowired註解是減小Spring XML配置的一種方式。可是它的類會映入對Spring的特定依賴(即便依賴只是一個註解)。
和@Autowired註解同樣,@Inject能夠用來自動裝配屬性、方法和構造器;與@Autowired不一樣的是,@Inject沒有required屬性。所以@Inject註解所標註的依賴關係必須存在,若是不存在,則會拋出異常。
相對於@Autowired對應的Qualifier,@Inject所對應的是@Named註解。
1
2
3
|
@Inject
@Named
(
"objName"
)
private
Object obj;
|
語法形式在#{}中使用表達式,如:
1
|
<property name=
"count"
value=
"#{5}"
/>
|
@Value是一個新的裝配註解,可讓咱們使用註解裝配String類型的值和基本類型的值,如int, boolean。咱們能夠經過@Value直接標註某個屬性,方法或者方法參數,並傳入一個String類型的表達式來裝配屬性,如:
1
2
|
@Value
(
"Eruption"
)
private
String song;
|
@Value能夠配合SpEL表達式一塊兒使用,譬若有些狀況下須要讀取properties文件中的內容,可使用:
1
|
@Value
(
"#{configProperties['ora_driver']}"
)
|
詳細能夠參考Spring+Mybatis多數據源配置(三)——Spring如何獲取Properties文件的信息
<context:component-scan>元素除了完成與<context:annotation-config>同樣的工做,還容許Spring自動檢測Bean和定義Bean.<context:component-scan>元素會掃描指定的包和其全部子包,以下:
1
|
<context:component-scan base-
package
=
"com.zzh.dao"
/>
|
默認狀況下,查找使用構造型(stereotype)註解所標註的類,這些特殊的註解以下:
- @Component:通用的構造型註解,標誌此類爲Spring組件
- @Controller:標識將該類定義爲SpringMVC controller
- @Repository:標識將該類定義爲數據倉庫
- @Service:標識將該類定義爲服務
以@Component爲例:
1
2
|
@Component
public
class
Guitar
implements
Intrument{}
|
這裏@Component會自動註冊Guitar 爲Spring Bean,並設置默認的Bean的Id爲guitar,首字母大寫變小寫。注意若是第一個和第二個字母都是大寫,默認的Bean的id會有特殊處理。
也能夠指定Bean的Id如:
1
2
|
@Component
(
"guitarOne"
)
public
class
Guitar
implements
Intrument{}
|
面向切面的編程AOP,是一種編程技術,容許程序模塊化橫向切割關注點,或橫切典型的責任劃分,如日誌和事務管理。
AOP的核心是切面,它將多個類的通用行爲封裝成可重用的模塊,該模塊含有一組API提供橫切功能。好比,一個日誌模塊能夠被稱做日誌的AOP切面。根據需求的不一樣,一個應用程序能夠有若干切面。在SpringAOP中,切面經過帶有@Aspect註解的類實現。
關注點是應用中的一個模塊的行爲,一個關注點可能會被定義成一個咱們想實現的一個功能。
橫切關注點一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,好比日誌,安全和數據傳輸,幾乎應用的每一個模塊都須要的功能。所以這些都屬於橫切關注點。
鏈接點表明一個應用程序的某個位置,在這個位置咱們能夠插入一個AOP切面,它其實是個應用程序執行Spring AOP的位置。
切點是一個或一組鏈接點,通知將在這些位置執行。能夠經過表達式或匹配的方式指明切入點。
引入運行咱們在已存在的類中添加新的方法和屬性。
通知是個在方法執行先後要作的動做,其實是程序執行時要經過SpringAOP框架觸發的代碼
Spring切面能夠應用五種類型的通知:
before:前置通知,在一個方法執行前被調用。@Before
after: 在方法執行以後調用的通知,不管方法執行是否成功。@After
after-returning: 僅當方法成功完成後執行的通知。@AfterReturning
after-throwing: 在方法拋出異常退出時執行的通知。@AfterThrowing
around: 在方法執行以前和以後調用的通知。@Around
編程式事務管理:這意味你經過編程的方式管理事務,給你帶來極大的靈活性,可是難維護。
聲明式事務管理:這意味着你能夠將業務代碼和事務管理分離,你只需用註解和XML配置來管理事務。
若是在應用程序中直接使用JDBC來進行持久化,譬如博主採用的是Mybatis,DataSourceTransactionManager會爲你處理事務邊界。譬如:
1
2
3
4
5
6
7
8
9
10
11
|
<bean id=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method=
"close"
>
<property name=
"driverClassName"
value=
"${driver}"
/>
<property name=
"url"
value=
"${url}"
/>
<property name=
"username"
value=
"zzh"
/>
<property name=
"password"
value=
"zzh"
/>
<property name=
"validationQuery"
value=
"SELECT 1"
/>
</bean>
<bean id=
"transactionManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
<property name=
"dataSource"
ref=
"dataSource"
/>
</bean>
|
若是你的事務須要跨多個事務資源(例如:兩個或多個數據庫;或者如Sping+ActiveMQ整合須要將ActiveMQ和數據庫的事務整合起來),就須要使用JtaTransactionManager:
1
|
<bean id=
"jtaTransactionManager"
class
=
"org.springframework.transaction.jta.JtaTransactionManager"
/>
|
JtaTransactionManager將事務管理的職責委託給了一個JTA的實現。JTA規定了應用程序與一個或多個數據源之間協調事務的標準API。transactionManagerName屬性指明瞭要在JNDI上查找的JTA事務管理器。
JtaTransactionManager將事務管理的職責委託給javax.transaction.UserTransaction和javax.transaction.TransactionManager對象。經過UserTransaction.commit()方法來提交事務。相似地,若是事務失敗,UserTransaction的rollback()方法將會被調用。
儘管Spring提供了多種聲明式事務的機制,可是全部的方式都依賴這五個參數來控制如何管理事務策略。所以,若是要在Spring中聲明事務策略,就要理解這些參數。(@Transactional)
若是事務只進行讀取的動做,則能夠利用底層數據庫在只讀操做時發生的一些最佳化動做,因爲這個動做利用到數據庫在只讀的事務操做最佳化,於是必須在事務中才有效,也就是說要搭配傳播行爲PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED來設置。
有的事務操做可能延續很長一段的時間,事務自己可能關聯到數據表的鎖定,於是長時間的事務操做會有效率上的問題,對於過長的事務操做,考慮Roll back事務並要求從新操做,而不是無限時的等待事務完成。 能夠設置事務超時期間,計時是從事務開始時,因此這個設置必須搭配傳播行爲PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED來設置。
1
2
3
4
5
|
<tx:advice id=
"txAdvice"
transaction-manager=
"transactionManager"
>
<tx:attributes>
<tx:method name=
"*"
/>
</tx:attributes>
</tx:advice>
|
核心架構的具體流程:
SpringMVC的核心是DispatcherServlet,這個Servlet充當SpringMVC的前端控制器。與其餘Servlet同樣,DispatcherServlet必須在Web應用程序的web.xml文件中進行配置。
1
2
3
4
5
|
<servlet>
<servlet-name>viewspace</servlet-name>
<servlet-
class
>org.springframework.web.servlet.DispatcherServlet</servlet-
class
>
<load-on-startup>
2
</load-on-startup>
</servlet>
|
默認狀況下,DispatcherServlet在加載時會從一個基於這個Servlet名字的XML文件中加載Spring應用上下文。由於servlet的名字是viewspace,因此配置文件的名稱爲viewspace-servlet.xml。
接下來,必須申明DispatcherServlet處理那些URL:
1
2
3
4
|
<servlet-mapping>
<servlet-name>viewspace</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
|
經過將DispatcherServlet映射到/,聲明瞭它會做爲默認的servlet而且會處理全部的請求,包括對靜態資源的請求。
能夠配置:
1
2
3
4
5
6
|
<mvc:resources mapping=
"/images/**"
location=
"/images/"
cache-period=
"31556926"
/>
<mvc:resources mapping=
"/js/**"
location=
"/js/"
cache-period=
"31556926"
/>
<mvc:resources mapping=
"/css/**"
location=
"/css/"
cache-period=
"31556926"
/>
|
處理靜態資源。
Spring自帶了多個處理器映射實現:
1
2
3
4
|
<mvc:annotation-driven />
<bean id=
"defaultAnnotationHandlerMapping"
class
=
"org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
>
</bean>
|
在構建控制器的時候,咱們還須要使用註解將請求參數綁定到控制器的方法參數上進行校驗以及信息轉換。提供註解驅動的特性。
1
2
|
<bean id=
"annotationMethodHandlerAdapter"
class
=
"org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"
/>
|
在SpringMVC中大齡使用了約定優於配置的開發模式。InternalResourceViewResolver就是一個面向約定的元素。它將邏輯視圖名稱解析爲View對象,而該對象將渲染的任務委託給Web應用程序上下文中的一個模板。
1
2
3
4
5
6
7
8
|
<!-- 配置視圖解析器,將ModelAndView及字符串解析爲具體的頁面 -->
<bean
class
=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
>
<property name=
"viewClass"
value=
"org.springframework.web.servlet.view.JstlView"
/>
<property name=
"prefix"
value=
"/WEB-INF/jsp/"
/>
<property name=
"suffix"
value=
".jsp"
/>
</bean>
|