Spring 框架概述
1.1. 什麼是Spring
Spring是分層的JavaSE/EE full-stack(一站式) 輕量級開源框架
分層: 來自JavaEE體系結構 (客戶端層、 web層、業務層、持久層 )
服務器端三層結構 (web層、業務層、持久層)
Servlet + JSP —- web層技術 —- Struts2框架
JDBC 接口 —- 持久化技術 —- Hibernate框架
EJB 框架(複雜) —- 業務層技術 —- Spring 框架 (取代EJB出現 )html
Spring 出現,就是爲了解決常見JavaEE 企業開發問題 !
一站式: Spring框架提供了 web層(表現層) SpringMVC、 業務層 IoC、AOP和事務管理、 持久層JdbcTemplate 各層javaEE軟件開發解決方案
輕量級:相對於EJB框架而言 java
Spring核心
IoC: 控制反轉
AOP: 面向切面編程
官網:http://www.springsource.org/web
Spring 給軟件開發帶來了什麼
方便解耦,簡化開發 (Spring IoC特性)
AOP編程的支持
聲明式事務的支持
方便程序的測試
方便集成各類優秀框架 (整合Struts2 、 Hibernate 、MyBatis 、Struts1 )
下降JavaEE API的使用難度 (Spring 提供大量工具類, 簡化代碼編寫 )spring
Spring 體系結構編程
Spring框架IoC和DI數組
下載開發包
http://projects.spring.io/spring-framework/ 網址下載開發包
最新版本4.1 課程 3.2 tomcat
開發包3.2
spring-framework-3.2.0.RELEASE-dist.zip
依賴吧 3.0 (常見開源技術jar包)
spring-framework-3.0.2.RELEASE-dependencies.zip服務器
Spring目錄結構session
Docs 文檔目錄(API 和 規範) Libs 開發須要jar包(包含javadoc和source) Schema 全部約束文檔
導入jar包到項目
進行Ioc和DI的開發,只須要導入最核心spring的jar包
app
Spring運行,使用commons-logging日誌技術
(commons-logging 和 slf4j 都屬於統一日誌接口, 整合log4j日誌實現 )
導入log4j jar
理解IoC和DI的概念
什麼是IoC ? 什麼是DI ? 區別是什麼?
IoC: 控制反轉, 解決程序對象緊密耦合問題(工廠+反射+ 配置文件), 將程序中原來構造對象的權限,交給IoC容器來構造,當程序須要對象,找IoC容器獲取。
DI : 依賴注入 , IoC容器須要爲程序提供依賴對象,返回對象所依賴對象一同能夠提供(Servlet須要Service, 找Ioc容器獲取Service, Service由容器提供,Service依賴DAO ,IoC容器提供Service對象同時, 將Service依賴DAO 注入到Service中)
編寫IoC和DI入門案例
將全部對象,交給IoC容器(Spring)來管理
(spring配置文件 一般能夠在src 或者 WEB-INF目錄下, 一般名稱 applicationContext.xml )
參考文檔 : xsd-config.html
經過applicationContext.xml 配置Spring管理對象
在程序中經過ApplicationContext接口 獲取spring工廠對象
1.ClassPathXmlApplicationContext 讀取 src下配置文件
2.FileSystemXmlApplicationContext 讀取WEB-INF下配置文件
IoC 經過工廠,從Spring容器獲取建立好對象
@Test public void testRegist2() { // 從Ioc容器得到對象 // 一、 獲取Ioc容器工廠對象 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); // 二、 從Ioc容器工廠 獲取須要對象 (根據bean的id 獲取) UserServlet userServlet = (UserServlet) applicationContext.getBean("userServlet"); userServlet.regist(); }
DI 在經過工廠獲取,spring對象時,spring同時提供對象所依賴的對象
// 依賴注入 (Spring 在構造 UserServlet對象時,同時將構造好 UserService對象,注入到UserServlet對象中 ) private UserService userService; public void setUserService(UserService userService) { this.userService = userService; }
配置
<!-- 將對象的建立權,交給容器管理 --> <bean id="userServlet" class="cn.itcast.spring.a_quickstart.UserServlet" > <!-- 返回UserServlet時,同時提供 依賴的UserService對象 --> <!-- name 屬性 對應 對象中 setXXX 方法, 表明對象中含有某個屬性 ref 引用了另外一個Bean對象id --> <property name="userService" ref="userService" /> </bean> <bean id="userService" class="cn.itcast.spring.a_quickstart.UserServiceImpl"/> <bean id="userDAO" class="cn.itcast.spring.a_quickstart.UserDAOImpl" />
BeanFactory 和 ApplicationContext 接口
ApplicationContext 是 BeanFactory 子接口,BeanFactory 纔是Spring框架最核心工廠接口。
ApplicationContext 是對BeanFactory 接口擴展, 企業開發不多直接使用BeanFactory
ApplicationContext 會在容器初始化時,對其中管理Bean對象進行建立, BeanFactory 會在對象獲取時才進行初始化 。
IoC容器裝配Bean(xml配置)
3.1.三種實例化Bean的方式
方式一: 使用類構造器實例化對象
<!-- 方式一 使用構造器(無參數)實例化對象 --> <bean id="bean1" class="cn.itcast.spring.b_instance.Bean1" />
方式二: 使用靜態工廠 靜態方法,對對象實例化
<!-- 方式二 使用靜態工廠實例化對象 --> <!-- 調用 工廠的 factory-method 返回對象 --> <bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2" />
方式三: 使用實例工廠 實例方法 對對象實例化
<!-- 方式三 使用實例工廠實例化對象 --> <!-- 先實例化工廠 --> <bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory" /> <!-- 再經過工廠對象的實例方法,構造目標對象 --> <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3" />
應用場景: 大多數狀況,能夠經過構造器直接實例化, 只有在對象構造過程很是複雜的狀況下,纔會採用工廠實例化的方式
Bean的做用域
最經常使用 singleton 和 prototype 兩種
Singleton (單例): 在一個BeanFactory對象中,引用惟一的一個目標實例
Prototype (多例): 每次經過工廠執行getBean時,返回不一樣實例對象
Request (請求範圍) : 建立對象保存在request範圍,若是request銷燬,對象銷燬
Session (會話範圍): 建立對象保存Session中, 若是session銷燬,對象銷燬
* globalSession (全局會話 ) :分佈式系統,全局會話的概念, 一次登陸,應用多個系統
<!-- 第三部分 Bean的做用域 --> <!-- 經過scope屬性,指定bean做用域 (默認做用域 singleton) --> <bean id="singletonBean" class="cn.itcast.spring.c_scope.SingletonBean" /><!-- 單例 --> <bean id="prototypeBean" class="cn.itcast.spring.c_scope.PrototypeBean" scope="prototype"/> <!-- 多例 -->
單例Bean 在容器初始化時,實例化 (只實例化一次 )
多例Bean 在工程執行getBean時 纔會實例化 (每調用一次,返回不一樣對象 )
Bean的生命週期
能夠經過 init-method屬性配置 Bean對象初始化執行方法,destory-method屬性配置Bean對象銷燬的方法
(初始化方法和構造方法 有區別? 構造方法做用申請空間,爲對象基本屬性初始化 , 初始化方法 對象複雜構造過程 , java語言建議將對象複雜構造過程單獨抽取 初始化方法 )
public class LifeCycleBean implements IHello { public LifeCycleBean() { System.out.println("LifeCycleBean 構造..."); } public void setup() { System.out.println("LifeCycleBean 初始化..."); } public void teardown() { System.out.println("LifeCycleBean 銷燬..."); } @Override public void sayHello() { System.out.println("hello ,itcast..."); } }
配置
<!-- 第四部分 bean的生命週期 --> <bean id="lifeCycleBean" class="cn.itcast.spring.d_lifecycle.LifeCycleBean" init-method="setup" destroy-method="teardown" />
在對象構造後,當即執行初始化init , 默認沒有執行destroy 銷燬方法
public class LifeCycleTest { @Test public void testInitDestroy() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); IHello lifeCycleBean = (IHello) applicationContext.getBean("lifeCycleBean"); System.out.println(lifeCycleBean); lifeCycleBean.sayHello(); // 必須手動調用 容器銷燬的方法 --- web服務器tomcat,自動調用容器銷燬 applicationContext.close(); } }
後處理器(後處理Bean)— 補充
在Spring構造Bean對象過程當中,有一個環節對Bean對象進行 後處理操做 (鉤子函數) —– Spring 提供 BeanPostProcessor 接口
能夠自定義類,實現 BeanPostProcessor 接口,配置到Spring容器中,在構造對象時,spring容器會調用接口中方法
後處理器,在對象構造過程當中,提供代理, 是AOP自動代理核心 !
public class MyBeanPostProcessor implements BeanPostProcessor { @Override /** * bean 表明Spring容器建立對象 * beanName 表明配置對象對應 id屬性 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { System.out.println("後處理器 初始化後執行..."); } return bean; } @Override public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { // 針對bean id 爲 lifeCycleBean的對象 進行代理 if (beanName.equals("lifeCycleBean")) { System.out.println("後處理器 初始化前執行..."); return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("執行代理....."); return method.invoke(bean, args); } }); } return bean; } }
Bean的依賴注入
三種注入方式
構造參數的屬性輸入
public class Car { private String name; private double price; // 爲Car類 提供構造方法 public Car(String name, double price) { super(); this.name = name; this.price = price; }
經過constructor-arg 屬性進行構造參數注入
<!-- 構造方法屬性注入 --> <bean id="car" class="cn.itcast.spring.e_di.Car"> <!-- 經過constructor-arg 注入構造函數的參數 --> <!-- index 表明參數順序 ,第一個參數 0 type 表明參數類型 name 表明參數的名稱 value 注入參數的值 ref 引用另外一個bean元素的id --> <constructor-arg index="0" type="java.lang.String" value="寶馬"/> <constructor-arg index="1" type="double" value="1000000"/> </bean>
setter方法屬性注入
public class Employee { private int id; private String name; private Car car;// 複雜元素 public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setCar(Car car) { this.car = car; }
在配置文件 使用 元素完成setter屬性注入
<!-- setter方法屬性注入 --> <bean id="employee" class="cn.itcast.spring.e_di.Employee" > <!-- 經過property 注入setter方法屬性 (屬性名稱, 由setter方法推理得到)--> <!-- name 屬性名稱 (由setter方法得到) value 注入參數的值 ref 引用另外一個Bean元素的id --> <property name="id" value="100001" /> <property name="name" value="張三" /> <!-- 注入複雜對象 --> <property name="car" ref="car" /> </bean>
屬性注入深刻
【知識點】 p名稱空間的使用
P名稱空間,在spring2.5版本後引入,爲了簡化屬性依賴注入(setter方法)
第一步: 在配置文件,引入p名稱空間
xmlns:p="http://www.springframework.org/schema/p"
第二步: 簡化setter方法注入配置
<!-- 使用p命名空間注入 --> <bean id="employee2" class="cn.itcast.spring.e_di.Employee" p:eid="100002" p:name="李四" p:car-ref="car"/>
【知識點】 spEL表達式的使用
在spring3.0以後,引入spEL 表達式語言,簡化屬性注入
參考 「Spring_表達式語言.pdf」 學習
語法: #{表達式}
用法一: 直接經過value注入,引用一個Bean對象
用法二: 引用一個Bean對象屬性
用法三: 直接調用對象的方法
public class ValueBean { private int id = 10003; private String name = "jor"; public int getId() { return id; } public String pickName() { return name; } }
<!-- spEL使用 --> <bean id="valueBean" class="cn.itcast.spring.e_di.ValueBean" /> <bean id="employee3" class="cn.itcast.spring.e_di.Employee" > <!-- 調用valueBean的getId --> <property name="eid" value="#{valueBean.id}" /> <!-- 直接調用對象的方法 --> <property name="name" value="#{valueBean.pickName().toUpperCase()}" /> <!-- #{car} 效果相似 ref --> <property name="car" value="#{car}" /> </bean>
集合元素類型屬性注入
Spring爲每種集合都提供一個元素標籤 進行注入
public class CollectionBean { private List<String> list; private Set<Integer> set; private Map<String, Integer> map; private Properties properties; public void setList(List<String> list) { this.list = list; } public void setSet(Set<Integer> set) { this.set = set; } public void setMap(Map<String, Integer> map) { this.map = map; } public void setProperties(Properties properties) { this.properties = properties; }
<!-- 集合類型屬性注入 --> <bean id="collectionBean" class="cn.itcast.spring.e_di.CollectionBean"> <!-- array 注入數組 list 注入List集合 set 注入Set集合 map 注入Map集合 props 注入 Properties 集合 --> <property name="list"> <list> <!-- value 注入基本數據類型, String 類型 ref 注入引用Bean的id --> <value>aaa</value> <value>bbb</value> <value>ccc</value> </list> </property> <property name="set"> <set> <value>10</value> <value>10</value> <value>20</value> </set> </property> <property name="map"> <map> <!-- map中每一個元素都是鍵值對 --> <entry key="abc" value="10"></entry> <entry key="def" value="20"></entry> </map> </property> <property name="properties"> <props> <prop key="qwe123">asd456</prop> <prop key="tyu567">hjk789</prop> </props> </property> </bean>