開源框架基礎——Spring

spring概述

spring是JavaEE/SE的輕量級組件,總的來說它解決了IBM提供的EJB重量級組件的問題。spring提供了表現層、持久層、切面編程(AOP)、控制反轉(Ioc)、spring的測試這五個大板塊。利用spring框架我們可以很好的解決JavaEE開發問題。

反轉控制(Ioc)

一、引入
通過原始的Java的JDBC數據庫編程中註冊驅動以驅動對象註冊時,會違反編程的一個原則:編譯不依賴,運行依賴。
解決方案一:以反射創建驅動對象,但仍然有問題,就是驅動類名硬編碼到程序中了。
解決方案二:還是以反射創建對象,但要把被創建的對象全類名配置到配置文件裏,以工廠模式來解決,但這種方式還是有不完美的,就是每次以工廠的方法獲取對象時,對於同一個類,獲得的對象都是不同的,即是線程安全的對象也會創建成多例。
解決方案三:以工廠模式創建,同時在工廠里加入一個容器(Map)來存放當加載完配置文件後就創建成功的對象。之後程序員就通過工廠提供的方法,以bean對象在容器裏的Key來取對應的對象。
通過上面的問題背景和解決方案的我們已經說完了SpringIoc的核心思想,即springIOC會提供容器(Map)來幫助我們創建和管理這些bean對象,同時也允許我們引用這些bean(即DI依賴注入),而我們要做的就是在spring配置文件裏配置好我們創建的對象的“全類名”和“在容器裏的key”。
二、入門
springIoc的XML配置方式

<bean id="" class=""/>

該標籤用於創建對象其中id表示對象存放到容器裏的key,class就是對象所屬的類全名
創建對象的兩種方式:
1、beanFactory:以這個容器來獲取spring容器時,它會延遲加載即用到對象時才創建該對象。
2、ApplicationContext:創建對象時會加載完配置文件就創建
創建對象的三種方式
1、無參構造函數

<bean id="" class=""/>

2、靜態工廠的方法
注意靜態工廠就是它裏面的方法是靜態的,所以在配置bean時要加上factory-method=""屬性來引用靜態工廠的方法
複製代碼

<bean id="" factory-method="staticFactoryCreateBean" class=""/>

3、實例工廠的方法
*實例工廠的方法不是靜態的,所以要先配置實例工廠的bean再在要引用實例工廠方法的bean上加上factory-class、factory-method

<bean id="instanceFactory" class="">
<bean id="" factory-class=instanceFactory" factory-method=""/>

4、springIoc入門程序
配置好配置文件後,只要獲取管理這些bean的容器即可調用這些容器裏bean的方法。而獲取spring容器和獲取容器裏bean的代碼如下:

ApplicationContext application = new ClassPactXmlApplicationContext("bean.xml");

UserService userService=application.getBean("userSerivice");

userService.xxx//調用userService對象的方法

5、springIoc的註解配置
創建對象的註解
@Component(value="")
@Service
@Repository
複製代碼其中value不寫時是類的短名和首字母小寫,這三個註解效果都差不多,都可以創建對象,可以互換,但還是按使用場景使用。
springIoc的DI依賴注入
1、XML的注入方式:
有參構造函數:

<constructor-arg type="" name="" value/ref=""/>

type:注入數據的類型
name:注入數據的名字
ref:引用其他bean類型數據
value:簡單數據類型和string類型
調用set方法

<property name="" value/ref=""/>

type:注入數據類型
name:注入數據名字
ref:引用其他bean類型
value:簡單數據類型和string類型

複雜數據類型的注入(集合)
list類型集合:

<property name="myList">
<array>
<value>AA</value>
</array>
</property>

代碼其中標籤array可以替換爲set或者list,用法都是一樣的
Map類型集合:

<property name="myMap">
<entry key="" value=""/>
</property>

<property name="myMap">
<props>
<prop key="">AA</prop>
<props>

以上的兩種寫法都可以替換

2、spring的註解注入
註解注入的常見註解

@Autowired
@Qualifier(value="")
@Resource(name="")
@Value(value="")

其中@Autowired是按類型注入,如果有多個相同的類型對象,那麼纔會按名字匹配;而@Qualifier是基於類型的按名字匹配,對於字段的注入時不能單獨使用,但和形參注入時可以單獨使用;@Resource是按名字注入;@Value是對簡單數據類型的注入,當然也可以從配置文件裏讀取信息。
配置類相關的註解

