1.Spring 框架介紹
Spring 是一個開源的輕量級 Java 開發框架,可以解決業務邏輯層和其他層的耦合太高的問題,它不僅可以用在 Java EE 上,對于 Java SE 同樣可以使用。美其名曰,Spring 的出現算是給軟件開發帶來了春天,它的分層架構可以使 Spring 框架搭配其他的框架使用,如 Struts2,Hibernate,三者總稱為 SSH 框架。Spring 不僅僅是一個框架,控制反轉(IOC)和面向切面編程(AOP)的設計思想才是其精華所在。
Spring 中 Java EE 開發的三層結構:
- web 層:Spring MVC
- service 層:Bean 管理
- dao 層:Spring 的 JDBCTemplate 整合其他持久層框架,如:Hibernate
2.spring 中的概念
2.1 AOP(面向切面編程)
這個在 Strust2 中也提到了,Struts2 的攔截器就是面向切面編程的一種實現方式,在原有的功能基礎上擴展功能不用修改源代碼,而是通過配置文件。
2.2 IOC(控制反轉)
將對象的創建權交給 Spring,而不是通過 new 的方式來創建對象,這樣也符合軟件開發中 高內聚低耦合 的設計理念,盡可能的降低對象與對象之間的調用關系。
3.搭建 Spring 框架
3.1 準備 Spring 的相關 jar 包
在 Spring 框架的官網上,下載按鈕并不是在顯眼的位置,這里提供一個 Spring 各個版本 下載地址,我下載的是 4.3.9 版本的 zip 壓縮包。解壓后,docs 文件夾是 Spring 的 API 文檔和開發規范,libs 文件夾 是 Spring 的 jar 包和源碼,scheme 文件夾 是 Spring 的約束文件。在 libs 文件夾內,每三個 jar 包是一組,包括開發用的 jar 包,說明文檔,源碼。
3.2 導入 Spring 的相關 jar 包
libs文件夾下的 spring-beans,spring-context,spring-core,spring-expression 這四個 jar 包,還有一個記錄日志的 jar 包 commons-logging,這個 jar 包不導入的話在控制臺會出現 java.lang.ClassNotFoundException
的錯誤,但這個包并不是 Spring 框架中的,屬于 Apache 項目中的一個開發組件,這里也提供一個 下載地址,在 java web項目中的lib文件夾下導入這五個 jar 包。
3.3 Spring 的使用案例
實體類
package cc.wenshixin.entity;
public class Student {
public void study()
{
System.err.println("學習中。。。");
}
}
配置文件
Spring 的配置文件的名稱和位置不是固定的,但建議直接放在 src 目錄下便于和其他框架的配置文件統一管理,另外官方建議的配置文件名是 applicationContext.xml,但也可以自己設定配置文件名稱。和 Struts2、Hibernate 框架中的配置文件的約束文件類型不同,前兩者是 dtd 約束,而后者是 scheme 約束。關于scheme的約束模板,可以在這個 地址 (在靠后的部分)上找,也可以抄下面基本的模板約束。
<?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">
<bean id="student" class="cc.wenshixin.entity.Student"></bean>
</beans>
測試類
使用IOC(控制反轉)技術(在下面會詳細介紹IOC的底層實現原理),對象創建的工作就交給 Spring 來完成,加上類在配置文件中的 id 名就可以返回創建的對象,這里面是工廠模式的設計思想。
package cc.wenshixin.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cc.wenshixin.entity.Student;
public class Test1 {
@Test
public void test01()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Student student = (Student) context.getBean("student");
student.study();
}
}
4.Spring 中的 bean 管理
4.1 IOC 的底層實現原理
IOC 的底層是通過 dom4j 解析 xml 文件、工廠設計模式,反射機制實現的,如下圖所示。
4.2 bean 實例化對象的三種方式
- 第一種 使用類的無參構造方法創建(重點)
上面的使用案例中就是使用的這種創建對象方式,比較簡單,在開發中經常使用。注意在實體類中要有無參數的構造函數,否則 Spring 無法創建實體類對象,出現異常。如果在實體類中有有參數的構造函數,要手動補上無參數的構造方法,來方便 Spring 的調用。
- 第二種 使用靜態工廠創建
使用一個工廠類,創建靜態的方法,返回對象
實體類代碼同上
工廠類
package cc.wenshixin.factory;
import cc.wenshixin.entity.Student;
public class StudentFactory1 {
public static Student getStudent()
{
return new Student();
}
}
配置文件
<!-- 使用靜態工廠創建 -->
<bean id="studentFactory1" class="cc.wenshixin.factory.StudentFactory1" factory-method="getStudent"></bean>
測試類
@Test
public void test02()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Student student = (Student) context.getBean("studentFactory1");
student.study();
}
- 第三種 使用實例工廠創建
使用一個工廠類,創建普通的方法,返回對象
實體類代碼同上
工廠類代碼
package cc.wenshixin.factory;
import cc.wenshixin.entity.Student;
public class StudentFactory2 {
public Student getStudent()
{
return new Student();
}
}
配置文件
<!-- 使用實例工廠創建 -->
<bean id="studentFactory2" class="cc.wenshixin.factory.StudentFactory2"></bean>
<bean id="stud" factory-bean="studentFactory2" factory-method="getStudent"></bean>
測試類
@Test
public void test03()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Student student = (Student) context.getBean("stud");
student.study();
}
4.3 bean 標簽中的常用屬性
- id 屬性:給 bean 起名字,id 屬性名稱可以任意,但不能包含特殊符號,用于根據 id 屬性值得到配置對象。
- class 屬性:創建對象所在類的全路徑
- name 屬性:功能和 id 屬性一樣,但 name 屬性名稱中可以包含特殊符號
- scope 屬性:
- 1.
singleton
屬性默認值,單個對象 - 2.
prototype
多個對象 - 3.
request
創建對象并把對象放在 request 域中 - 4.
session
創建對象并把對象放在 session 域中 - 5.
globalSession
創建對象并把對象放在 globalSession 中
- 1.
scope屬性的前兩個屬性值常用,后面幾個知道即可.
測試 singleton
屬性值,默認的可以不寫,修改上面測試類中的代碼如下:
@Test
public void test01()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象,使用單例模式,兩個對象引用的地址相同
Student s1 = (Student) context.getBean("student");
Student s2 = (Student) context.getBean("student");
System.out.println(s1);
System.out.println(s2);
}
測試 prototype
屬性值,修改配置文件的代碼如下:
<bean id="student" class="cc.wenshixin.entity.Student" scope="prototype"></bean>
再次執行上面的測試類代碼,觀察兩個對象引用的地址不同,即創建了多個對象。
4.3 bean 中屬性注入
所謂屬性注入就是在創建類對象時向對象的屬性中設置值,名字起的有些高大上。
一般屬性注入有三種方式
- 1.使用 set 方法注入
public class Student{
private String name;
public setName(String name){
this.name = name
}
}
//set方法注入
Student student = new Student();
student.setName("小明");
- 2.使用有參構造函數注入
public class Student{
private String name;
public Student(String name){
this.name = name
}
}
//構造函數注入
Student student = new Student("小明");
- 3.使用接口注入
public interface Dao{
public void setName(String name);
}
public class DaoImpl implements Dao{
private String name;
public void setName(String name){
this.name = name;
}
}
但在 Spring 中,只支持前兩種方式,也即是 set 方法注入和構造函數注入,通過配置文件來是使對象被創建時給對象的相關屬性賦值。
- 使用 set 方法注入屬性
修改實體類為
package cc.wenshixin.entity;
public class Student {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
配置文件
<!-- 使用方式注入屬性 -->
<bean id="student" class="cc.wenshixin.entity.Student">
<property name="name" value="小明"></property>
</bean>
測試方法
@Test
public void test01()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Student s = (Student) context.getBean("student");
//輸入配置文件中注入的屬性值
System.out.println(s.getName());
}
- 使用有參構造函數注入屬性
實體類增加有參構造方法
配置文件修改為
<!-- 使用有參構造函數注入屬性 -->
<bean id="student" class="cc.wenshixin.entity.Student">
<!-- 使用有參構造注入 -->
<constructor-arg name="name" value="小紅"></constructor-arg>
</bean>
測試方法同上
- 注入對象類型的屬性
創建一個 servic 類和 dao 類,在 service 中得到 dao 的對象,這在 Java Web 開發中是很常見的。
示例代碼如下:
實體類同上
dao 類
package cc.wenshixin.entity;
public class Dao {
public void insert()
{
System.out.println("Dao插入學生數據。。。");
}
}
service 類
package cc.wenshixin.entity;
public class Service {
//定義到類型屬性
private Dao dao;
//生成set方法
public void setDao(Dao dao) {
this.dao = dao;
}
public void add()
{
System.out.println("Service添加操作");
dao.insert();
}
}
配置文件
property
標簽中,name
屬性值為 service
類中的屬性名稱,ref
屬性值為dao中配置中 id
屬性值,這里就不能寫 value
屬性了,因為是一個對象,無法屬性注入。
<!-- 配置service和dao對象 -->
<bean id="dao" class="cc.wenshixin.entity.Dao"></bean>
<bean id="service" class="cc.wenshixin.entity.Service">
<property name="dao" ref="dao"></property>
</bean>
測試方法
@Test
public void test03()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Service service = (Service) context.getBean("service");
service.add();
}
- P 名稱空間屬性注入
在配置文件的約束中加上 xmlns:p="http://www.springframework.org/schema/p"
。
實體類中需要默認的構造函數和屬性對應的set方法
package cc.wenshixin.entity;
public class Student {
private String name;
public Student() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
注釋:加上p名稱空間
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p名稱空間注入 -->
<bean id="student" class="cc.wenshixin.entity.Student" p:name="老王"></bean>
</beans>
測試方法
@Test
public void test01()
{
//1.加載spring的配置文件,根據配置文件來創建對象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.得到配置中創建的對象
Student s = (Student) context.getBean("student");
System.out.println(s.getName());
}