Spring概述及基于XML的IOC配置
- 1. spring概述
-
- 1.1 spring是什麼
- 1.2 spring的優勢
- 1.3 spring的體系結構
- 2. IoC的概念和作用
-
- 2.1 程式的耦合和解耦
- 2.2 工廠模式解耦
- 2.3 ioc的概念和作用
- 3. spring基于XML的IOC
-
- 3.1 實作
- 3.2 細節
-
- 3.2.1 spring中的工廠類的結構圖
- 3.2.2 BeanFactory和ApplicationContext的差別
- 3.2.3 ApplicationContext的三個實作類
- 4. IOC中的bean标簽
-
- 4.1 建立bean對象的三種方式
- 4.2 bean的作用範圍
- 4.3 bean的生命周期
- 5. spring的依賴注入
-
- 5.1 依賴注入的概念
- 5.2 構造函數注入
- 5.3 set 方法注入(常用)
- 5.4 注入集合資料
1. spring概述
1.1 spring是什麼
Spring是分層的 Java SE/EE應用 full-stack 輕量級開源架構,以==IoC(Inverse Of Control:反轉控制)==和 ==AOP(Aspect Oriented Programming:面向切面程式設計)==為核心,提供了展現層SpringMVC和持久層 Spring JDBC 以及業務層事務管理等衆多的企業級應用技術,還能整合開源世界衆多著名的第三方架構和類庫,逐漸成為使用最多的Java EE 企業應用開源架構。
1.2 spring的優勢
-
友善解耦,簡化開發
通過 Spring提供的IoC容器,可以将對象間的依賴關系交由 Spring進行控制,避免寫死所造成的過度程式耦合。使用者也不必再為單例模式類、屬性檔案解析等這些很底層的需求編寫代碼,可以更專注于上層的應用。
-
AOP 程式設計的支援
通過 Spring的 AOP 功能,友善進行面向切面的程式設計,許多不容易用傳統OOP 實作的功能可以通過 AOP 輕松應付。
-
聲明式事務的支援
可以将我們從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活的進行事務的管理,提高開發效率和品質。
-
友善程式的測試
可以用非容器依賴的程式設計方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是随手可做的事情。
-
友善內建各種優秀架構
Spring可以降低各種架構的使用難度,提供了對各種優秀架構(Struts、Hibernate、Hessian、Quartz等)的直接支援。
-
降低JavaEE API 的使用難度
Spring對JavaEE API(如 JDBC、JavaMail、遠端調用等)進行了薄薄的封裝層,使這些 API 的使用難度大為降低。
-
Java 源碼是經典學習範例
Spring的源代碼設計精妙、結構清晰、匠心獨用,處處展現着大師對Java 設計模式靈活運用以及對 Java技術的高深造詣。它的源代碼無意是 Java 技術的最佳實踐的範例。
1.3 spring的體系結構