@Bean
複製代碼用於把方法的返回值保存到容器裏,默認以方法名作爲容器中該對象的key

@Configuaration
@ComponentScan(value={})
@Import(value={})
@PropertySource(value="classpath:xxx.properties")
@Configuration用於告知spring這個類是配置類,配置類等效於spring的配置文件
@ComponenetScan(value={})註解版的掃描包
@Import(value={})導入其他配置類,但不是把其他配置類加入容器中
@PropertySource()只能加載classpath下的.properties類型的文件

3、springIoc的純註解版
這時就要用配置類來替換spring的配置文件,並把以前在配置文件裏配置的信息全部換成註解和在配置類裏完成。

spring的切面編程(AOP)

概述

切面編程(AOP),其核心思想就是在不改變源碼的基礎上能動態的爲原對象增加功能;而實現這一功能的方式就是動態代理。
一、spring中動態代理方式
1、基於接口的動態代理
要求:被代理對象必須至少實現一個接口
提供方:JDK官方
涉及的類:Proxy
涉及的方法:newproxyInstance(ClassLoader,Class[],InvocationHandler)
參數解釋:
ClassLoader:類加載器,即指定加載動態代理類的加載器,一般默認就是用被代理對象的加載器
Class[] interfaces:即指定被代理對象實現的接口,一般用反射來獲取
InvocationHandler:一個接口,在這個接口裏一般以匿名內部類來實現,而這個接口裏的方法則是我們編寫如何增強被代理對象的實現。
2、基於子類的動態代理
要求:被代理類不能被final修飾
提供方:CGLIB
涉及類:Enhancer
涉及方法:create(ClassLoader,Callback)
參數解釋:
classLoader:同上
Callback:也是一個接口,我們使用子類,MethodInterceptor,而它子類裏的方法,interceptro(proxy,method,args,proxymethod),同樣也是我們編寫具體怎麼增強的方法
3、AOP的原理
其實爲什麼不用改源碼就可以增強方法?
其實,在生成的動態代理對象裏,它具有和被代理對象一樣的行爲,當程序員在調用代理對象裏和被代理對象的相同方法時,其實代理對象裏的方法去調用了interceptor和invoke,而interceptor方法裏又去調用真正的目標對象裏的這個方法,而我們可以在interceptor方法中對於在調用目標對象方法前後添加系統代碼實現增強目標代碼的功效。
4、AOP的應用
數據源(dbcp)中的連接對象的close()方法,這個close方法並沒有真正的關閉數據連接對象,而是把連接對象放到了數據源的緩存裏。
再比如web開發時業務層的方法要實現事務的支持,我們也可以用動態代理的實現,返回具體事務支持的service對象
5、AOP的XML配置
配置具體增強的類(通知)
配置aop
配置被增強的方法(切入點)和增強方法具體的增強細節

<bean id="txAdvice" class="xxxx"/>
<aop:config>
<aop:aspect id="logger" ref="txAdvice>
<aop:before pointcut="execution(* com..*.*(..))" method="">
<!--</aop:aspect>-->
</aop:config>

注意:切入點表達式配置在aspect裏時只能在這個切面裏使用該切入點表達式,但如果配置在aspect外面,那麼就可以在多個aspect中使用

<aop:config>
<aop:pointcut id="pt" expression="execution(* com..*.*(..)")/>
<aop:aspect id="" ref="txAdvice">
<aop:before emthod="" pointcut-ref="pt">
</aop:aspect>
</aop:config>

切入點表達式配置:
訪問修飾 返回值 包名.包名…類名.方法名(參數列表)
訪問修飾符可以不寫
放回值可以用表示任意類型
包名可以用.的方式來表示有多少個包或者com…來表示com包及其子包
類名可以用“
”替代任意類
參數如果是基本類型可以直接寫如果是引用類型那麼就要包名.類名;也可以*表示任意類型但必
須要有參數;還可以是…表示任意類型或者沒有參數
6、AOP的註解和XML配置
1、首先要加配置類@Configuration
2、其次掃描包@CompnentScan(value={})
3、配置切面@Aspect
4、在xml配置文件裏開啓切面註解配置

<aop:aspectj-autoproxy/>

