一、Spring簡介
1、Spring介紹
Spring 是一款主流的 Java EE 輕量級開源框架 ,Spring 由“Spring 之父”Rod Johnson 提出并創立,其目的是用于簡化 Java 企業級應用的開發難度和開發周期,Spring的用途不僅限于服務器端的開發,從簡單性、可測驗性和松耦合的角度而言,任何Java應用都可以從Spring中受益,Spring 框架除了自己提供功能外,還提供整合其他技術和框架的能力,
Spring 自誕生以來備受青睞,一直被廣大開發人員作為 Java 企業級應用程式開發的首選,時至今日,Spring 儼然成為了 Java EE 代名詞,成為了構建 Java EE 應用的事實標準,
官網:https://spring.io/
2、使用Spring的原因
官方解釋:https://spring.io/why-spring
Spring使Java編程對每個人來說更快、更容易、更安全, Spring對速度、簡單性和生產率的關注使它成為世界上最流行的Java框架, spring給整個行業帶來等了春天,為我們軟體的開發帶來了極大的便利,
參考:snyk發布的2021年JVM 生態系統報告(2022年的還沒有發布)

Java 世界仍然是 Spring 主導的世界,超過一半的市場使用 Spring Boot,幾乎三分之一使用 Spring MVC,總的來說,我們看到我們生活在一個高度由 Spring 主導的宇宙中,這似乎表明 Spring 的人們在為社區服務方面做得很好,
- Spring is everywhere
Spring 框架提供靈活的類別庫受到世界各地開發人員的信任,無論是流媒體電視、在線購物、還是無數其他創新的解決方案,Spring每天都為數百萬終端用戶提供愉快的體驗,Spring也有來自所有科技巨頭的貢獻,包括阿里巴巴、亞馬遜、谷歌、微軟等,
- Spring is flexible
Spring 靈活而全面的擴展能力和第三方庫讓開發人員可以構建幾乎任何可以想象到的應用程式, Spring框架的控制反轉(IoC)和依賴注入(DI)特性為一系列廣泛的特性和功能提供了基礎, 無論您是在為web構建安全的、回應式的、基于云的微服務,還是為企業構建復雜的流資料流,Spring都有工具可以提供幫助,
- Spring is productive
Spring Boot 改變了您處理Java編程任務的方式,從根本上簡化了您的體驗, Spring Boot結合了應用程式背景關系和自動配置的嵌入式web服務器等必要條件,使microservice開發變得輕而易舉, 為了更快,您可以將Spring Boot與Spring Cloud豐富的支持庫、服務器、模式和模板組合在一起,以創紀錄的時間將整個基于微服務的架構安全地部署到云中,
- Spring is fast
我們的工程師非常關心性能, 在Spring中,默認情況下,您會注意到快速啟動、快速關閉和優化執行, Spring專案也越來越多地支持reactive(nonblocking)編程模型,以獲得更高的效率, 開發人員的生產力是Spring的超級力量, Spring Boot幫助開發人員輕松地構建應用程式,而且比其他競爭范式要輕松得多,
- Spring is secure
Spring在處理安全問題方面十分可靠, Spring代碼的貢獻者與安全專業人員一起修補和測驗任何報告的漏洞, 第三方依賴關系也被密切監控,并定期發布更新,以幫助您的資料和應用程式盡可能安全, 此外,Spring Security使您更容易集成行業標準的安全方案,并交付可靠的默認安全解決方案,
- Spring is supportive
Spring社區是一個龐大的、全球性的、多樣化的社區,涵蓋了所有年齡和能力的人,從完全的初學者到經驗豐富的專業人士, 無論你處在人生的哪個階段,你都能找到幫助你進入下一個階段的支持和資源,
3、Spring提供的功能

