Spring中通過注解配置(使用的范圍比較廣)
一: 首先我們需要在Spring容器中注冊(cè)組件掃描器,Spring會(huì)從ClassPath下自動(dòng)掃描,偵測(cè),實(shí)例化具有特定注解的組件,這些組件包括
@Component 基本注解,標(biāo)識(shí)了一個(gè)受Spring容器管理的組件
@Respository標(biāo)識(shí)的是持久層組件
@Service 標(biāo)識(shí)的是業(yè)務(wù)層(服務(wù)層)組件
@Controller 標(biāo)識(shí)的是表述層組件
對(duì)于掃描到的組件,Spring有其自己的默認(rèn)的命名策略,即使用的是用戶定義的類名(只不過是把類的是一個(gè)字母小寫)
如果用戶想自己想使用自定義的名稱,可以在注解中通過value屬性進(jìn)行修改(如果只有value屬性,可以省略)
二:僅有注解是不能夠使用的,我們需要在Spring容器中注冊(cè)組件掃描器,即<context:component-scan> base-package屬性是用來指定需要掃描的基類包,Spring容器會(huì)掃描這個(gè)基類包及其子類包中所有的類
如果我們需要掃描多個(gè)包時(shí),包名之間用逗號(hào)隔開即可.
resource-patten屬性用來掃描指定的類,而不是所有的類.
<context:include-filter>表示的是要包含的目標(biāo)類
<context:exclude-filter>表示的是要排除的目標(biāo)類
組件掃描器中可以包含多個(gè)這樣的子節(jié)點(diǎn).
我們的spring是有默認(rèn)的filter的,所以如果我們想要達(dá)到子節(jié)點(diǎn)的效果,需要關(guān)閉默認(rèn)的filter
即,
<context:component-scan base-package="com.atguigu.spring.beans"
use-default-filters="false">
</context:component-scan>
三:如何使用注解簡(jiǎn)歷Bean之間的關(guān)系
在<context:component-scan>掃描組件的同時(shí),還會(huì)自動(dòng)注冊(cè)AutowiredAnnotationBeanPostProcessor
的Bean后置處理器,該處理器會(huì)自動(dòng)裝載@Autowired,@Resource,@Inject注解的屬性.
也就是說,我們可以通過以上三種注解,建立Bean之間的關(guān)系
注意:@Autowired會(huì)自動(dòng)裝配具有兼容類型的單個(gè)的Bean屬性,可以放在構(gòu)造器,方法,方法的參數(shù)之前
默認(rèn)情況下,被@Autowired修飾的屬性都需要被設(shè)置,若某一個(gè)實(shí)行不需要被設(shè)置時(shí),可以把@Autowired
的required的屬性設(shè)置為false.
默認(rèn)情況下:當(dāng)Spring容器中含有多個(gè)相同類型的Bean(比如一個(gè)接口有多個(gè)實(shí)現(xiàn)類的時(shí)候),通過類型
的自動(dòng)裝配會(huì)報(bào)出不唯一Bean異常,我們可以通過在@Qualifier注解中提供bean名稱
該注解也能應(yīng)用在方法的參數(shù)中.通過類名稱指定裝配哪一個(gè)Bean
@Autowired也可以使用在List,集合,map中,其中會(huì)把Bean的名稱當(dāng)做鍵,bean本身當(dāng)做值裝配到map中.
四:Spring新特性:泛型依賴注入:
可以為子類注入子類對(duì)應(yīng)的泛型類型的成員變量的引用.父類中建立了引用關(guān)系,那么子類中也會(huì)建立
對(duì)應(yīng)的泛型關(guān)系,并且會(huì)把子類相應(yīng)的泛型類型的成員變量注入.
Spring-aop面向切面編程
1:我們使用面向切面編程的步驟如下:
1> 使用@Component把表示切面的類放入到Spring容器中
2> 使用@Aspect把類聲明成切面
3> 使用@Before("execution(目標(biāo)方法的簽名)")聲明切面中到底是哪種通知,以及其對(duì)應(yīng)的目標(biāo)方法
4> 在Spring 容器中使用<aop:axpectj-autoProxy></aop:aspectj-autoProxy>,他的作用,就是
當(dāng)容器找到了目標(biāo)類要增強(qiáng)目標(biāo)類時(shí),自動(dòng)的為目標(biāo)類創(chuàng)建代理對(duì)象.
2:如果我們想要了解織入的細(xì)節(jié),我們可以在通知中添加參數(shù)JoinPoint,通過JoinPoint我們可以
的到目標(biāo)方法的方法簽名,和目標(biāo)方法的參數(shù)
String name = JoinPoint.getSignature().getName();//目標(biāo)方法簽名
Lise<> args = Arrays.asList(JoinPoint.getArgs());//目標(biāo)方法參數(shù)
3:關(guān)于execution()中的表達(dá)式的總結(jié):
* com.abc.aynu.aopClass.(..)
第一個(gè)表示的是任意修飾符(public,private,等),任意返回值
第二個(gè)表示的是該包下的所有方法
(..)表示的是匹配任意數(shù)量的參數(shù)(目標(biāo)方法的形參我們都是不寫的)
如果接口及目標(biāo)類和切面是在同一個(gè)包下,我們還可以省略包, aopClass.*(..)
4:@After("execution()")后置通知,會(huì)在目標(biāo)方法返回結(jié)果之后,拋出異常之前執(zhí)行,
所以再后置通知中,無法訪問目標(biāo)方法的返回值.
5:@AfterReturning(value="execution()",returning="")
返回通知,可以訪問到目標(biāo)方法的返回值,通知中的形參和returning中的值保持一致,我們就可以在通知中
訪問到目標(biāo)方法的返回值
6:@AfterThrowing(value="execution()" throwing=""),異常通知,我們同樣可以通知中捕獲到異常信息
我們可以指定具體的異常進(jìn)行捕獲,不是該異常,那么異常通知就不會(huì)被執(zhí)行.
7:@Around環(huán)繞著目標(biāo)方法體執(zhí)行.環(huán)繞通知必須要攜帶ProceedingJoinPoint類型的參數(shù),該參數(shù)可以決定是否
執(zhí)行目標(biāo)方法,并且環(huán)繞通知必須要有返回值,即目標(biāo)方法的返回值.
例如:@Around("execution()")
public Object aroundMethod(ProceedingJoinPoint pjt){
String name = pjt.getSignature().getName();//目標(biāo)方法的簽名.
Object result = null;//目標(biāo)方法的返回值
... //前置通知
pjt.proceed();//執(zhí)行目標(biāo)方法
... //后置通知
return result;
}
8:切面的優(yōu)先級(jí)
當(dāng)有多個(gè)切面時(shí),切面的優(yōu)先級(jí)問題,我們可以是用@Order(數(shù)字),數(shù)字越小,優(yōu)先級(jí)越高,
指定切面的織入順序.
9:切入點(diǎn)表達(dá)式的復(fù)用
當(dāng)我們想重用切入點(diǎn)表達(dá)式的時(shí)候,我們可以這樣,利用@PointCut("execution()"):
@PointCut("execution()")
public void declarePointCutExpression(){}
然后我們就可以這樣使用了,@Before("declarePointCutExpression()"),如果引用的表達(dá)式
位于不同的包下,需要加上包名.
五:Spring的事務(wù)管理機(jī)制
1:首先我們需要在Spring的容器中注冊(cè)事務(wù)管理器
2:然后在容器中注冊(cè)事務(wù)注解驅(qū)動(dòng)
3:在我們需要的操作方法用@Transational,表示該方法的執(zhí)行是支持事務(wù)的
<!--注冊(cè)事務(wù)管理器-->
<bean id="transationManager" class="DataSourceTransationManager">
<property name="datasource" ref="dataSource"/>
</bean>
<!--注冊(cè)事務(wù)驅(qū)動(dòng)-->
<tx:annotation-drivern transation-managger="transationManager"/>
六:Spring中事務(wù)的傳播行為
當(dāng)一個(gè)事務(wù)方法A.被另外一個(gè)事務(wù)B調(diào)用的時(shí)候,我們必須要指明事務(wù)A的應(yīng)該怎么執(zhí)行,是
繼續(xù)在現(xiàn)有事務(wù)中執(zhí)行,還是開啟新的事務(wù),并在自己的事務(wù)中執(zhí)行呢?
事務(wù)的傳播行為可以用事務(wù)的傳播屬性指定,Spring中提供了7種傳播屬性.
常用的屬性是required和requires_news
Spring中默認(rèn)的默認(rèn)的事務(wù)屬性是required,它默認(rèn)的就是會(huì)在現(xiàn)有的事務(wù)中運(yùn)行..
required_news,也就是當(dāng)方法在A事務(wù)中執(zhí)行的過車高中遭遇了B事務(wù),
那么A事務(wù)會(huì)被掛起,然后會(huì)執(zhí)行B事務(wù),當(dāng)B事務(wù)執(zhí)行完畢的時(shí)候,繼續(xù)執(zhí)行A事務(wù)直至事務(wù)A結(jié)束.
@Transational(propagation=REQUIRED或者是REQIURES_NEWS)指定事務(wù)的屬性.
七:并發(fā)事務(wù)導(dǎo)致的問題
當(dāng)一個(gè)應(yīng)用程序,或者不同的應(yīng)用程序的多個(gè)事務(wù)在同一個(gè)數(shù)據(jù)集上并發(fā)執(zhí)行時(shí),可能會(huì)出現(xiàn)許多意外
并發(fā)會(huì)導(dǎo)致一下三種問題:
1> 臟讀:對(duì)于兩個(gè)事務(wù),T1,T2.若T1讀取了已經(jīng)被T2更新了但還提交的字段,如果T2執(zhí)行了回滾的操作
那么T1讀取的就是臨時(shí)的無效的數(shù)據(jù).
2> 不可重復(fù)讀:對(duì)于兩個(gè)事務(wù),T1,T2.T1讀取了一個(gè)字段,T2更新了該字段,如果T1再次讀取該字段,
讀取的值就會(huì)和之前的不同
3> 幻讀:對(duì)于兩個(gè)事務(wù),T1,T2.T1讀取了一個(gè)表中的一個(gè)字段,然后T2在表中插入了幾行記錄,如果T1
再次讀取同一張表,就會(huì)多讀出幾行.
解決方案:我們使用@Transational(isolation.READ_COMMMITED),我們使用isolation指定事務(wù)的
隔離級(jí)別,最常用的就是READ_COMMITED,讀已提交.Spring默認(rèn)的情況下,會(huì)對(duì)所有的運(yùn)行時(shí)異常
進(jìn)行回滾,通常情況下,我們?nèi)ツJ(rèn)值就行.
isolation的常用取值有四個(gè):
1> rollbackFor:通過類的類型指定執(zhí)行回滾
2> rollbackForClassName:通過類的全限定類名制動(dòng)具體的類執(zhí)行回滾
3> norollbackFor:通過類的類型指定執(zhí)行不回滾
4> norollbackForClassName:通過類的全限定類名制動(dòng)具體的類執(zhí)行不回滾
readOnly:取值為 true,false.設(shè)置為只讀級(jí)別.
timeout:取值為整數(shù),單位是秒.它表示的是你這個(gè)事務(wù)方法在強(qiáng)制回滾之前最多可以占用多長(zhǎng)時(shí)間
它可以防止一個(gè)事務(wù)對(duì)連接占用的時(shí)間過長(zhǎng).超過該時(shí)間,會(huì)強(qiáng)制進(jìn)行回滾.