第一章 初識Spring
1.1 Spring簡介
-
Spring是一個為簡化企業級開發而生的開源框架,
-
Spring是一個IOC(DI)和AOP容器框架,
-
IOC全稱:Inversion of Control【控制反轉】
- 將物件【萬物皆物件】控制權交個Spring
-
DI全稱:(Dependency Injection):依賴注入
-
AOP全稱:Aspect-Oriented Programming,面向切面編程
-
官網:https://spring.io/
1.2 搭建Spring框架步驟
-
匯入jar包
<!--匯入spring-context--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.1</version> </dependency> <!--匯入junit4.12--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> -
撰寫核心組態檔
-
組態檔名稱:applicationContext.xml【beans.xml或spring.xml】
-
組態檔路徑:src/main/resources
-
示例代碼
<?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"> <!-- 將物件裝配到IOC容器中--> <bean id="stuZhenzhong" > <property name="stuId" value="https://www.cnblogs.com/ygstudy/p/101"></property> <property name="stuName" value="https://www.cnblogs.com/ygstudy/p/zhenzhong"></property> </bean> </beans>
-
-
使用核心類別庫
@Test public void testSpring(){ //使用Spring之前 // Student student = new Student(); //使用Spring之后 //創建容器物件 ApplicationContext iocObj = new ClassPathXmlApplicationContext("applicationContext.xml"); //通過容器物件,獲取需要物件 Student stuZhenzhong = (Student)iocObj.getBean("stuZhenzhong"); System.out.println("stuZhenzhong = " + stuZhenzhong); }
1.3 Spring特性
- 非侵入式:基于Spring開發的應用中的物件可以不依賴于Spring的API,
- 容器:Spring是一個容器,因為它包含并且管理應用物件的生命周期,
- 組件化:Spring實作了使用簡單的組件配置組合成一個復雜的應用,在 Spring 中可以使用XML和Java注解組合這些物件,
- 一站式:在IOC和AOP的基礎上可以整合各種企業應用的開源框架和優秀的第三方類別庫(實際上Spring 自身也提供了表述層的SpringMVC和持久層的JDBCTemplate),
1.4 Spring中getBean()三種方式
-
getBean(String beanId):通過beanId獲取物件
- 不足:需要強制型別轉換,不靈活
-
getBean(Class clazz):通過Class方式獲取物件
-
不足:容器中有多個相同型別bean的時候,會報如下錯誤:
expected single matching bean but found 2: stuZhenzhong,stuZhouxu
-
-
getBean(String beanId,Clazz clazz):通過beanId和Class獲取物件
- 推薦使用
注意:框架默認都是通過無參構造器,幫助我們創建物件,
? 所以:如提供物件的構造器時,一定添加無參構造器
1.5 bean標簽詳解
- 屬性
- id:bean的唯一標識
- class:定義bean的型別【class全類名】
- 子標簽
- property:為物件中屬性賦值【set注入】
- name屬性:設定屬性名稱
- value屬性:設定屬性數值
- property:為物件中屬性賦值【set注入】
day06
第二章 SpringIOC底層實作
IOC:將物件的控制器反轉給Spring
2.1 BeanFactory與ApplicationContexet
- BeanFactory:IOC容器的基本實作,是Spring內部的使用介面,是面向Spring本身的,不是提供給開發人員使用的,****
- ApplicationContext:BeanFactory的子介面,提供了更多高級特性,面向Spring的使用者,幾乎所有場合都使用ApplicationContext而不是底層的BeanFactory,
2.2 圖解IOC類的結構

- BeanFactory:Spring底層IOC實作【面向Spring框架】
- ...
- ApplicationContext:面向程式員
- ConfigurableApplicationContext:提供關倍訓重繪容器物件方法
- ...
- ClassPathXmlApplicationContext:基于類路徑檢索xml檔案
- AnnotationConfigApplicationContext:基于注解創建容器物件
- FileSystemXmlApplicationContext:基于檔案系統檢索xml檔案
- ...
- ConfigurableApplicationContext:提供關倍訓重繪容器物件方法
- ApplicationContext:面向程式員
- ...
第三章 Spring依賴注入數值問題【重點】
3.1 字面量數值
- 資料型別:基本資料型別及包裝類、String
- 語法:value屬性或value標簽
3.2 CDATA區
- 語法:<![CDATA[]]>
- 作用:在xml中定義特殊字符時,使用CDATA區
3.3 外部已宣告bean及級聯屬性賦值
-
語法:ref
-
注意:級聯屬性更改數值會影響外部宣告bean【ref賦值的是參考】
-
示例代碼
<bean id="dept1" > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/1"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/研發部門"></property> </bean> <bean id="empChai" > <property name="id" value="https://www.cnblogs.com/ygstudy/p/101"></property> <property name="lastName" value="https://www.cnblogs.com/ygstudy/p/chai"></property> <property name="email" value="https://www.cnblogs.com/ygstudy/p/[email protected]"></property> <property name="salary" value="https://www.cnblogs.com/ygstudy/p/50.5"></property> <property name="dept" ref="dept1"></property> <property name="dept.deptName" value="https://www.cnblogs.com/ygstudy/p/財務部門"></property> </bean>

3.4 內部bean
-
概述
- 內部類:在一個類中完整定義另一個類,當前類稱之為內部類
- 內部bean:在一個bean中完整定義另一個bean,當前bean稱之為內部bean
-
注意:內部bean不會直接裝配到IOC容器中
-
示例代碼
<!-- 測驗內部bean--> <bean id="empXin" > <property name="id" value="https://www.cnblogs.com/ygstudy/p/102"></property> <property name="lastName" value="https://www.cnblogs.com/ygstudy/p/xx"></property> <property name="email" value="https://www.cnblogs.com/ygstudy/p/[email protected]"></property> <property name="salary" value="https://www.cnblogs.com/ygstudy/p/51.5"></property> <property name="dept"> <bean > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/2"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/人事部門"></property> </bean> </property> </bean>
3.5 集合
-
List
<!-- 測驗集合--> <bean id="dept3" > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/3"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/程式員鼓勵師"></property> <property name="empList"> <list> <ref bean="empChai"></ref> <ref bean="empXin"></ref> <!-- <bean></bean>--> </list> </property> </bean> <!-- 測驗提取List--> <util:list id="empList"> <ref bean="empChai"></ref> <ref bean="empXin"></ref> </util:list> <bean id="dept4" > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/4"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/運營部門"></property> <property name="empList" ref="empList"></property> </bean> -
Map
<!-- 測驗Map--> <bean id="dept5" > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/5"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/采購部門"></property> <property name="empMap"> <map> <entry key="101" value-ref="empChai"></entry> <entry> <key><value>103</value></key> <ref bean="empChai"></ref> </entry> <entry> <key><value>102</value></key> <ref bean="empXin"></ref> </entry> </map> </property> </bean> <util:map id="empMap"> <entry key="101" value-ref="empChai"></entry> <entry> <key><value>103</value></key> <ref bean="empChai"></ref> </entry> <entry> <key><value>102</value></key> <ref bean="empXin"></ref> </entry> </util:map> <bean id="dept6" > <property name="deptId" value="https://www.cnblogs.com/ygstudy/p/106"></property> <property name="deptName" value="https://www.cnblogs.com/ygstudy/p/后勤部門"></property> <property name="empMap" ref="empMap"></property> </bean>
第四章 Spring依賴注入方式【基于XML】
為屬性賦值方式
- 通過xxxset()方法
- 通過構造器
- 反射
4.1 set注入
- 語法:<property>
4.2 構造器注入
- 語法:<constructor-arg>
4.3 p名稱空間注入
匯入名稱空間:xmlns:p="http://www.springframework.org/schema/p"
-
語法:
-
示例代碼
<bean id="stuZhouxu" > <property name="stuId" value="https://www.cnblogs.com/ygstudy/p/102"></property> <property name="stuName"> <value><![CDATA[<<zhouxu>>]]></value> </property> </bean> <bean id="stuZhiFeng" > <constructor-arg name="stuId" value="https://www.cnblogs.com/ygstudy/p/103"></constructor-arg> <constructor-arg name="stuName" value="https://www.cnblogs.com/ygstudy/p/zhifeng"></constructor-arg> </bean> <bean id="stuXiaoxi" p:stuId="104" p:stuName="xiaoxi"></bean>
第五章 Spring管理第三方bean
5.1 Spring管理druid步驟
-
匯入jar包
<!--匯入druid的jar包--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--匯入mysql的jar包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> <!-- <version>8.0.26</version>--> </dependency> -
撰寫db.properties組態檔
#key=value db.driverClassName=com.mysql.jdbc.Driver db.url=jdbc:mysql://localhost:3306/db220106 db.username=root db.password=root -
撰寫applicationContext.xml相關代碼
<!-- 加載外部屬性檔案db.properties--> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <!-- 裝配資料源--> <bean id="dataSource" > <property name="driverClassName" value="https://www.cnblogs.com/ygstudy/p/${db.driverClassName}"></property> <property name="url" value="https://www.cnblogs.com/ygstudy/p/${db.url}"></property> <property name="username" value="https://www.cnblogs.com/ygstudy/p/${db.username}"></property> <property name="password" value="https://www.cnblogs.com/ygstudy/p/${db.password}"></property> </bean> -
測驗
@Test public void testDruidDataSource() throws Exception{ //獲取容器物件 ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext_druid.xml"); DruidDataSource dataSource = ioc.getBean("dataSource", DruidDataSource.class); System.out.println("dataSource = " + dataSource); DruidPooledConnection connection = dataSource.getConnection(); System.out.println("connection = " + connection); }
第六章 Spring中FactoryBean
6.1 Spring中兩種bean
- 一種是普通bean
- 另一種是工廠bean【FactoryBean】
- 作用:如需我們程式員引數到bean的創建時,使用FactoryBean
6.2 FactoryBean使用步驟
- 實作FactoryBean介面
- 重寫方法【三個】
- 裝配工廠bean
- 測驗
package com.atguigu.factory;
import com.atguigu.pojo.Dept;
import org.springframework.beans.factory.FactoryBean;
/**
* @author Chunsheng Zhang 尚硅谷
* @create 2022/3/26 14:09
*/
public class MyFactoryBean implements FactoryBean<Dept> {
/**
* getObject():引數物件創建的方法
* @return
* @throws Exception
*/
@Override
public Dept getObject() throws Exception {
Dept dept = new Dept(101,"研發部門");
//.....
return dept;
}
/**
* 設定引數物件Class
* @return
*/
@Override
public Class<?> getObjectType() {
return Dept.class;
}
/**
* 設定當前物件是否為單例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
第七章 Spring中bean的作用域
7.1 語法
- 在bean標簽中添加屬性:scope屬性即可
7.2 四個作用域
- singleton【默認值】:單例【在容器中只有一個物件】
- 物件創建時機:創建容器物件時,創建物件執行
- prototype:多例【在容器中有多個物件】
- 物件創建時機:getBean()方法被呼叫時,創建物件執行
- request:請求域
- 當前請求有效,離開請求域失效
- 當前請求:URL不變即為當前請求
- session:會話域
- 當前會話有效,離開當前會話失效
- 當前會話:當前瀏覽不關閉不更換即為當前會話
第八章 Spring中bean的生命周期
8.1 bean的生命周期
① 通過構造器或工廠方法創建bean實體
② 為bean的屬性設定值和對其他bean的參考
③ 呼叫bean的初始化方法
④ bean可以使用了
⑤ 當容器關閉時,呼叫bean的銷毀方法
8.2 bean的后置處理器
-
作用:在呼叫初始化方法前后對bean進行額外的處理,
-
實作:
- 實作BeanPostProcessor介面
- 重寫方法
- postProcessBeforeInitialization(Object, String):在bean的初始化之前執行
- postProcessAfterInitialization(Object, String):在bean的初始化之后執行
- 在容器中裝配后置處理器
-
注意:裝配后置處理器會為當前容器中每個bean均裝配,不能為區域bean裝配后置處理器
8.3 添加后置處理器后bean的生命周期
① 通過構造器或工廠方法創建bean實體
② 為bean的屬性設定值和對其他bean的參考
postProcessBeforeInitialization(Object, String):在bean的初始化之前執行
③ 呼叫bean的初始化方法
postProcessAfterInitialization(Object, String):在bean的初始化之后執行
④ bean可以使用了
⑤ 當容器關閉時,呼叫bean的銷毀方法
第九章 Spring中自動裝配【基于XML】
9.1 Spring中提供兩種裝配方式
- 手動裝配
- 自動裝配
9.2 Spring自動裝配語法及規則
-
在bean標簽中添加屬性:Autowire即可
-
byName:物件中屬性名稱與容器中的beanId進行匹配,如果屬性名與beanId數值一致,則自動裝配成功
-
byType:物件中屬性型別與容器中class進行匹配,如果唯一匹配則自動裝配成功
-
匹配0個:未裝配
-
匹配多個,會報錯
expected single matching bean but found 2: deptDao,deptDao2
-
-
-
注意:基于XML方式的自動裝配,只能裝配非字面量數值
9.3 總結
- 基于xml自動裝配,底層使用set注入
- 最終:不建議使用byName、byType,建議使用注解方式自動裝配
第十章 Spring中注解【非常重要】
10.1 使用注解將物件裝配到IOC容器中
約定:約束>配置【注解>XML】>代碼
位置:在類上面標識
注意:
- Spring本身不區分四個注解【四個注解本質是一樣的@Component】,提供四個注解的目的只有一個:提高代碼的可讀性
- 只用注解裝配物件,默認將類名首字母小寫作為beanId
- 可以使用value屬性,設定beanId;當注解中只使用一個value屬性時,value關鍵字可省略
-
裝配物件四個注解
- @Component:裝配普通組件到IOC容器
- @Repository:裝配持久化層組件到IOC容器
- @Service:裝配業務邏輯層組件到IOC容器
- @Controller:裝配控制層|表示層組件到IOC容器
-
使用注解步驟
-
匯入相關jar包【已匯入】
-
開啟組件掃描
<!-- 開啟組件掃描 base-package:設定掃描注解包名【當前包及其子包】 --> <context:component-scan base-package="com.atguigu"></context:component-scan> -
使用注解標識組件
-
10.2 使用注解裝配物件中屬性【自動裝配】
-
@Autowired注解
-
作用:自動裝配物件中屬性
-
裝配原理:反射機制
-
裝配方式
-
先按照byType進行匹配
-
匹配1個:匹配成功,正常使用
-
匹配0個:
-
默認【@Autowired(required=true)】報錯
/*expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} */ -
@Autowired(required=false),不會報錯
-
-
匹配多個
-
再按照byName進行唯一篩選
-
篩選成功【物件中屬性名稱==beanId】,正常使用
-
篩選失敗【物件中屬性名稱!=beanId】,報如下錯誤:
//expected single matching bean but found 2: deptDao,deptDao2
-
-
-
-
-
@Autowired中required屬性
- true:表示被標識的屬性必須裝配數值,如未裝配,會報錯,
- false:表示被標識的屬性不必須裝配數值,如未裝配,不會報錯,
-
-
@Qualifier注解
- 作用:配合@Autowired一起使用,將設定beanId名稱裝配到屬性中
- 注意:不能單獨使用,需要與@Autowired一起使用
-
@Value注解
- 作用:裝配物件中屬性【字面量數值】
第十一章 Spring中組件掃描
11.1 默認使用情況
<!-- 開啟組件掃描
base-package:設定掃描注解包名【當前包及其子包】
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
11.2 包含掃描
- 注意:
- 使用包含掃描之前,必須設定use-default-filters="false"【關閉當前包及其子包的掃描】
- type
- annotation:設定被掃描注解的全類名
- assignable:設定被掃描實作類的全類名
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:include-filter type="assignable" expression="com.atguigu.service.impl.DeptServiceImpl"/>
</context:component-scan>
11.3 排除掃描
<!-- 【排除掃描】 假設:環境中共有100包,不想掃描2/100-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!-- <context:exclude-filter type="assignable" expression="com.atguigu.controller.DeptController"/>-->
</context:component-scan>
第十三章 Spring完全注解開發【0配置】
13.1 完全注解開發步驟
- 創建配置類
- 在class上面添加注解
- @Configuration:標識當前類是一個配置類,作用:代替XML組態檔
- @ComponentScan:設定組件掃描當前包及其子包
- 使用AnnotationConfigApplicationContext容器物件
13.2 示例代碼
/**
* @author Chunsheng Zhang 尚硅谷
* @create 2022/3/28 14:05
*/
@Configuration
@ComponentScan(basePackages = "com.atguigu")
public class SpringConfig {
}
@Test
public void test0Xml(){
//創建容器物件
// ApplicationContext context =
// new ClassPathXmlApplicationContext("applicationContext.xml");
//使用AnnotationConfigApplicationContext容器物件
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);
System.out.println("deptDao = " + deptDao);
}
第十四章 Spring集成Junit4
14.1 集成步驟
- 匯入jar包
- spring-test-5.3.1.jar
- 指定Spring的組態檔的路徑
- 【@ContextConfiguration】
- 指定Spring環境下運行Junit4的運行器
- @RunWith
14.2 示例代碼
/**
* @author Chunsheng Zhang 尚硅谷
* @create 2022/3/28 14:12
*/
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestSpringJunit4 {
@Autowired
private DeptService deptService;
@Test
public void testService(){
//創建容器物件
// ApplicationContext context =
// new ClassPathXmlApplicationContext("applicationContext.xml");
// DeptService deptService = context.getBean("deptService", DeptServiceImpl.class);
deptService.saveDept(new Dept());
}
}
第十五章 AOP前奏
15.1 代理模式
-
代理模式:我們需要做一件事情,又不期望自己親力親為,此時,可以找一個代理【中介】
-
我們【目標物件】與中介【代理物件】不能相互轉換,因為是“兄弟”關系

15.2 為什么需要代理【程式中】
-
需求:實作【加減乘除】計算器類
- 在加減乘除方法中,添加日志功能【在計算之前,記錄日志,在計算之后,顯示結果,】
-
實作后發現問題如下
- 日志代碼比較分散,可以提取日志類
- 日志代碼比較混亂,日志代碼【非核心業務代碼】與加減乘除方法【核心業務代碼】書寫一處
-
總結:在核心業務代碼中,需要添加日志功能,但不期望在核心業務代碼中書寫日志代碼,
- 此時:使用代理模式解決問題【先將日志代碼橫向提取到日志類中,再動態織入回到業務代碼中】
15.3 手動實作動態代理環境搭建
-
實作方式
- 基于介面實作動態代理: JDK動態代理
- 基于繼承實作動態代理: Cglib、Javassist動態代理
-
實作動態代理關鍵步驟
- 一個類:Proxy
- 概述:Proxy代理類的基類【類似Object】
- 作用:newProxyInstance():創建代理物件
- 一個介面:InvocationHandler
- 概述:實作【動態織入效果】關鍵介面
- 作用:invoke(),執行invoke()實作動態織入效果
- 一個類:Proxy
15.4 手動實作動態代理關鍵步驟
注意:代理物件與實作類【目標物件】是“兄弟”關系,不能相互轉換
- 創建類【為了實作創建代理物件工具類】
- 提供屬性【目標物件:實作類】
- 提供方法【創建代理物件】
- 提供有參構造器【避免目標對為空】
package com.atguigu.beforeaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Chunsheng Zhang 尚硅谷
* @create 2022/3/28 16:22
*/
public class MyProxy {
/**
* 目標物件【目標客戶】
*/
private Object target;
public MyProxy(Object target){
this.target = target;
}
/**
* 獲取目標物件的,代理物件
* @return
*/
public Object getProxyObject(){
Object proxyObj = null;
/**
類加載器【ClassLoader loader】,目標物件類加載器
目標物件實作介面:Class<?>[] interfaces,目標物件實作所有介面
InvocationHandler h
*/
ClassLoader classLoader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
//創建代理物件
proxyObj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
//執行invoke()實作動態織入效果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//獲取方法名【目標物件】
String methodName = method.getName();
//執行目標方法之前,添加日志
MyLogging.beforeMethod(methodName,args);
//觸發目標物件目標方法
Object rs = method.invoke(target, args);
//執行目標方法之后,添加日志
MyLogging.afterMethod(methodName,rs);
return rs;
}
});
return proxyObj;
}
// class invocationImpl implements InvocationHandler{
// }
}
@Test
public void testBeforeAop(){
// int add = calc.add(1, 2);
// System.out.println("add = " + add);
//目標物件
Calc calc = new CalcImpl();
//代理工具類
MyProxy myProxy = new MyProxy(calc);
//獲取代理物件
Calc calcProxy = (Calc)myProxy.getProxyObject();
//測驗
// int add = calcProxy.add(1, 2);
int div = calcProxy.div(2, 1);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/543958.html
標籤:Java
上一篇:Gateway-服務網關
下一篇:Maven