總結:Spring發展到現在已經不再是一個單純的應用框架,而是逐漸發展成為一個由多個不同子專案(模塊)組成的成熟技術,例如 Spring Framework、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,
Spring提供的所有專案組成:https://spring.io/projects
這些子專案涵蓋了從企業級應用開發到云計算等各方面的內容,能夠幫助開發人員解決軟體發展程序中不斷產生的各種實際問題,給開發人員帶來了更好的開發體驗,
Spring Framework 是其它子專案的基礎,可以理解成 Spring 的專案也只是在 Spring Framework 的基礎上對其進行擴展實作的,故我們也稱 Spring Framework 為 Spring 框架,框架本身的好處是重用性,其它專案不用重復開發Spring Framework已經實作的功能,對其添磚加瓦,形成自己特色的專案就好,
而且我們所說的Spring MVC其實也屬于Spring Framework核心專案之一;只是因為使用頻率最高且強調web功能,所以我們會拆出來成為Spring MVC 框架,
4、Spring Framework組成
官網介紹:https://spring.io/projects/spring-framework#overview


上圖中包含了 Spring 框架的所有模塊,這些模塊可以滿足一切企業級應用開發的需求,在開發程序中可以根據需求有選擇性地使用所需要的模塊,下面分別對這些模塊的作用進行簡單介紹,
- Spring Core(核心容器)
spring core提供了IOC,DI,Bean配置裝載創建的核心實作,核心概念: Beans、BeanFactory、、ApplicationContext,
- spring-core :IOC和DI的基本實作
- spring-beans:BeanFactory和Bean的裝配管理(BeanFactory)
- spring-context:Spring context背景關系,即IOC容器(AppliactionContext)
- spring-expression:spring運算式語言
- Spring AOP
- spring-aop:面向切面編程的應用模塊,整合ASM,CGLib,JDK Proxy
- spring-aspects:集成AspectJ,AOP應用框架
- spring-instrument:動態Class Loading模塊
- Spring Data Access
- spring-jdbc:spring對JDBC的封裝,用于簡化jdbc操作
- spring-orm:java物件與資料庫資料的映射框架
- spring-oxm:物件與xml檔案的映射框架
- spring-jms: Spring對Java Message Service(java訊息服務)的封裝,用于服務之間相互通信
- spring-tx:spring jdbc事務管理
- Spring Web
- spring-web:最基礎的web支持,建立于spring-context之上,通過servlet或listener來初始化IOC容器
- spring-webmvc:實作web mvc
- spring-websocket:與前端的全雙工通信協議
- spring-webflux:Spring 5.0提供的,用于取代傳統java servlet,非阻塞式Reactive Web框架,異步,非阻塞,事件驅動的服務,Netty,Undertow和Servlet 3.1+容器等服務器上運行
- Spring Message
- Spring-messaging:spring 4.0提供的,為Spring集成一些基礎的報文傳送服務
- Spring test
- spring-test:集成測驗支持,主要是對junit的封裝
5、Spring Framework特點
- 非侵入式:使用 Spring Framework 開發應用程式時,Spring 對應用程式本身的結構影響非常小,對領域模型可以做到零污染;對功能性組件也只需要使用幾個簡單的注解進行標記,完全不會破壞原有結構,反而能將組件結構進一步簡化,這就使得基于 Spring Framework 開發應用程式時結構清晰、簡潔優雅,
- 控制反轉:IoC——Inversion of Control,翻轉資源獲取方向,把自己創建資源、向環境索取資源變成環境將資源準備好,我們享受資源注入,
- 面向切面編程:AOP——Aspect Oriented Programming,在不修改源代碼的基礎上增強代碼功能,
- 容器:Spring IoC 是一個容器,因為它包含并且管理組件物件的生命周期,組件享受到了容器化的管理,替程式員屏蔽了組件創建程序中的大量細節,極大的降低了使用門檻,大幅度提高了開發效率,
- 組件化:Spring 實作了使用簡單的組件配置組合成一個復雜的應用,在 Spring 中可以使用 XML 和 Java 注解組合這些物件,這使得我們可以基于一個個功能明確、邊界清晰的組件有條不紊的搭建超大型復雜應用系統,
- 一站式:在 IoC 和 AOP 的基礎上可以整合各種企業應用的開源框架和優秀的第三方類別庫,而且 Spring 旗下的專案已經覆寫了廣泛領域,很多方面的功能性需求可以在 Spring Framework 的基礎上全部使用 Spring 來實作,
Spring框架版本:Spring6要求JDK最低版本是JDK17
二、IoC概述
1、背景介紹
介紹IOC之前我們先對其背景進行介紹,也即物件的創建史!
1) 普通new實體
在實際專案設計程序中,介面是一個重要組成元素,不同層之間的操作需要通過介面來呼叫,利用介面,可以實作子類的隱藏,也可以更好地描述不同層之間的操作標準,Java中要想獲得介面物件,需要通過關鍵字new來實作,下面的案例不要研究其業務意義,只是一個測驗demo!
public interface ConnectionMessage {
public String select();
}
public class MySQLMessageImpl implements ConnectionMessage {
@Override
public String select() {
System.out.println("連接---查詢MySQL資料庫資訊");
return "";
}
}
public class MyTest {
public static void main(String[] args) {
ConnectionMessage message = new MySQLMessageImpl();
message.select();
}
}