2. IoC的概念和作用
2.1 程式的耦合和解耦
耦合:程式間的依賴關系,包括類之間的依賴和方法間的依賴。
解耦:降低程式間的依賴關系
實際開發中應該做到,編譯期不依賴,運作時才依賴。
解耦的思路:
第一步:使用反射來建立對象,而避免使用new關鍵字。
第二步:通過讀取配置檔案來擷取要建立的對象全限定類名
2.2 工廠模式解耦
建立持久層接口和實作類
public interface IAccountDao {
/**
* 模拟儲存帳戶
*/
void saveAccount();
}
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("儲存了帳戶");
}
}
建立業務層接口和實作類
public interface IAccountService {
/**
* 模拟儲存帳戶
*/
void saveAccount();
}
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
}
}
模拟表現層
public class Client {
public static void main(String[] args) {
IAccountService as = new AccountServiceImpl();
as.saveAccount();
}
}
建立BeanFactory類
一個建立Bean對象的工廠
Bean:在計算機英語中,有可重用元件的含義。
JavaBean:用java語言編寫的可重用元件。
javabean>=實體類
它就是建立我們的service和dao對象的。
第一個:需要一個配置檔案來配置我們的service和dao
配置的内容:唯一辨別=全限定類名(key=value)
第二個:通過讀取配置檔案中配置的内容,反射建立對象
我的配置檔案可以是xml也可以是properties
public class BeanFactory {
//定義一個Properties對象
private static Properties props;
//定義一個Map用于存放我們要建立的對象,稱為容器
private static Map<String,Object> beans;
//使用靜态代碼塊為Properties對象指派
static{
try {
//執行個體化對象
props = new Properties();
//擷取properties檔案的流對象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
//執行個體化容器
beans = new HashMap<String,Object>();
//取出配置檔案中所有的key
Enumeration keys = props.keys();
//周遊枚舉
while(keys.hasMoreElements()){
String key = keys.nextElement().toString();
//根據key擷取value
String beanPath = props.getProperty(key);
//反射建立對象
Object value = Class.forName(beanPath).newInstance();
//把keyvalue存入到容器
beans.put(key,value);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化properties失敗!");
}
}
/**
* 根據bean的名稱擷取bean對象
* @param beanName
* @return
*/
public static Object getBean(String beanName){
Object bean = null;
String beanPath = props.getProperty(beanName);
try {
bean = Class.forName(beanPath).newInstance();//每次都會調用預設構造函數建立對象
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
建立一個bean.properties
accountService=com.wyj.service.impl.AccountServiceImpl
accountDao=com.wyj.dao.impl.AccountDaoImpl
修改表現層、業務層
IAccountService as = (IAccountService)BeanFactory.getBean("accountService");
private IAccountDao accountDao = (IAccountDao)BeanFactory.getBean("accountDao");
2.3 ioc的概念和作用
3. spring基于XML的IOC
3.1 實作
- 建立持久層、業務層接口和實作類
- 導入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
- 建立bean.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">
<!--把對象的建立交給spring來管理-->
<bean id="accountService" class="com.wyj.service.impl.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.wyj.dao.impl.AccountDaoImpl"></bean>
</beans>
- 測試代碼
public static void main(String[] args) {
//1.擷取核心容器對象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\Desktop\\bean.xml")
//2.根據id擷取bean對象
IAccountService as = (IAccountService)ac.getBean("accountService");
IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);
System.out.println(as);
System.out.println(adao);
}
3.2 細節
3.2.1 spring中的工廠類的結構圖
3.2.2 BeanFactory和ApplicationContext的差別
BeanFactory才是 Spring 容器中的頂層接口。
ApplicationContext是它的子接口。
BeanFactory和ApplicationContext的差別
建立對象的時間點不一樣。
ApplicationContext:隻要一讀取配置檔案,預設情況下就會建立對象。
BeanFactory:什麼使用什麼時候建立對象。
3.2.3 ApplicationContext的三個實作類
==ClassPathXmlApplicationContext:==它可以加載類路徑下的配置檔案,要求配置檔案必須在類路徑下。不在的話,加載不了。(更常用)
==FileSystemXmlApplicationContext:==它可以加載磁盤任意路徑下的配置檔案(必須有通路權限)
==AnnotationConfigApplicationContext:==它是用于讀取注解建立容器的。
4. IOC中的bean标簽
4.1 建立bean對象的三種方式
-
使用預設構造函數建立
在spring的配置檔案中使用bean标簽,配以id和class屬性後且沒有其他屬性和标簽時, 采用的是預設構造函數建立bean對象,此時如果類中沒有預設構造函數,對象無法建立
-
使用工廠中的靜态方法建立對象(使用某個類中的靜态方法建立對象,并存入容器)
id 屬性:指定 bean 的 id,用于從容器中擷取
class 屬性:指定靜态工廠的全限定類名
factory-method 屬性:指定生産對象的靜态方法
public class StaticFactory {
public static IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
- 使用普通工廠中的方法建立對象(使用某個類總的方法建立對象,并存入容器)
先把工廠的建立交給 spring 來管理。
然後在使用工廠的 bean 來調用裡面的方法
factory-bean 屬性:用于指定執行個體工廠 bean 的 id。
factory-method 屬性:用于指定執行個體工廠中建立對象的方法。
<bean id="instanceFactory" class="com.wyj.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
public class InstanceFactory {
public IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
4.2 bean的作用範圍
bean作用:
用于配置對象讓 spring 來建立的。
預設情況下它調用的是類中的無參構造函數。如果沒有無參構造函數則不能建立成功。
屬性:
id:給對象在容器中提供一個唯一辨別。用于擷取對象。
class:指定類的全限定類名。用于反射建立對象。預設情況下調用無參構造函數。
scope:指定對象的作用範圍。
- singleton :預設值,單例的.
- prototype :多例的.
- request :WEB 項目中,Spring 建立一個 Bean 的對象,将對象存入到 request 域中.
- session :WEB 項目中,Spring 建立一個 Bean 的對象,将對象存入到 session 域中.
-
global session :WEB 項目中,應用在 Portlet 環境.如果沒有 Portlet 環境那麼
globalSession 相當于 session.
- init-method:指定類中的初始化方法名稱。
- destroy-method:指定類中銷毀方法名稱。
4.3 bean的生命周期
單例對象:scope=“singleton”
一個應用隻有一個對象的執行個體。它的作用範圍就是整個應用。
生命周期:
對象出生:當應用加載,建立容器時,對象就被建立了。
對象活着:隻要容器在,對象一直活着。
對象死亡:當應用解除安裝,銷毀容器時,對象就被銷毀了。
多例對象:scope=“prototype”
每次通路對象時,都會重新建立對象執行個體。
生命周期:
對象出生:當使用對象時,建立新的對象執行個體。
對象活着:隻要對象在使用中,就一直活着。
對象死亡:當對象長時間不用時,被 java 的垃圾回收器回收了。
5. spring的依賴注入
5.1 依賴注入的概念
==依賴注入:Dependency Injection。==它是 spring 架構核心 ioc 的具體實作。我們的程式在編寫時,通過控制反轉,把對象的建立交給了 spring,但是代碼中不可能出現沒有依賴的情況。ioc 解耦隻是降低他們的依賴關系,但不會消除。例如:我們的業務層仍會調用持久層的方法。那這種業務層和持久層的依賴關系,在使用 spring 之後,就讓 spring 來維護了。簡單的說,就是坐等架構把持久層對象傳入業務層,而不用我們自己去擷取。
在目前類需要用到其他類的對象,由spring為我們提供,我們隻需要在配置檔案中說明,依賴關系的維護,就稱之為依賴注入。
依賴注入:
== 能注入的資料:==
基本類型和String
其他bean類型(在配置檔案中或者注解配置過的bean)
複雜類型/集合類型
== 注入的方式:==
使用構造方式提供
使用set方法提供
使用注解提供
5.2 構造函數注入
顧名思義,就是使用類中的構造函數,給成員變量指派。注意,指派的操作不是我們自己做的,而是通過配置的方式,讓 spring 架構來為我們注入。
public class AccountServiceImpl implements IAccountService {
//如果是經常變化的資料,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name=name;
this.age=age;
this.birthday=birthday;
}
public void saveAccount() {
System.out.println("service中的saveAccount方法執行了。。。"+name+","+age+","+birthday);
}
}
使用的标簽:constructor-age
标簽出現的位置:bean标簽的内部
标簽中的屬性:
type:用于指定要注入的資料類型,該資料類型也是構造函數中某個或某些參數的類型
index:用于指定要注入的資料給構造函數中指定索引位置的參數指派。索引位置從0開始。
name:用于指定給構造函數中指定名稱的參數指派(常用的)
--------------------------以上三個用于指定給構造函數中那個參數指派--------------------
value:用于提供基本類型和string類型的資料
ref:用于指定其他的bean類型的資料。它指的是在spring的ioc核心容器中出現過的bean對象
優點:在擷取bean對象時,注入資料是必須的操作,否則對象無法建立成功
缺點:改變了bean對象的執行個體化方式,使我們在建立對象時如果用不到這些資料也必須提供
<bean id="accountService" class="com.wyj.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--配置一個日期對象-->
<bean id="now" class="java.util.Date"></bean>
5.3 set 方法注入(常用)
public class AccountServiceImpl2 implements IAccountService {
//如果是經常變化的資料,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void saveAccount() {
System.out.println("service中的saveAccount方法執行了。。。"+name+","+age+","+birthday);
}
}
涉及的标簽:property
出現的位置:bean标簽的内部
标簽的屬性:
name:用于指定注入時所調用的set方法名稱
value:用于提供基本類型和string類型的資料
ref:用于指定其他的bean類型的資料。它指的是在spring的ioc核心容器中出現過的bean對象
優點:建立對象時沒有明确的限制,可以直接使用預設構造函數
缺點:如果有某個成員必須有值,則擷取對象是有可能set方法沒有執行
<bean id="accountService2" class="com.wyj.service.impl.AccountServiceImpl2">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
5.4 注入集合資料
public class AccountServiceImpl3 implements IAccountService {
private String[] myStr;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStr(String[] myStr) {
this.myStr = myStr;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
public void saveAccount() {
System.out.println(Arrays.toString(myStr));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
注入集合資料
List 結構的:
array,list,set
Map 結構的
map,entry,props,prop
<bean id="accountService3" class="com.wyj.service.impl.AccountServiceImpl3">
<property name="myStr">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>bbb</value>
</entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testC">ccc</prop>
<prop key="testD">ddd</prop>
</props>
</property>
</bean>