Spring簡介
Spring是一個開放源代碼的設計層面框架判帮,它解決的是業(yè)務邏輯層和其他各層的松耦合問題,因此它將面向接口的編程思想貫穿整個系統(tǒng)應用五鲫。Spring是于2003 年興起的一個輕量級的Java 開發(fā)框架河绽,由Rod Johnson創(chuàng)建。簡單來說塞淹,Spring是一個分層的JavaSE/EE full-stack(一棧式) 輕量級開源框架。
- J2EE三層架構體系
-> 表現層
-> 業(yè)務層
-> 持久層
VIEW: Struts罪裹,Spring MVC
Service: 業(yè)務處理饱普,功能邏輯,事物控制 IOC ,AOP
DAO: Mybatis坊谁,JBDC ,Hibernate
- 一站式
Spring提供了JavaEE各層的解決方案费彼,
表現層:Spring MVC。
持久層:JdbcTemplate口芍、ORM框架整合箍铲。
業(yè)務層:IOC、AOP鬓椭、事務控制颠猴。
輕量級
Spring的出現取代了EJB的臃腫、低效小染、繁瑣復雜翘瓮、脫離現實。Spring體系架構
IOC
- IOC介紹
IOC其是一種設計思想裤翩,將創(chuàng)建對象的權利交給Spring资盅,由IOC統(tǒng)一加載和管理,讓Spring去管理對象生命周期踊赠,極大的解決了程序耦合性高的問題呵扛。
- IOC思想前瞻
IOC的思想最核心的地方在于,資源不由使用資源的雙方管理筐带,而由不使用資源的第三方管理今穿,這可以帶來很多好處。
第一伦籍,資源集中管理蓝晒,實現資源的可配置和易管理。
第二帖鸦,降低了使用資源雙方的依賴程度芝薇,也就是我們說的耦合度。比如說甲方要達成某種目的不需要直接依賴乙方作儿,它只需要達到的目的告訴第三方機構就可以了剩燥。
- Spring IOC容器
Spring IOC容器有兩種BeanFactory和ApplicationContext,BeanFactory 是 Spring 框架的基礎設施,面向 Spring 本身灭红。ApplicationContext 面向使用 Spring 框架的開發(fā)者,幾乎所有的應用場合我們都直接使用 ApplicationContext 而非底層的 BeanFactory口注。
- BeanFactory
BeanFactory 接口位于類結構樹的頂端 变擒,IOC容器所設定的最基本功能規(guī)范。它最主要的方法就是 getBean(String beanName)寝志,該方法從容器中返回特定名稱的 Bean娇斑。
BeanFactory的三個子接口:
?* HierarchicalBeanFactory:提供父容器的訪問功能
?* ListableBeanFactory:提供了批量獲取Bean的方法
?* AutowireCapableBeanFactory:在BeanFactory基礎上實現對已存在實例的管
解析
public interface BeanFactory {
/**
* 獲取產生對象的FactoryBean
* 如:myObject是一個FactoryBean,使用&myObject得到的是FactoryBean
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 獲取IoC容器中管理的bean
* @param name
* @return
* @throws BeansException
*/
Object getBean(String name) throws BeansException;
/**
* 判斷容器是否含有指定名稱的bean
* @param name
* @return
*/
boolean containsBean(String name);
/**
* 檢查指定名稱的bean是否是單例(可以在BeanDefinition中指定)
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 檢查指定名稱的bean是否是prototype類型(可以在BeanDefinition中指定)
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 檢查指定名稱的bean的Class類型是否是特定Class類型
* @param name
* @param targetType 用戶指定
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
/**
* 查詢指定名稱bean的Class類型
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 查詢指定名稱bean的所有別名(用戶在BeanDefinition中指定的)
* @param name
* @return
*/
String[] getAliases(String name);
}
- ApplicationContext
ApplicationContext app = new ClassPathXmlApplicationContext(" .xml");
類名 對象名 =(類名)app.getBean(" ");
解析
從 ApplicationContext 的繼承機構可以看到材部, ApplicationContext 繼承了BeanFactory毫缆,也就是說,ApplicationContext 擁有BeanFactory的全部功能乐导,ApplicationContext 是通過將容器的功能委派給DefaultListableBeanFactory來實現苦丁。除了繼承BeanFactory,還有ResourceLoader物臂、EnvironmentCapable旺拉、ApplicationEventPublisher、MessageSource等接口棵磷,也就說明ApplicationContext 除了容器的功能外蛾狗,還囊括了資源的處理、環(huán)境仪媒、事件發(fā)布沉桌、國際化等。
- 示列
1:xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 若沒寫id算吩,則默認為com.test.Man#0,#0為一個計數形式 -->
<bean id="man" class="com.test.Man"></bean>
</beans>
public class Test {
public static void main(String[] args) {
//加載項目中的spring配置文件到容器
//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");
//加載系統(tǒng)盤中的配置文件到容器
ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");
//從容器中獲取對象實例
Man man = context.getBean(Man.class);
man.driveCar();
}
}
DI(依賴注入)
- DI概念前瞻
IOC重點是如何在系統(tǒng)運行中動態(tài)向某個對象提供它所需要的其他對象留凭。這一點是通過DI(Dependency Injection,依賴注入)來實現的赌莺。比如對象A需要操作數據庫冰抢,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有了 Spring我們就只需要告訴Spring艘狭,A中需要一個Connection挎扰,至于這個Connection怎么構造,何時構造巢音,A不需要知道遵倦。在系統(tǒng)運行時,Spring會在適當的時候制造一個Connection官撼,然后像打針一樣梧躺,注射到A當中,這樣就完成了對各個對象之間關系的控制。A需要依賴 Connection才能正常運行掠哥,而這個Connection是由 Spring注入到A中的巩踏,依賴注入的名字就這么來的。那么DI是如何實現的呢续搀? Java 1.3之后一個重要特征是反射(reflection)塞琼,它允許程序在運行的時候動態(tài)的生成對象、執(zhí)行對象的方法禁舷、改變對象的屬性彪杉,Spring就是通過反射來實現注入的。
- DI關鍵點牵咙!
理解DI的關鍵是:依賴派近,為什么需要依賴,誰注入誰洁桌,注入了什么渴丸,應用程序依賴于IOC容器,為什么需要依賴:應用程序需要IoC容器來提供對象需要的外部資源比如對數據庫操作的對象战坤,IOC容器注入這個曙强,應用程序依賴這個對象,IOC和DI有什么關系呢途茫?其實它們是同一個概念的不同角度描述碟嘴,由于控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系)囊卜,所以2004年大師級人物Martin Fowler又給出了一個新的名字:依賴注入娜扇,相對IOC 而言,依賴注入明確描述了被注入對象依賴IoC容器配置依賴對象栅组!
- Spring裝配bean有三種方式
構造器注入
使用setter方法注入 [推薦]
接口注入
- 基于注解的方式
@Component:可以用于注冊所有bean
@Repository:主要用于注冊dao層的bean
@Controller: 主要用于注冊控制層的bean
@Service: 主要用于注冊服務層的bean
@Resource:java的注解雀瓢,默認以byName的方式去匹配與屬性名相同的bean的id,如果沒有找到就會以byType的方式查找玉掸,如果byType查找到多個的話刃麸,使用@Qualifier注解(spring注解)指定某個具體名稱的bean。
@Autowired:spring注解司浪,默認也是以byName的方式去匹配與屬性名相
同的bean的id泊业,如果沒有找到,就通過byType的方式去查找啊易,如果查找到多個吁伺,用@Qualifier注解限定具體使用哪個。
@Autowired
private IUserDao userDao;
但是如果IUserDao有多個實現類則需要:
@Autowired
@Qualifier("指定具體實現")
private IUserDao userDao;
AOP
AOP概念點
在軟件業(yè)租谈,AOP為Aspect Oriented Programming的縮寫篮奄,意為:[面向切面編程],通過預編譯方式和運行期動態(tài)代理實現程序功能的統(tǒng)一維護的一種技術。AOP是OOP的延續(xù)窟却,是軟件開發(fā)中的一個熱點昼丑,也是Spring框架中的一個重要內容,使函數式編程降低夸赫,提高程序的可重用性矾克,同時提高了開發(fā)的效率。
流程圖描述
- spring術語講解
1憔足、切面:攔截器類,其中會定義切點以及通知
2酒繁、通知:切面當中的方法滓彰,包括:
前置通知:在動態(tài)代理反射原先方法前調用的方法
后置通知:在動態(tài)代理反射完原有方法后調用的方法
返回通知:如果方法正常執(zhí)行,在調用完后置通知后州袒,就調用返回通知
異常通知:如果方法出現異常揭绑,在調用完后置通知后,就調用異常通知
環(huán)繞通知:可以決定是否調用目標方法郎哭,同時可以控制方法的返回
對象(這個通知具有一些細節(jié)他匪,接下來會進一步說明)
3、引入:往代理對象中添加新的方法夸研,但是新的方法不會被攔截
4邦蜜、切點:即定義需要攔截的方法的特征,可以通過正則表達式匹配亥至,也可以通過類的全限定名
5悼沈、連接點:需要攔截的方法
6、織入:生成代理對象并將切面內容嵌入流程中姐扮,將切面內容嵌入到流程中是什么意思呢絮供?例如現在定義了前置通知,那么代理對象在調用被代理對象的方法之前就會調用前置通知
- 示列
@Aspect
public class UserInterceptor {
@Pointcut("execution( * org.srm.practice.service.*.*(..))")
public void user() {
}
@Before("user()")
public void sayHello() {
System.out.println("前置");
}
@After("user()")
public void sayGoodbey() {
System.out.println("后置");
}
@Around("user()")
public void sayAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("環(huán)繞通知..環(huán)繞前");
pjp.proceed();//執(zhí)行方法
System.out.println("環(huán)繞通知..環(huán)繞后");
}
}
事物
Spring支持編程式事務管理和聲明式事務管理兩種方式茶敏。
- 編程式事務管理
編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager壤靶。對于編程式事務管理,Spring推薦使用TransactionTemplate惊搏。
- 聲明式事務管理建立在AOP之上的
聲明式事務管理建立在AOP之上的贮乳。其本質是對方法前后進行攔截,然后在目標方法開始之前創(chuàng)建或者加入一個事務胀屿,在執(zhí)行完目標方法之后根據執(zhí)行情況提交或者回滾事務塘揣。聲明式事務最大的優(yōu)點就是不需要通過編程的方式管理事務,這樣就不需要在業(yè)務邏輯代碼中摻雜事務管理的代碼宿崭,只需在配置文件中做相關的事務規(guī)則聲明(或通過基于@Transactional注解的方式)亲铡,便可以將事務規(guī)則應用到業(yè)務邏輯中
事務隔離級別
隔離級別是指若干個并發(fā)的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:
TransactionDefinition.ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別奖蔓。對大部分數據庫而言赞草,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據吆鹤。該級別不能防止臟讀厨疙,不可重復讀和幻讀,因此很少使用該隔離級別疑务。比如PostgreSQL實際上并沒有此級別沾凄。
TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀知允,這也是大多數情況下的推薦值撒蟀。
TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重復執(zhí)行某個查詢,并且每次返回的記錄都相同温鸽。該級別可以防止臟讀和不可重復讀保屯。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務依次逐個執(zhí)行,這樣事務之間就完全不可能產生干擾涤垫,也就是說姑尺,該級別可以防止臟讀、不可重復讀以及幻讀蝠猬。但是這將嚴重影響程序的性能切蟋。通常情況下也不會用到該級別。
事務傳播行為
所謂事務的傳播行為是指吱雏,如果在開始當前事務之前敦姻,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執(zhí)行行為歧杏。在TransactionDefinition定義中包括了如下幾個表示傳播行為的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務镰惦,則加入該事務;如果當前沒有事務犬绒,則創(chuàng)建一個新的事務旺入。這是默認值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個新的事務凯力,如果當前存在事務茵瘾,則把當前事務掛起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務咐鹤,則加入該事務拗秘;如果當前沒有事務,則以非事務的方式繼續(xù)運行祈惶。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行雕旨,如果當前存在事務扮匠,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行凡涩,如果當前存在事務棒搜,則拋出異常。
TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務活箕,則加入該事務力麸;如果當前沒有事務,則拋出異常育韩。
TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務克蚂,則創(chuàng)建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務筋讨,則該取值等價于TransactionDefinition.PROPAGATION_REQUIRED陨舱。
事務超時,所謂事務超時,就是指一個事務所允許執(zhí)行的最長時間版仔,如果超過該時間限制但事務還沒有完成,則自動回滾事務误墓。在 TransactionDefinition 中以 int 的值來表示超時時間蛮粮,其單位是秒。默認設置為底層事務系統(tǒng)的超時值谜慌,如果底層數據庫事務系統(tǒng)沒有設置超時值然想,那么就是none,沒有超時限制欣范。