以上是使用MySQL操作的模擬程式,如果切換為PostgreSQL就需要修改其使用類!
public class MyTest {
public static void main(String[] args) {
//ConnectionMessage message = new MySQLMessageImpl();
ConnectionMessage message = new PostgreSQLMessageImpl();
message.select();
}
}

這就是所謂的耦合,呼叫的時候要修改代碼,即直接new , 顯然不符合面向物件的設計原則---------開閉原則
2.1)普通工廠
針對上面的情況我們可以使用工廠方式,創建一個BeanFactory.java檔案
public class BeanFactory {
public static ConnectionMessage select(){
return new MySQLMessageImpl();
}
}
這樣使用的時候就變成下面這樣
public class MyTest {
public static void main(String[] args) {
// ConnectionMessage message = new MySQLMessageImpl();
// ConnectionMessage message = new PostgreSQLMessageImpl();
ConnectionMessage message = BeanFactory.select();
message.select();
}
}

上圖的思想沒問題,但是我們的代碼還尚有問題,即BeanFactory里面還是有代碼耦合

2.2)反射工廠1.0
我們接下來可以利用反射完善一下!
public class BeanFactory {
private static ConnectionMessage message;
public static ConnectionMessage select() throws Exception {
Class<?> clazz = Class.forName("com.ty.demo.dao.impl.MySQLMessageImpl");
message = (MySQLMessageImpl) clazz.getDeclaredConstructor().newInstance();
return message;
}
}
這樣比直接new好多了,減少了工廠內獲取物件的耦合,但是獲取類限定名的時候還是需要進行修改!

2.3)反射工廠2.0
下面我們可以用properties屬性組態檔存盤檔案限定名,把具體的類限定名和代碼相分離,未來只需要修改此組態檔即可!

