此筆記由孫哥的視訊整理而來
作者: Wyt
孫哥B站視訊連結如下:
孫哥說Spring5 全部更新完畢 完整筆記、程式碼看置頂評論連結~學不會Spring? 因為你沒找對人
存在的問題:
1. 執行環境苛刻
2. 程式碼移植性差
Spring是分層的 Java SE/EE應用 full-stack 輕量級開源框架,以 IOC(Inverse Of Control:反轉控制)和 AOP(Aspect Oriented Programming:面向切面程式設計)為核心。
優勢
1. 方便解耦,簡化開發
2. AOP程式設計的支援
3. 宣告式事物的支援
4. 方便程式的測試
輕量級
1. 對於執行環境是沒有額外要求的
開源 tomcat resion jetty
收費 weblogic websphere
2. 程式碼移植性高
不需要實現額外介面
1. 工廠
2. 代理
3. 模板
4. 策略
1. 廣義概念
物件導向設計中,解決特定問題的經典程式碼
2. 狹義概念
GOF4人幫定義的23種設計模式:工廠、介面卡、裝飾器、門面、代理、模板...
1. javase基礎
2. mysql的基本操作
3. 瞭解jdbc
4. maven
1. JDK
2. Maven
3. IDEA
Spring官方網站: www.spring.io
Maven包名
src
main
java: 用來存放專案主要的程式碼: .java
resouce: 存放組態檔: .xml .propertise
test: 存放測試類: .java
target: 存放依賴: .jar
pom.xml: 物件模型(Project Object Model)管理檔案
包名.iml: IDEA生成的對Module的設定資訊
1. 一般在resouce資料夾新建applicationContext.xml
用於管理bean物件,aop設定等
(理論上可以任意命名,放在任意位置)
2. 使用時:
ApplicationContext ctx = new
ClassPathXmlApplicationContext("/applicationContext.xml");
1. bean:
Spring容器作為超級大工廠,負責建立、管理所有的Java物件,這些Java物件被稱為Bean。
在applicationContext.xml中,
用<bean id="###" class="相對位置">, 引入某個類並賦值id(唯一), 其他`屬性有如name(別名)等
2. 依賴管理:
2.1 Spring容器管理容器中Bean之間的依賴關係,Spring使用一種被稱為「依賴注入」的方式來管理Bean之間的依賴關係。
2.2 使用依賴注入,不僅可以為Bean注入普通的屬性值,還可以注入其他Bean的參照。依賴注入是一種優秀的解耦方式,其可以讓Bean以組態檔組織在一起,而不是以寫死的方式耦合在一起。
https://www.runoob.com/maven/maven-manage-dependencies.html
3. 反射
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
1. 設定pom.xml
2. 建立java類物件
3. 設定applicationContext.xml
4. 新增測試程式碼並執行
詳細步驟:
1. 設定pom.xml, 指定編碼格式和JDK版本
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
">
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.complier.source>15</maven.complier.source>
<maven.complier.target>15</maven.complier.target>
</properties>
2. 在pom.xml中引入相關依賴
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependencies>
3. 建立java類物件
在main.java建立com.hello.HelloWorld.java
新增方法
public void hey() {
System.out.println("HelloWorld");
}
4. 在resource建立applicationContext.xml
建立bean
<bean id="helloworld" class="com.hello.helloworld"/>
5. 在test新建測試類Test01.java
類中新增測試方法:
//import org.junit.Test
@Test
public void test01() {
//獲取工廠物件
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//根據xml中bean的id,獲取bean物件(強制型別轉換)
HelloWorld hello = (HelloWorld) ctx.getBean("helloworld");
//HelloWorld hello = ctx.getBean("helloworld", HelloWord.class);
//呼叫HelloWorld的成員方法
hello.hey();
}
//通過這種方式獲得物件,就不需要強制型別轉換
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
//當前Spring的組態檔中 只能有一個<bean class是Person型別
Person person = ctx.getBean(Person.class);
System.out.println("person = " + person);
//獲取的是 Spring工廠組態檔中所有bean標籤的id值 person person1
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = " + beanDefinitionName);
}
//根據型別獲得Spring組態檔中對應的id值
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String id : beanNamesForType) {
System.out.println("id = " + id);
}
//用於判斷是否存在指定id值得bean
if (ctx.containsBeanDefinition("a")) {
System.out.println("true = " + true);
}else{
System.out.println("false = " + false);
}
//用於判斷是否存在指定id值得bean
if (ctx.containsBean("person")) {
System.out.println("true = " + true);
}else{
System.out.println("false = " + false);
}
1. 只設定class屬性
<bean class="com.baizhiedu.basic.Person"/>
a) 上述這種設定 有沒有id值 com.baizhiedu.basic.Person#0
b) 應用場景: 如果這個bean只需要使用一次,那麼就可以省略id值
如果這個bean會使用多次,或者被其他bean參照則需要設定id值
2. name屬性
作用:用於在Spring的組態檔中,為bean物件定義別名(小名)
相同:
1. ctx.getBean("id|name")-->object
2. <bean id="" class=""
等效
<bean name="" class=""
區別:
1. 別名可以定義多個,但是id屬性只能有一個值
2. XML的id屬性的值,命名要求:必須以字母開頭,字母 數位 下劃線 連字元 不能以特殊字元開頭 /person
name屬性的值,命名沒有要求 /person
name屬性會應用在特殊命名的場景下:/person (spring+struts1)
XML發展到了今天:ID屬性的限制,不存在 /person
3. 程式碼
//用於判斷是否存在指定id值得bean,不能判斷name值
if (ctx.containsBeanDefinition("person")) {
System.out.println("true = " + true);
}else{
System.out.println("false = " + false);
}
//用於判斷是否存在指定id值得bean,也可以判斷name值
if (ctx.containsBean("p")) {
System.out.println("true = " + true);
}else{
System.out.println("false = " + false);
}
* 介面型別,代表應用上下文,可以通過其範例獲得 Spring 容器中的 Bean 物件
ApplicationContext的實現類:
1. ClassPathXmlApplicationContext
它是從類的根路徑下載入組態檔 推薦使用這種
2. FileSystemXmlApplicationContext
它是從磁碟路徑上載入組態檔,組態檔可以在磁碟的任意位置。
3. AnnotationConfigApplicationContext
當使用註解設定容器物件時,需要使用此類來建立 spring 容器。它用來讀取註解。
問題:未來在開發過程中,是不是所有的物件,都會交給Spring工廠來建立呢?
回答:理論上 是的,但是有特例 :實體物件(entity)是不會交給Spring建立,它是由持久層框架進行建立。
https://www.runoob.com/design-pattern/factory-pattern.html
1. 概念:
工廠(如applicationContext.xml)中事先引入bean物件,
則我們可以通過工廠類,建立物件
上文中通過new ClassPathXmlApplicationContext()獲取工廠類
3. 好處:解耦合
耦合:指定是程式碼間的強關聯關係,一方的改變會影響到另一方
問題:不利於程式碼維護
簡單:把介面的實現類,寫死在程式中
1. 定義型別 (類)
2. 通過組態檔的設定告知工廠(applicationContext.xml)
key = value
3. 通過工廠獲得類的物件
Object ret = BeanFactory.getBean("key")
Spring與紀錄檔框架進行整合,紀錄檔框架就可以在控制檯中,輸出Spring框架執行過程中的一些重要的資訊。
好處:便於瞭解Spring框架的執行過程,利於程式的偵錯
預設
Spring1.2.3早期都是於commons-logging.jar
Spring5.x預設整合的紀錄檔框架 logback log4j2
Spring5.x整合log4j
1. 引入log4j jar包
2. 引入log4.properties組態檔
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
# resources資料夾根目錄下
### 設定根
log4j.rootLogger = debug,console
### 紀錄檔輸出到控制檯顯示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
概念:通過Spring工廠及組態檔,為所建立物件的成員變數賦值
原始方法:直接通過編碼的方式,為物件的成員變數賦值,存在耦合
<bean id="person" class="com.hello.Person">
<property name="id">
<value>01</value>
</property>
<property name="name">
<value>xiaoming</value>
</property>
</bean>
解耦合
Spring通過底層呼叫物件屬性對應的set方法,完成成員變數的賦值,這種方式我們也稱之為set注入
1. String
2. 陣列
3. Set
4. List
5. Map
6. Properties(特殊)
注入:通過Spring的組態檔,為成員變數賦值
Set注入:Spring呼叫Set方法 通過組態檔 為成員變數賦值
構造注入:Spring呼叫構造方法 通過組態檔 為成員變數賦值
public class Cat implements Serializable {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
}
<bean id="cat" class="com.hello.Cat">
<constructor-arg>
<value>Kity</value>
</constructor-arg>
<constructor-arg>
<value>2</value>
</constructor-arg>
</bean>
通過控制<constructor-arg>標籤的數量進行區分
通過在標籤引入 type屬性 進行型別的區分 <constructor-arg type="">
1. 構造注入需要過載,操作麻煩
2. Spring框架底層, 大量應用了 set注入
總結:set注入應用更多
1. 控制:對於成員變數賦值的控制權
2. 反轉控制:把對於成員變數賦值的控制權,從程式碼中反轉(轉移)到Spring工廠和組態檔中完成 (注入)
3. 好處:解耦合,
即如需對成員變數賦值, 在組態檔操作, 而不是在程式碼中操作
減少了直接對程式碼的操作
4. 底層實現:工廠設計模式
1. 依賴注入:通過Spring的工廠及組態檔,為物件(bean,元件)的成員變數賦值
2. 依賴注入:當一個類需要另一個類時,就意味著依賴,一旦出現依賴,就可以把另一 個類作為本類的成員變數,最終通過Spring組態檔進行注入(賦值)。
3. 好處:解耦合
Rod Johnson是第一個高度重視以組態檔來管理Java範例的共同作業關係的人,他給這種方式起了一個名字:控制反轉(Inverse of Control,IoC)。後來Martine Fowler為這種方式起了另一個名稱:依賴注入(Dependency Injection),因此不管是依賴注入,還是控制反轉,其含義完全相同。當某個Java物件(呼叫者)需要呼叫另一個Java物件(被依賴物件)的方法時,在傳統模式下通常有兩種做法:
1. 原始做法: 呼叫者主動建立被依賴物件,然後再呼叫被依賴物件的方法;
2. 簡單工廠模式: 呼叫者先找到被依賴物件的工廠,然後主動通過工廠去獲取被依賴物件,最後再呼叫被依賴物件的方法。
注意上面的主動二字,這必然會導致呼叫者與被依賴物件實現類的寫死耦合,非常不利於專案升級的維護。使用Spring框架之後,呼叫者無需主動獲取被依賴物件,呼叫者只要被動接受Spring容器為呼叫者的成員變數賦值即可,由此可見,使用Spring後,呼叫者獲取被依賴物件的方式由原來的主動獲取,變成了被動接受——所以Rod Johnson稱之為控制反轉。
另外從Spring容器的角度來看,Spring容器負責將被依賴物件賦值給呼叫者的成員變數——相當於為呼叫者注入它依賴的範例,因此Martine Fowler稱之為依賴注入。
在java中,不能通過new關鍵字建立的物件,都稱為複雜物件,如抽象類(abstract,例如Calendar日期類)、介面(interface,JDBC中的Connection連線類)。
2. Spring組態檔的設定
# 如果Class中指定的型別 是FactoryBean介面的實現類,那麼通過id值獲得的是這個類所建立的複雜物件 Connection
<bean id="conn" class="com.baizhiedu.factorybean.ConnectionFactoryBean"/>
細節
- 如果就想獲得FactoryBean型別的物件 ctx.getBean("&conn")
獲得就是ConnectionFactoryBean物件
- isSingleton方法
返回 true 只會建立一個複雜物件
返回 false 每一次都會建立新的物件
問題:根據這個物件的特點 ,決定是返回true (SqlSessionFactory) 還是 false (Connection)
- mysql高版本連線建立時,需要制定SSL證書,解決問題的方式
url = "jdbc:mysql://localhost:3306/suns?useSSL=false"
- 依賴注入的體會(DI)
把ConnectionFactoryBean中依賴的4個字串資訊 ,進行組態檔的注入
好處:解耦合
<bean id="conn" class="com.baizhiedu.factorybean.ConnectionFactoryBean">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
- Spring中用於建立複雜物件的一種方式,也是Spring原生提供的,後續講解Spring整合其他框架,大量應用FactoryBean
* 工廠在構造方法初始化時,會將類進行範例化放在工廠中
1. 避免Spring框架的侵入
2. 整合遺留系統
<bean id="connFactory" class="com.hello.factorybean.ConnectionFactory"></bean>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
* 工廠初始化之前,工廠中的類已經被範例化放在工廠容器中
public class StaticConnectionFactory {
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/資料庫名稱?useSSL=false", "root", "123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
}
<bean id="conn" class="com.hello.factorybean.StaticConnectionFactory" factory-method="getConnection"/>
1. 功能:控制簡單物件的建立次數
2. 常用選項:
sigleton:只會建立一次簡單物件 預設值
prototype:每一次都會建立新的物件
3. 使用: 在.xml組態檔中對bean物件操作
<bean id="account" scope="singleton|prototype" class="xxxx.Account"/>
* 在物件中新增成員方法
FactoryBean{
isSingleton(){
return true 只會建立一次
return false 每一次都會建立新的
}
}
* 如沒有isSingleton方法 還是通過scope屬性 進行物件建立次數的控制
* 好處:節省不別要的記憶體浪費
什麼樣的物件只建立一次?
1. SqlSessionFactory
2. DAO
3. Service
什麼樣的物件 每一次都要建立新的?
1. Connection
2. SqlSession | Session
3. Struts2 Action
<?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">
</beans>
1. ApplicationContext的繼承體系
applicationContext:介面型別,代表應用上下文,可以通過其範例獲得 Spring 容器中的 Bean 物件
2. ApplicationContext的實現類
1)ClassPathXmlApplicationContext
它是從類的根路徑下載入組態檔 推薦使用這種
2)FileSystemXmlApplicationContext
它是從磁碟路徑上載入組態檔,組態檔可以在磁碟的任意位置。
3)AnnotationConfigApplicationContext
當使用註解設定容器物件時,需要使用此類來建立 spring 容器。它用來讀取註解。
把Spring組態檔中需要經常修改的字串資訊,轉移到一個更小的組態檔中
1. Spring的組態檔中存在需要經常修改的字串?
存在 以資料庫連線相關的引數 代表
2. 經常變化字串,在Spring的組態檔中,直接修改
不利於專案維護(修改)
3. 轉移到一個小的組態檔(.properties)
利於維護(修改)
組態檔引數化:利於Spring組態檔的維護(修改)
名字:隨便 (jdbc.properties)
放置位置:隨便 (resources資料夾下)
以鍵值對方式書寫: key=value
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/suns?useSSL=false
jdbc.username = root
jdbc.password = 123456
1. <beans>屬性中加入
xmlns:context="http://www.springframework.org/schema/context"
2. <beans>屬性選項xsi:schemaLocation中加入
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
3. 載入jdbc.properties
<context:property-placeholder location="classpath:/jdbc.properties"/>
4. 設定資料來源物件
<bean id="conn" class="com.wyt.factorybean.ConnectionFactoryBean">
<propertise name="key1" value="value1"/>
<propertise name="key2" value="value2"/>
...
</bean>