7、對於配置類裏面的方法上可以使用

@Before
@AfterReturning
@AfterThrowing
@After
@Around

這幾個註解來表達這些方法分別屬於什麼類型的通知
8、在配置類里加上一個空參的方法在這個方法上配置切入點表達式

@PointCut("execution(* com..*.*(..)"))
public void pointcut(){}

之後再各通知方法上引入這個切入點即可

@Before("pointcut()")
public void log(){
    
}

9、AOP的純註解
其實就是把在配置文件里加入的開啓aop註解配置的開關標籤換成在配置類上加入一個註解來開啓aop的註解配置

@EnableAspectJAutoProxy

通知裏比較特殊的通知環繞通知
在以配置類配置環繞通知時要注意,環繞配置裏要用明確的目標方法調用,因此spring爲我們提供了一個參數接口ProceedingJoinPoint這個接口在運行時有spring來創建實現類,它的proceed()方法等效於interceptor方法,所以我們可以在環繞通知裏手動配置各種通知類型的具體方法

Public Object aroundPrint(ProceedJointPoint pjp){
Object retVal;
Try{
//前置通知
retVal = Pjp.proceed();
//後置通知
}catch(Throwable e){
//異常通知
}finally{
//最終通知
}

springJdbcTemplate

關鍵點:spring對於持久層的操作推出的是JdbcTemplate,而對於JdbcTemplate在Dao層的使用時最好Dao的實現類去實現一個JdbcDaoSupport的接口,實現後它可以方便在spring配置文件裏在對Dao層配置時簡化對JdbcTemplate的配置(即只配置數據源就可以配置好Dao中配置好JdbcTemplate了)
實戰:
獲取JdbcTemplate對象

JdbcTemplate jd = new JdbcTemplate(dataSource);
複製代碼直接new就可以了。但要操作數據庫時注意update是對更新、插入、去除語句操作的,query是對查詢操作的,而其中對於查詢結果映射爲對象時採用的是RowMapper這個接口。通常我們使用的是BeanPropertyRowMapper這個接口,它可以返回多行時的對象、單行時的對象。而對於單個值的映射,採用的是queryForObject()的方法,其中這個方法裏可以指定返回的數字的類型。
還有要注意的一點是springjdbcTemplate提供了一個內置的數據源即DataSourceManager,我們也可以使用它。

spring的事務管理

引入:spring中共提供了三個與事務有關的接口:PlatformTransactionManager(事務管理器的接口)、TransactionDefinition(事務屬性接口)、TransactionStatus(事務運行狀態接口)
PlatformTransactionManager:其實現類如果持久層採用的是mybatis那麼就用DataSourceTransactionManager,如果是Hibernate那麼就採用其他的事務管理器的配置,總之一句話就是spring會根據你持久層採用的是什麼框架來分別提供了對應的事務管理器的實現類。即事務管理器定義瞭如何提交、回滾等方法。

TransactionDefinition:

getName()獲取事務名稱
getIsolationLevel():獲取事務隔離狀態
getPropagationBehavior():獲取事務傳播行爲
getTimeout():獲取超時時間,默認爲-1,即不超時
isReadyOnly():事務是否是隻讀事務,一般查詢是隻讀事務
複製代碼對於事務的這些屬性,通常我們可以在配置文件裏配置通知的時候配置
TransactionStatus:

flush()
hasSavePoint()
isCompleted()
isNewTransaction()
isRollback()

這個接口裏的方法是返回事務運行時的狀態。
1、XML的事務配置

配置事務管理器
<bean id="transactionManager" class="xxx"/>
配置事務通知
<tx:advice id="txAdvice" transaction-Manager="transactionManager">
<tx:attribute>
<tx:method propagtion="REQUEIRED" isReadOnly="true" method="*">
</tx:attribute>
</tx:advice>
配置aop
<aop:config>
<aop:pointcut expression="execution(* com..*.*(..))" id="pt"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>

2、XML和註解版

配置事務管理器
<bean id="transactionManager" class="xxx"/>
開啓事務註解配置的開關
<tx:annotation-driven transaction-manager="transactionManager"/>
在業務層中在所需事務的方法上@Transaction註解,同時也可以在這個註解上配置事務的屬性
3、純註解版
這裏就僅提供思路了:
配置類
開啓事務註解配置@EnableTransactionManagement
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章