-
Spring框架概述圖
這張圖展示了,搭建項目時所需要的模塊(對應的jar包),例如:使用spring框架連接數據庫,則需要用到Core, Aop, Dao模塊的jar包。
-
解壓之後獲得
本章主要介紹SpringIoC,所以只使用其中的ioc文件夾下的jar包和applicationContext.xml文件
-
創建web project
打開eclipse,選擇File >>> New >>> Dynamic Web Project
填寫完項目名稱之後,直接點擊Finish,項目就創建完成了。
創建之後的目錄結構如下:
-
打開下載的jar包,將ioc文件夾下的jar包複製到lib目錄下,將applicationContext.xml文件複製到src目錄下
到此,環境已經準備完成。 -
使用SpringIoC創建對象的三種方法
src目錄下創建一個class文件,用於接下來的測試
第一種方法:採用new構造器創建對象
不使用框架
package org.springioc.test;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TestBean {
public static void main(String[] args) {
Calendar c1 = new GregorianCalendar();
System.out.println("c1="+c1);
}
}
使用框架
首先在applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- 使用new構造器方法創建對象 -->
<bean id="c2" class="java.util.GregorianCalendar"></bean>
</beans>
然後在測試類TestBean中通過框架創建對象
package org.springioc.test;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBean {
public static void main(String[] args) {
Calendar c1 = new GregorianCalendar();
System.out.println("c1="+c1);
String conf = "applicationContext.xml";//配置文件的文件名
//實例化容器
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
//創建對象,
//ac.getBean("c2", Calendar.class)
//c2爲配置文件applicationContext.xml中的id
//Calendar.class爲獲取對象的類型
Calendar c2222 = ac.getBean("c2", Calendar.class);
System.out.println("c2222="+c2222);
}
}
第二種方法:採用靜態工廠方法創建對象
不使用框架
測試類TestBean中
Calendar c3 = Calendar.getInstance();
使用框架
首先在applicationContext.xml中增加配置
<!-- 使用靜態工廠方法創建對象 -->
<bean id="c3" class="java.util.Calendar" factory-method="getInstance"></bean>
測試類TestBean中
Calendar c3333 = ac.getBean("c3", Calendar.class);
System.out.println("c3333="+c3333);
第三中方法:採用對象工廠方法創建對象
不使用框架
測試類TestBean中
Date date = c3.getTime();
System.out.println("date="+date);
使用框架
首先在applicationContext.xml中增加配置,c3爲第二種方法種配置的id
<!-- 採用對象工廠方法創建對象 -->
<bean id="date" factory-bean="c3" factory-method="getTime"></bean>
測試類TestBean中
Date date3333 = ac.getBean("date", Date.class);
System.out.println("date3333="+date3333);
- 創建對象時單例,非單例控制
使用以上方式創建對象,默認是單例(singleton),但是可以通過scope屬性 更改,它的值有singleton(單例)和prototype(非單例)。
下面舉例說明:
在src目錄下新建目錄org.spingioc.bean,在此目錄下新建類ExampleBean
package org.springioc.bean;
public class ExampleBean {
public void execute() {
System.out.println("調用execute方法");
}
}
使用框架,創建對象
首先配置applicationContext.xml
<bean id="e1" class="org.springioc.bean.ExampleBean"></bean>
編寫測試類ExampleTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.ExampleBean;
public class ExampleTest {
public static void main(String[] args) {
String conf ="applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
ExampleBean e1 = ac.getBean("e1", ExampleBean.class);
ExampleBean e2 = ac.getBean("e1", ExampleBean.class);
System.out.println(e1==e2);
}
}
結果爲true,代表爲singleton模式。
將applicationContext.xml增加scope屬性,將它改爲非單例模式
<bean scope="prototype" id="e1" class="org.springioc.bean.ExampleBean"></bean>
再次運行測試類ExampleTest,結果爲false,代表爲非單例模式。
- 創建對象時初始化動作
不使用框架,可以使用構造器和構造代碼塊實現對象的初始化
package org.springioc.bean;
public class ExampleBean {
{
System.out.println("構造代碼塊!");
}
public ExampleBean() {
System.out.println("無參構造函數!");
}
public void execute() {
System.out.println("調用execute方法");
}
}
運行測試類ExampleTest,控制檯顯示
使用框架
首先在ExampleBean類中增加初始化函數init
public void init() {
System.out.println("初始化方法!");
}
將init函數配置在applicationContext.xml中
<bean init-method="init" scope="prototype" id="e1" class="org.springioc.bean.ExampleBean"></bean>
運行測試類ExampleTest,控制檯顯示
以上這兩種方法初始化對象的區別,使用構造代碼塊和構造器初始化對象,是在對象創建的過程中初始化對象,使用init-method初始化對象,是在對象創建完成再對對象做初始化動作。
- 對象的銷燬
在applicationContext.xml中配置destroy-method實現對象的銷燬。使用bean中的這個屬性,需要兩個條件支持
第一個:必須實現AbstractApplicationContext容器,並且運行它的close方法
package org.springioc.test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ExampleTest {
public static void main(String[] args) {
String conf ="applicationContext.xml";
AbstractApplicationContext ac = new ClassPathXmlApplicationContext(conf);
ac.close();
}
}
第二個:對象必須是單例模式(singleton)
<bean destroy-method="destroy" init-method="init" scope="singleton" id="e1" class="org.springioc.bean.ExampleBean"></bean>
另外在ExampelBean中增加destroy方法
public void destroy() {
System.out.println("銷燬對象!");
}
運行ExampleTest類,
- 控制單例對象的創建時機
若需在實例化容器的時候創建對象,需要在applicationContext.xml配置三個屬性
第一個:abstract=“false”,不配置默認爲false
第二個:scope=“singleton” ,不配默認爲singleton
第三個:lazy-init="false"
<bean abstract="false" lazy-init="false" destroy-method="destroy" init-method="init" scope="singleton" id="e1" class="org.springioc.bean.ExampleBean"></bean>
否則在調用容器的getBean函數的時候創建對象
<bean abstract="false" lazy-init="true" destroy-method="destroy" init-method="init" scope="singleton" id="e1" class="org.springioc.bean.ExampleBean"></bean>
-
在applicationContext.xml中bean元素中配置的init-method, destroy-method, lazy-init是針對單個對象的;也可以在beans元素中配置default-init-method, default-destroy-method, default-lazy-init,這樣對配置文件中的每一個對象都能生效。(瞭解)
-
SpringIoC依賴注入(控制反轉或反向控制)
控制反轉:改變了獲取對象的方式,不使用框架的情況下,使用new創建對象;ioc中,由容器創建對象,對象的參數,以及對象之間的關係,只需要修改配置即可改變。
下面介紹兩種方式:
第一種,構造器注入,這種方法需要創建有參的構造器
首先創建一個Phone類
package org.springioc.bean;
public class Phone {
private String brand;
private String price;
public Phone(String brand, String price) {
this.brand=brand;
this.price=price;
}
public void show() {
System.out.println("--手機--brand:"+brand+" price:"+price);
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setPrice(String price) {
this.price = price;
}
}
配置applicationContext.xml文件
<bean id="p1" class="org.springioc.bean.Phone">
<!-- 構造器注入,index參數序號從零開始計數,value想要賦給對象屬性的值 -->
<constructor-arg index="0" value="蘋果"></constructor-arg>
<constructor-arg index="1" value="12000"></constructor-arg>
</bean>
編寫測試類PhoneTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.Phone;
public class PhoneTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Phone p = ac.getBean("p1", Phone.class);
p.show();
}
}
第二種:set注入
創建Computer類
package org.springioc.bean;
public class Computer {
private String brand;
private String price;
public void show() {
System.out.println("--電腦--brand:"+brand+" price:"+price);
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setPrice(String price) {
this.price = price;
}
}
配置applicationContext.xml文件
<bean id="pc" class="org.springioc.bean.Computer">
<!-- set注入,name對象屬性,value屬性值 -->
<property name="brand" value="聯想"></property>
<property name="price" value="8000"></property>
</bean>
編寫測試類PhoneTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.Phone;
public class PhoneTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Phone p = ac.getBean("p1", Phone.class);
p.show();
}
}
另一種情況如果屬性值爲一個對象,該如何用注入的方式
創建Student類
package org.springioc.bean;
public class Student {
private Phone phone;
private Computer pc;
public void show() {
phone.show();
pc.show();
}
public void setPhone(Phone phone) {
this.phone = phone;
}
public void setPc(Computer pc) {
this.pc = pc;
}
}
配置applicationContext.xml文件,使用ref引用原有的對象
<bean id="st" class="org.springioc.bean.Student">
<property name="phone" ref="p1"></property>
<property name="pc" ref="pc"></property>
</bean>
編寫測試類StudentTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.Student;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student st = ac.getBean("st", Student.class);
st.show();
}
}
- 自動注入(autowrite),瞭解就可!
Spring IoC容器可以自動裝配(autowire)相互協作bean之間的關聯關係。因此,如果可能的話,可以自動讓Spring通過檢查BeanFactory中的內容,來替我們指定bean的協作者(其他被依賴的bean)。autowire一共有五種類型(“no”, “byName”, “byType”, “constructor”, “autodetect”)。由於autowire可以針對單個bean進行設置,因此可以讓有些bean使用autowire,有些bean不採用。autowire的方便之處在減少或者消除屬性或構造器參數的設置,這樣可以給我們的配置文件減減肥!
下面以"byType"舉例:
配置applicationContext.xml文件
<bean id="st1" class="org.springioc.bean.Student" autowire="byType"></bean>
修改測試類StudentTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.Student;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student st = ac.getBean("st1", Student.class);
st.show();
}
}
- 各種類型的信息注入配置
創建類MessageBean
package org.springioc.bean;
import java.sql.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
public class MessageBean {
private String name;
private int age;
private Date birth;
private List<String> friends;
private Set<String> cities;
private Map<String,String> books;
private Properties db;
public void show() {
String lstFriends="";
for(int i=0;i<friends.size();i++) {
lstFriends +=friends.get(i)+",";
}
System.out.println("name:"+name+", age:"+age+", birth:"+birth+", friends:"+lstFriends);
for(String s : cities) {
System.out.println(s);
}
Set<Entry<String,String>> booksSet = books.entrySet();
for(Entry<String,String> e :booksSet) {
System.out.println("key:"+e.getKey()+", value:"+e.getValue());
}
Set<Object> dbSet = db.keySet();
for(Object key : dbSet) {
System.out.println("key:"+key+", value:"+db.getProperty(key.toString()));
}
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirth(String birth) {
Date date =Date.valueOf(birth);
this.birth = date;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public void setCities(Set<String> cities) {
this.cities = cities;
}
public void setBooks(Map<String, String> books) {
this.books = books;
}
public void setDb(Properties db) {
this.db = db;
}
}
第一,基礎類型,和String類型
<!-- 給name賦值null -->
<property name="name">
<null/>
</property>
<property name="age" value="18"></property>
<!-- birth爲Date類型,set方法需要重寫 -->
<property name="birth" value="2019-01-01"></property>
第二,List類型
<property name="friends">
<list>
<value>朋友1</value>
<value>朋友2</value>
</list>
</property>
第三,Set類型
<property name="cities">
<set>
<value>城市1</value>
<value>城市2</value>
</set>
</property>
第四,Map類型
<property name="books">
<map>
<entry key="001" value="書1"></entry>
<entry key="002" value="書2"></entry>
</map>
</property>
第五,Properties類型
<property name="db">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
編寫測試類MessageTest
package org.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springioc.bean.MessageBean;
public class MessageTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
MessageBean msg = ac.getBean("msg", MessageBean.class);
msg.show();
}
}
第六,傳遞bean對象
<util:list id="fds">
<value>朋友3</value>
<value>朋友4</value>
</util:list>
<util:set id="cts">
<value>城市3</value>
<value>城市4</value>
</util:set>
<util:map id="boks">
<entry key="003" value="書3"></entry>
<entry key="004" value="書4"></entry>
</util:map>
<util:properties id="dbs">
<prop key="user">root</prop>
<prop key="password">123456</prop>
</util:properties>
<bean id="msg1" class="org.springioc.bean.MessageBean">
<property name="friends" ref="fds"></property>
<property name="cities" ref="cts"></property>
<property name="books" ref="boks"></property>
<property name="db" ref="dbs"></property>
</bean>
第七,Spring表達式注入
<bean id="msg1" class="org.springioc.bean.MessageBean">
<property name="friends" ref="fds"></property>
<property name="cities" ref="cts"></property>
<property name="books" ref="boks"></property>
<property name="db" ref="dbs"></property>
<!-- 表達式注入 -->
<property name="name" value="#{fds[0]}"></property>
<property name="age" value="#{dbs.password}"></property>
</bean>
第八,讀取properties文件
在src目錄下創建db.properties文件,文件內容格式爲key=value:
user=xiaohong
password=321123
配置applicationContext.xml文件,classpath代表src目錄下
<util:properties id="dbParams" location="classpath:db.properties"/>
- 組件自動掃描
組件自動掃描,可以按指定的包路徑,將包下所有組件掃描,如果發現類定義前有以下標記,會將組件掃描到Sping容器
@Component//其他組件
@Controller//控制層組件
@Service//業務層組件 xxxService
@Repository//數據訪問層組件 xxxDao
@Named(需要引入第三方jar包,一般用不到!)
@Scope控制對象是否單例,默認單例
@PostConstruct指定init-method
@PreDestroy指定destroy-method
首先配置applicationContext.xml文件
<!-- 開啓組件掃描 -->
<context:component-scan base-package="org.springioc.bean"/>
編寫bean類Book.java
package org.springioc.bean;
import org.springframework.stereotype.Component;
@Component//默認id爲類名首字母小寫;也可以設置固定的id,@Component("id")
public class Book {
private String name;
private int num;
public void execute() {
System.out.println("book的execute方法!");
}
public void show() {
System.out.println("name:"+name+", num:"+num);
}
}
編寫測試類,BookTest.java
package org.springioc.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component//默認id爲類名首字母小寫;也可以設置固定的id,@Component("id")
@Scope("prototype")//設置單例或非單例,不設置默認爲singleton
public class Book {
private String name;
private int num;
@PostConstruct//設置初始化方法
public void init() {
System.out.println("初始化方法!");
}
@PreDestroy//設置方法銷戶方法
public void destroy() {
System.out.println("銷燬方法!");
}
public void execute() {
System.out.println("book的execute方法!");
}
}
- 注入註解
@Resource:可以在變量定義前
或setXX方法前應用
@Autowired:可以在變量定義前
或setXX方法前應用
一般使用時,功能等價,都可以實現注入。
如果不存在多個匹配類型,使用@Resource
或@Autowired都可以。
如果存在多個匹配類型,建議按名稱注入
@Resource(name=“指定名稱”)或
@Autowired
@Qualifier(“p”)
如果指定名稱注入,不會再按類型匹配注入。
新建一個web工程
配置applicationContext.xml
<!-- 開啓組件掃描 -->
<context:component-scan base-package="cn.springioc"/>
編寫Phone.java,Computer.java,Student.java
package cn.springioc.bean;
import org.springframework.stereotype.Component;
@Component
public class Phone {
public void show(){
System.out.println("顯示手機配置信息");
}
}
package cn.springioc.bean;
import org.springframework.stereotype.Component;
@Component
public class Computer {
public void show(){
System.out.println("顯示計算機配置信息");
}
}
package cn.springioc.bean;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("st")
public class Student {
@Resource//首先根據名字phone去匹配,如果匹配不到就按照類型去匹配。這裏根據phone匹配能夠找到
private Phone phone;
public void setPhone(Phone phone) {
this.phone = phone;
}
@Autowired//首先根據名字pc去匹配,如果匹配不到就按照類型去匹配。這裏根據pc匹配找不到,就根據類型去匹配
private Computer pc;
public void setPc(Computer pc) {
this.pc = pc;
}
public void show() {
phone.show();
pc.show();
}
}
編寫測試類StudentTest.java
package cn.springioc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.springioc.bean.Student;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student st = ac.getBean("st", Student.class);
st.show();
}
}
@Resouce(name=“id”),按照名字id去匹配,如果匹配不到不會按照類型去匹配,匹配不到就拋錯
@Resource(name="pc1")//按照名字去匹配pc1,如果找不到就報錯
private Computer pc;
public void setPc(Computer pc) {
this.pc = pc;
}
將Computer.java,的bean的id改爲pc1,否則會拋錯
@Component("pc1")
public class Computer {
public void show(){
System.out.println("顯示計算機配置信息");
}
}
@Autowired 和 @Qualifier(“id”)按照指定的id名字匹配
@Autowired
@Qualifier("pc1")
private Computer pc;
public void setPc(Computer pc) {
this.pc = pc;
}
或則
private Computer pc;
@Autowired
public void setPc(@Qualifier("pc1") Computer pc) {
this.pc = pc;
}