public class BeanFactory {
private static ConnectionMessage message;
//創建Properties物件來加載properties屬性組態檔
private static Properties environment = new Properties();
private static InputStream resource;
static {
//加載bean.properties組態檔
resource = BeanFactory.class.getResourceAsStream("/bean.properties");
try {
environment.load(resource);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static ConnectionMessage select() throws Exception {
Class<?> clazz = Class.forName(environment.getProperty("mysqlMessage"));
message = (MySQLMessageImpl) clazz.getDeclaredConstructor().newInstance();
return message;
}
}
2.3)通用工廠
上面我們的工廠方法基本設計完成了,但是還有點小問題,那就是每次都需要在BeanFactory工廠類寫一個與其對應的物件創建工廠方法,這時我們設計一個通用的工廠方法
public class BeanFactory {
//創建Properties物件來加載properties屬性組態檔
private static Properties environment = new Properties();
private static InputStream resource;
static {
//加載bean.properties組態檔
resource = BeanFactory.class.getResourceAsStream("/bean.properties");
try {
environment.load(resource);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* @param key 組態檔對應的mysqlMessage和postgresqlMessage
* @return
*/
public static Object getBean(String key) {
Object returnedObject = null;
try {
Class<?> clazz = Class.forName(environment.getProperty(key));
returnedObject = clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return returnedObject;
}
}

一個通用工廠就完成了,但是這種方式你還需要先自己提供工廠類和方法,我們如果用Spring的話,工廠類不用我們手動實作,Spring提供了工廠,使我們可以將更多精力放在核心代碼的開發處理上,
2、IoC---控制反轉
簡介:控制反轉(Inversion of Control,縮寫為IoC),它不是一門技術,而是面向物件編程中的一種設計思想,可以用來降低代碼之間的耦合度,能夠指導我們如何設計出松耦合、更優良的程式,
核心: 將物件的創建權交出去,將物件和物件之間關系的管理權交出去,由第三方容器來負責創建與維護 ,
目標:降低程式耦合度,提高程式擴展力
控制反轉,反轉的是什么?
- 將物件的創建權利交出去,即不在程式中采用硬編碼的方式來new物件,而是交給第三方容器負責
- 將物件和物件之間關系的維護權交出去,交給第三方容器負責
實作方式:依賴注入(Dependency Injection)與依賴查找(Dependency Lookup)
- 依賴注入:Spring創建物件的程序中,將物件依賴屬性通過配置進行注入,常見的實作方式:
- set注入
- 構造注入
總結:
- IOC 就是一種控制反轉的思想, 而 DI 是對IoC的一種具體實作
- Bean管理:Bean物件的創建,以及Bean物件中屬性的賦值(或者叫做Bean物件之間關系的維護)
相關名詞
容器:可以管理物件的生命周期、物件與物件之間的依賴關系
物體類:
- POJO(Plain Old Java Object):是Martin Fowler、Rebecca Parsons和Josh MacKenzie在2000年的一次演講的時候提出來的,按照Martin Fowler的解釋是“Plain Old Java Object”,從字面上翻譯為“純潔老式的Java物件”,但大家都使用“簡單java物件”來稱呼它,POJO的內在含義是指:那些沒有繼承任何類、也沒有實作任何介面,更沒有被其它框架侵入的java物件,不允許有業務方法,也不能攜帶connection之類的方法,實際就是普通JavaBeans,
- JavaBean:是一種JAVA語言寫成的可重用組件,JavaBean符合一定規范撰寫的Java類,不是一種技術,而是一種規范,大家針對這種規范,總結了很多開發技巧、工具函式,符合這種規范的類,可以被其它的程式員或者框架使用,它的方法命名,構造及行為必須符合特定的約定:
1、所有屬性為private,
2、這個類必須有一個公共的預設建構式,即是提供無引數的構造器,
3、這個類的屬性使用getter和setter來訪問,其他方法遵從標準命名規范,
4、這個類應是可序列化的,實作serializable介面,
因為這些要求主要是靠約定而不是靠實作介面,所以許多開發者把JavaBean看作遵從特定命名約定的POJO,
POJO與JavaBean的區別:
| POJO | JavaBean | |
|---|---|---|
| 權限控制 | 沒有對成員提供太多控制 | 提供對成員的完全控制 |
| 可序列化 | 可以實作 | 應該實作 |
| 欄位訪問 | 具有任何可見性,可以直接訪問 | 欄位只有私人可見性,只能由getter和setter訪問 |
| 無參構造 | 可以沒有 | 必須具有 |
| 使用場景 | 當您不想限制成員并讓用戶完全訪問您的物體時使用它 | 當您要向用戶提供您的物體,但僅向物體的一部分提供服務時,將使用它 |
POJO類和Bean均用于定義Java物件,以提高其可讀性和可重用性,POJO沒有其他限制,而bean是具有某些限制的特殊POJO,
- SpringBean:受Spring管理的物件,所有能受Spring容器管理的物件都可以成為SpringBean,Spring中的bean,是通過組態檔、javaconfig等的設定,由Spring自動實體化,用完后自動銷毀的物件,
SpringBean和JavaBean的區別:
| JavaBean | SpringBean | |
|---|---|---|
| 用處不同 | 更多地作為值傳遞引數 | 用處幾乎無處不在,任何組件都可以被稱為bean |
| 寫法不同 | 作為值物件,要求每個屬性都提供getter和setter方法 | 只需為接受設值注入的屬性提供setter方法 |
| 生命周期不同 | 傳統javabean作為值物件傳遞,不接受任何容器管理其生命周期 | spring管理其生命周期行為 |
Entity Bean:是域模型物件,用于實作O/R映射,負責將資料庫中的表記錄映射為記憶體中的Entity物件,事實上,創建一個Entity Bean物件相當于新建一條記錄,洗掉一個 Entity Bean會同時從資料庫中洗掉對應記錄,修改一個Entity Bean時,容器會自動將Entity Bean的狀態和資料庫同步,
三、入門程式
1、引入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.4</version>
</dependency>
當引入Spring-webmvc依賴之后,表示將Spring的基礎依賴也一起引入了

有的教程可能引得是spring-context依賴,此依賴是除了web部分其余的基礎依賴都會引進來,它們一般是在Spring MVC的時候再引入spring-webmvc依賴,
2、創建java類
public class HelloWorld {
public void sayHello(){
System.out.println("hello world");
}
}
3、創建組態檔
在resources目錄創建一個 Spring 組態檔 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">
<!--
配置HelloWorld所對應的bean,表示將HelloWorld的物件交給Spring的IOC容器管理
通過bean標簽配置IOC容器所管理的bean
屬性:
id:設定bean的唯一標識
class:設定bean所對應型別的全限定名
-->
<bean id="hello" ></bean>
</beans>
4、測驗程式
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
context.getBean("hello", HelloWorld.class).sayHello();
}
}
5、簡單分析
這里我們這是簡單介紹一下基本原理,Spring整個Bean的創建程序很復雜,之后再一點點介紹!
- 底層利用通過反射機制呼叫無引數構造方法


- Spring創建物件就像之前我們使用Properties的步驟類似,它使用的是dom4j決議beans.xml檔案,從中獲取class屬性值,類的全類名;然后通過反射機制呼叫無引數構造方法創建物件
Class.forName("com.ty.demo.bean.HelloWorld").getDeclaredConstructor().newInstance()
- 創建好的物件存盤在ConcurrentHashMap中
bean物件最終存盤在spring容器中,在spring原始碼底層就是一個map集合,存盤bean的map在DefaultListableBeanFactory類中:

Spring容器加載到Bean類時 , 會把這個類的描述資訊, 以包名加類名的方式存到beanDefinitionMap 中,
Map<String,BeanDefinition>
- 其中 String是Key , 默認是類名首字母小寫 ,
- BeanDefinition , 存的是類的定義(描述資訊) ,
- 我們通常叫BeanDefinition介面為 : bean的定義物件,
6、SpringTest測驗
前面通過ApplicationContext啟動了Spring容器,并實作了組態檔的加載,但這樣處理并不能體現出Spring的運行特征,為了更好地還原現實的開發場景,可利用SpringTest依賴庫和JUnit實作測驗環境下的Spring容器啟動,且可以使用@Autowired代替getBean方法實作自動注入,
引入依賴
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.0.4</version>
</dependency>
測驗程式
@ContextConfiguration(locations = {"classpath:bean.xml"})
@ExtendWith(SpringExtension.class)
public class MyTest {
@Autowired
private HelloWorld helloWorld;
@Test
void testHelloWorld() {
helloWorld.sayHello();
}
}
- @ContextConfiguration:表示Spring組態檔所在的目錄,本程式通過classpath進行加載,由于src/main/resources屬于源目錄,所以目錄中保存的所有資源將自動設定在CLASSPATH之中
- @ExtendWith(SpringExtension.class):表示要使用的測驗工具型別,
- @Autowired:自動注入
7、整合logback日志
在專案開發中,日志十分的重要,不管是記錄運行情況還是定位線上問題,都離不開對日志的分析,日志記錄了系統行為的時間、地點、狀態等相關資訊,能夠幫助我們了解并監控系統狀態,在發生錯誤或者接近某種危險狀態時能夠及時提醒我們處理,同時在系統產生問題時,能夠幫助我們快速的定位、診斷并解決問題,
引入依賴
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
<scope>test</scope>
</dependency>
測驗程式


出處:https://www.cnblogs.com/hanyu-2020/
---------------------------------------------------------
個性簽名:獨學而無友,則孤陋而寡聞,做一個靈魂有趣的人!
如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,博主在此感謝!
本文內容若有疏漏請多多包涵,如有錯誤麻煩請指正,如有想法交流非常歡迎在下方評論!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542677.html
標籤:Java
上一篇:day15-宣告式事務
