Spring的基本應用
學習目標
- 掌握:ApplicationContext 容器使用屬性 setter 方法注入的實現
- 熟悉:Spring 中的 IoC 和 DI
- 瞭解:Spring 的概念和優點
主要內容
1.1 Spring 概述
1.2 Spring 的核心容器
1.3 Spring 的入門程式
1.4 依賴注入
1.1.1 什麼是 Spring
Spring 是分層的 JavaSE/EE full-stack 輕量級開源框架,以 IoC(Inverse of Control 控制反轉)和 AOP(Aspect Oriented Programming 面向切面程式設計)為核心,使用基本的 JavaBean 來完成以前只可能由 EJB 完成的工作,取代了 EJB 的臃腫、低效的開發模式。
在實際開發中,通常伺服器端在採用三層體系架構,分別為表示層 (Web)、業務邏輯層 (Service)、持久層 (Dao), Spring 對每一層都提供了技術支援。
- 表示層 在表示層提供了與 Struts 等框架的整合
- 業務邏輯層 在業務邏輯層可以管理事務、記錄日誌等
- 持久層 在持久層可以整合 Hibernate、JdbcTemplate
等技術
1.1.2 Spring 框架的優點
Spring 具有簡單、可測試和鬆耦合等特點。Spring 不僅可以用於伺服器端開發,也可以應用於任何 Java 應用的開發中。
Spring 框架的 7 大優點:
- 非侵入式設計
- 方便解耦、簡化開發
- 支援 AOP
- 支援宣告式事務處理
- 方便程式測試
- 方便整合各種優秀框架
- 降低 Java EE API 的使用難度
1.1.3 Spring 的體系結構
Spring 框架採用的是分層架構,它一系列的功能要素被分成 20 個模組。
1.1.4 Spring 的下載及目錄結構
Spring 框架包
下載 後的解壓:
- libs 資料夾中包含 JAR 包和原始碼
- docs 資料夾中包含 API 文件和開發規範
- Schema 資料夾中包含開發所需要的 schema 檔案
開啟 libs 目錄可以看到 60 個 JAR 檔案,具體如下:
- 以 RELEASE.jar 結尾的是 class 檔案 JAR 包
- 以 RELEASE-javadoc.jar 結尾的是 API 文件壓縮包
- 以 RELEASE-sources.jar 結尾的是原始檔壓縮包
在 libs 目錄中有四個 Spring 的基礎包,分別對應 Spring 核心容器的四個模組。
- spring-core-4.3.6.RELEASE.jar 包含 Spring 框架的核心工具類,Spring 其它元件都要用到這個包裡的類。
- spring-beans-4.3.6.RELEASE.jar 所有應用都要用到的 JAR 包,它包含訪問配置檔案、建立和管理 Bean 以及進行控制反轉或者依賴注入操作相關的所有類。
- spring-context-4.3.6.RELEASE.jar 提供了在基礎 IoC 功能上的擴充套件服務,還提供了許多企業級服務的支援
- spring-expression-4.3.6.RELEASE.jar 定義了 Spring 的表示式語言。
第三方依賴包
在使用 Spring 開發時,除了要使用自帶的 JAR 包外,Spring 的核心容器還需要依賴 commons.logging 的 JAR 包。下載
1.2 Spring 的核心容器
Spring 容器會負責控制程式之間的關係,而不是由程式程式碼直接控制。Spring 為我們提供了兩種核心容器,分別為 BeanFactory
和 ApplicationContext
,本節將對這兩種核心容器進行簡單介紹。
1.2.1 BeanFactory
建立 BeanFactory
例項時,需要提供 Spring 所管理容器的詳細配置資訊,這些資訊通常採用 XML 檔案形式來管理,其載入配置資訊的語法如下:
BeanFactory beanFactory =
new XmlBeanFactory(new FileSystemResource("F: /applicationContext.xml"));
這種載入方式在實際開發中並不多用,作為了解即可。
1.2.2 ApplicationContext
ApplicationContext
是 BeanFactory
的子介面,是另一種常用的 Spring 核心容器。它由 org.springframework.context.ApplicationContext
介面定義,不僅包含了 BeanFactory 的所有功能,還添加了對國際化、資源訪問、事件傳播等方面的支援。建立 ApplicationContext
介面例項,通常採用兩種方法,具體如下:
- 通過 ClassPathXmlApplicationContext 建立
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(String configLocation);
ClassPathXmlApplicationContext
會從類路徑 classPath
中尋找指定的 XML 配置檔案,找到並裝載完成 ApplicationContext
的例項化工作。
- 通過 FileSystemXmlApplicationContext 建立
ApplicationContext applicationContext =
new FileSystemXmlApplicationContext(String configLocation);
FileSystemXmlApplicationContext
會從指定的檔案系統路徑(絕對路徑)中尋找指定的 XML 配置檔案,找到並裝載完成 ApplicationContext
的例項化工作。
在 Java 專案中,會通過 ClassPathXmlApplicationContext
類來例項化 ApplicationContext
容器。而在 Web 專案中,ApplicationContext
容器的例項化工作會交由 Web 伺服器來完成。
Web 伺服器例項化 ApplicationContext
容器時,通常會使用 ContextLoaderListener
來實現,此種方式只需要在 web.xml 中新增如下程式碼:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
1.3 Spring 的入門程式
-
在 Eclipse 中,建立一個名為 chapter01 的 Web 專案,將 Spring 的 4 個基礎包以及 commons-logging 的 JAR 包複製到 lib 目錄中,併發布到類路徑下。
-
在 src 目錄下,建立一個 com.itheima.ioc 包,並在包中建立介面 UserDao,然後在介面中定義一個
say()
方法。
package com.itheima.ioc;
public interface UserDao {
public void say();
}
- 在 com.itheima.ioc 包下,建立
UserDao
介面的實現類UserDaoImpl
,該類需要實現介面中的say()
方法,並在方法中編寫一條輸出語句。
package com.itheima.ioc;
public class UserDaoImpl implements UserDao {
public void say() {
System.out.println("userDao say hello World !");
}
}
- 在 src 目錄下,建立 Spring 的配置檔案 applicationContext.xml,並在配置檔案中建立一個 id 為
userDao
的 Bean。
<?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-4.3.xsd">
<bean id="userDao" class="com.itheima.ioc.UserDaoImpl" />
</beans>
- 在 com.itheima.ioc 包下,建立測試類
TestIoC
,並在類中編寫main()
方法。在main()
方法中,需要初始化 Spring 容器,並載入配置檔案,然後通過 Spring 容器獲取userDao
例項(即 Java 物件),最後呼叫例項中的say()
方法。
package com.itheima.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestIoC {
public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.say();
}
}
控制檯 Console:
userDao say hello World !
1.4.1 依賴注入的概念
什麼是依賴?
如果類 A 的物件要完成某一操作,必須呼叫類 B 的物件的某些操作來幫忙,才能完成。我們稱作類 A 依賴類 B。
舉例:a 物件呼叫 b 物件的 x()
方法,完成 a 物件的 y()
方法。
對於依賴關係通常解決方法:
public class B {
public void x() {
System.out.println("b.x() is called!--common");
}
對於依賴關係通常解決方法:
public class A {
private B b;
public void setB(B b) {
this.b=b;
}
public void y() {
b.x();
System.out.println("a.y() is called!--common");
}
}
對於依賴關係通常解決方法:
public class TestNoSpringCommon {
public static void main(String[] args) {
A a=new A(); // 新建物件 a
B b=new B(); // 新建物件 b
a.setB(b); // 呼叫物件 a.setB(b) 方法
a.y(); // 呼叫物件 a.y() 方法
}
}
對於依賴關係(介面方式)通常解決方法:
public interface BInterface {
public void x();
}
public class BImpl implements BInterface{
public void x() {
System.out.println("b.x() is called!--noSpringUseInterface");
}
}
對於依賴關係(介面方式)通常解決方法:
public interface AInterface {
public void y();
}
public class AImpl implements AInterface{
private BImpl b;
public void setB(BImpl b) {
this.b=b;
}
public void y() {
b.x();
System.out.println("a.y() is called!--noSpringUseInterface");
}
}
對於依賴關係(介面方式)通常解決方法:
public class TestNoSpring {
public static void main(String[] args) {
AImpl aImpl=new AImpl();
BImpl bImpl=new BImpl();
aImpl.setB(bImpl);
aImpl.y();
}
}
DI 的全稱是 Dependency Injection,中文稱之為依賴注入。它與控制反轉(IoC:Inversion of Control)的含義相同,只不過這兩個稱呼是從兩個角度描述的同一個概念。
IoC
在使用 Spring 框架之後,物件的例項不再由應用程式使用 new
來建立,而是由 Spring 容器來建立,Spring 容器會負責控制程式之間的關係,而不是由應用程式程式碼直接控制。這樣,控制權由應用程式碼轉移到了 Spring 容器,控制權發生了反轉,這就是控制反轉。
DI
從 Spring 容器的角度來看,Spring 容器負責將被依賴物件賦值給呼叫者的成員變數,這相當於為呼叫者被注入了它依賴的例項,這就是 Spring 的依賴注入。
對於依賴關係(介面方式)使用 Spring 解決方法:
提前引入使用 spring 框架的基礎 jar 檔案:4+1
public interface BInterface {
public void x();
}
public class BImpl implements BInterface{
public void x() {
System.out.println("b.x() is called!--useSpring");
}
}
public interface AInterface {
public void y();
}
public class AImpl implements AInterface{
private BImpl b;
public void setB(BImpl b) {
this.b=b;
}
public void y() {
b.x();
System.out.println("a.y() is called!--useSpring");
}
}
public class TestDI {
public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml"); //初始化 spring 容器,載入配置檔案
AImpl aImpl = (AImpl) applicationContext.getBean("aImpl"); //通過容器獲取 aImpl 例項
aImpl.y(); //呼叫 aImpl.y() 方法
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!--新增一個 id 為 bImpl 的 springdi.BImpl 的例項 -->
<bean id="bImpl" class="springdi.BImpl" />
<!--新增一個 id 為 aImpl 的 springdi.AImpl 的例項 -->
<bean id="aImpl" class="springdi.AImpl">
<!-- 將 id 為 bImpl 的 Bean 例項注入到 springdi.AImpl 例項中 -->
<property name="b" ref="bImpl" />
</bean>
</beans>
1.4.2 依賴注入的實現
- 在 com.itheima.ioc 包中,建立介面
UserService
,在介面中編寫一個say()
方法。
package com.itheima.ioc;
public interface UserService {
public void say();
}
- 在 com.itheima.ioc 包中,建立
UserService
介面的實現類UserServiceImpl
,在類中宣告userDao
屬性,並新增屬性的setter
方法。
package com.itheima.ioc;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void say() {
this.userDao.say();
System.out.println("userService say hello World !");
}
}
- 在配置檔案 applicationContext.xml 中,建立一個 id 為
userService
的 Bean,該 Bean 用於例項化UserServiceImpl
類的資訊,並將userDao
的例項注入到userService
中。
<bean id="userService" class="com.itheima.ioc.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
- 在 com.itheima.ioc 包中,建立測試類
TestDI
,來對程式進行測試。
package com.itheima.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService =
(UserService) applicationContext.getBean("userService");
userService.say();
}
}
- 控制檯 Console:
userDao say hello World !
userService say hello World !
小結
本章主要介紹了 Spring 框架入門的一些基礎知識,包括 Spring 的概念、優點、體系結構、核心容器、依賴注入等,同時通過一個入門程式講解了 Spring 的基本使用。
通過本章的學習,讀者可以對 Spring 框架及其體系結構有一個初步的瞭解,能夠初步的掌握 Spring 框架的使用,並能夠理 Spring 框架中 IoC 和 DI 的思想,掌握屬性 setter 方法注入的實現。
本章作業
請簡述 Spring 框架的優點。
請簡述什麼是 Spring 的 IoC 和 DI。