spring基础知识(IOC、DI、AOP)
目錄
一、spring概述
二、spring核心功能 ioc控制反轉
1、什么是IOC
2、為什么要使用IOC
3、IOC的技術實現——DI依賴注入
? ? ?3.1Spring的第一個程序——spring創建對象的步驟
? ? ?3.2 DI依賴注入
? ?3.2.1基于XML的DI
? ?3.2.2基于注解的DI
? ?3.2.3注解與XML對比
四、面向切面編程AOP
4.1 概述
4.1.1動態代理的實現方式
4.1.2 動態代理的作用
4.1.3 AOP概述
4.1.4 AOP的實現
4.1.5 AOP的好處
4.2 AspectJ對AOP的實現
4.2.1 AspectJ切入點表達式
4.2.2 AspectJ 基于注解的 AOP 實現
一、spring概述
?Spring 的主要作用就是為代碼“解耦”,降低代碼間的耦合度。就是讓對象和對象(模塊和模塊)之間關系不是使用代碼關聯,而是通過配置來說明。減輕對項目模塊之間的管理,?類和類之間的管理, 幫助開發人員創建對象,管理對象之間的關系。
Spring 根據代碼的功能特點,使用 Ioc 降低業務對象之間耦合度。IoC 使得主業務在相互調用過程中,不用再自己維護關系了,即不用再自己創建要使用的對象了。而是由 Spring容器統一管理,自動“注入”,注入即賦值。 而 AOP 使得系統級服務得到了最大復用,且不用再由程序員手工將系統級服務“混雜”到主業務邏輯中了,而是由 Spring 容器統一完成“織入”。
二、spring核心功能 ioc控制反轉
1、什么是IOC
控制: 創建對象,對象的屬性賦值,對象之間的關系管理。
反轉: 把原來的開發人員管理,創建對象的權限轉移給代碼之外的容器實現。 由容器代替開發人員管理對象。創建對象,給屬性賦值。
IOC:把對象的創建,賦值,管理工作都交給代碼之外的容器實現, 也就是對象的創建是有其它外部資源完成。
2、為什么要使用IOC
目的就是減少對代碼的改動, 也能實現不同的功能。 實現解耦合。?
3、IOC的技術實現——DI依賴注入
Spring 容器是一個超級大工廠,負責創建、管理所有的 Java 對象,這些 Java 對象被稱為 Bean。Spring 容器管理著容器中 Bean 之間的依賴關系,Spring 使用“依賴注入”的方式來管理 Bean 之間的依賴關系。使用 IoC 實現對象之間的解耦和。spring是使用的di實現了ioc的功能, spring底層創建對象,使用的是反射機制。
3.1Spring的第一個程序——spring創建對象的步驟
1.創建maven項目
2.加入maven的依賴
? spring的依賴,版本5.2.5版本【spring-context】
? junit依賴【junit】
3.創建類(接口和它的實現類)
? 和沒有使用框架一樣, 就是普通的類。
4.創建spring需要使用的配置文件
? 在 src/main/resources/目錄現創建一個 xml 文件,文件名可以隨意,但 Spring 建議的名稱為 applicationContext.xml。聲明類的信息,這些類由spring創建和管理
實例化方式
(一)默認構造 <bean? id="" class=""/>:用于定義一個實例對象。一個實例對應一個 bean 元素。
id:該屬性是 Bean 實例的唯一標識,程序通過 id 屬性訪問 Bean,Bean 與 Bean 間的依賴關系也是通過 id 屬性關聯的。
class:指定該 Bean 所屬的類,注意這里只能是類,不能是接口。
(二)靜態工廠<bean id="" class="工廠類" factory-method="靜態方法">
靜態工廠:用于生成實例對象,所有的方法必須是static
public class MyBeanFactory {public static UserService createService(){return new UserServiceImpl();} } <!-- 將靜態工廠創建的實例交予spring class 確定靜態工廠全限定類名factory-method 確定靜態方法名--><bean id="userServiceId" class="com.itheima.c_inject.b_static_factory.MyBeanFactory" factory-method="createService"></bean>(三)實例工廠:<bean id="工廠id" class="工廠類">? <bean id="" factory-bean="工廠id" factory-method="方法">
必須先有工廠實例對象,通過實例對象創建對象。提供所有的方法都是“非靜態”的。
<!-- 創建工廠實例 --><bean id="myBeanFactoryId" class="com.itheima.c_inject.c_factory.MyBeanFactory"></bean><!-- 獲得userservice * factory-bean 確定工廠實例* factory-method 確定普通方法--><bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>?
5.測試spring創建的類
若 Spring 配置文件存放在項目的類路徑下,則使用 ClassPathXmlApplicationContext 實現類進行加載。
測試方法規范:
? ? ?1)public 方法
?? ? 2)沒有返回值 void?
?? ? 3)方法名稱自定義,建議名稱是test + 你要測試方法名稱
?? ? 4)方法沒有參數
?? ? 5)方法的上面加入 @Test ,這樣的方法是可以單獨執行的。 不用使用main方法。
3.2 DI依賴注入
di:依賴注入,表示創建對象,給屬性賦值。
di的實現有兩種:
1.在spring的配置文件中, 使用標簽和屬性完成,叫做基于XML的di實現
2.使用spring中的注解,完成屬性賦值, 叫做基于注解的id實現
di的語法分類:
?1. set注入(設置注入): spring調用類的set方法,在set方法可以實現屬性的賦值。
?2. 構造注入,spring調用類的有參數構造方法,創建對象。在構造方法中完成賦值。
3.2.1基于XML的DI
(1)set注入
set 注入也叫設值注入是指,通過 setter 方法傳入被調用者的實例。這種注入方式簡單、直觀,因而在 Spring 的依賴注入中大量使用
需要有set方法,沒有set方法是報錯的。并且調用的是默認的無參構造函數,如果重寫了構造函數,一定要手動加入無參的構造函數才可
set注入(設值注入) :spring調用類的set方法, 你可以在set方法中完成屬性賦值
? ? ? ? ?1)簡單類型的set注入
? ? ? ? ? ? <bean id="xx" class="yyy">
? ? ? ? ? ? ? ?<property name="屬性名字" value="此屬性的值"/>
? ? ? ? ? ? ? ?一個property只能給一個屬性賦值
? ? ? ? ? ? ? ?<property....>
? ? ? ? ? ? </bean>
? ? ? ? ?2) 引用類型的set注入 : spring調用類的set方法
? ? ? ? ? ?<bean id="xxx" class="yyy">
? ? ? ? ? ? ? <property name="屬性名稱" ref="bean的id(對象的名稱)" />
? ? ? ? ? ?</bean>
(2)構造注入
構造注入是指,在構造調用者實例的同時,完成被調用者的實例化。即,使用構造器設置依賴關系。
構造注入:spring調用類有參數構造方法,在創建對象的同時,在構造方法中給屬性賦值。構造注入使用 <constructor-arg> 標簽
? ? ? ? ? <constructor-arg> 標簽:一個<constructor-arg>表示構造方法一個參數。
? ? ? ? ? <constructor-arg> 標簽屬性:
? ? ? ? ? ? ?name:表示構造方法的形參名
? ? ? ? ? ? ?index:表示構造方法的參數的位置,參數從左往右位置是 0 , 1 ,2的順序
? ? ? ? ? ? ?value:構造方法的形參類型是簡單類型的,使用value
? ? ? ? ? ? ?ref:構造方法的形參類型是引用類型的,使用ref
(3)引用類型的自動注入
對于引用類型屬性的注入,也可不在配置文件中顯示的注入。可以通過為<bean/>標簽,設置 autowire 屬性值,為引用類型屬性進行隱式自動注入(默認是不自動注入引用類型屬
性)。根據自動注入判斷標準的不同,可以分為兩種:
- byName:根據名稱自動注入
- byType: 根據類型自動注入
引用類型的自動注入: spring框架根據某些規則可以給引用類型賦值。·不用你在給引用類型賦值了
? ? ? ?使用的規則常用的是byName, byType.
? ? ? ?1.byName(按名稱注入) : java類中引用類型的屬性名和spring容器中(配置文件)<bean>的id名稱一樣,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 且數據類型是一致的,這樣的容器中的bean,spring能夠賦值給引用類型。
? ? ? ? ?語法:
? ? ? ? ?<bean id="xx" class="yyy" autowire="byName">
? ? ? ? ? ? 簡單類型屬性賦值
? ? ? ? ?</bean>
? ? ? ?2.byType(按類型注入) : java類中引用類型的數據類型和spring容器中(配置文件)<bean>的class屬性
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 是同源關系的,這樣的bean能夠賦值給引用類型
? ? ? ? ?同源就是一類的意思:
? ? ? ? ? 1.java類中引用類型的數據類型和bean的class的值是一樣的。
? ? ? ? ? 2.java類中引用類型的數據類型和bean的class的值父子類關系的。
? ? ? ? ? 3.java類中引用類型的數據類型和bean的class的值接口和實現類關系的
? ? ? ? ?語法:
? ? ? ? ?<bean id="xx" class="yyy" autowire="byType">
? ? ? ? ? ? 簡單類型屬性賦值
? ? ? ? ?</bean>
注意:在byType中, 在xml配置文件中聲明bean只能有一個符合條件的,多余一個是錯誤的
(4)集合類型注入
<bean id="collDataId" class="com.itheima.f_xml.e_coll.CollData" ><property name="arrayData"><array><value>DS</value><value>DZD</value><value>屌絲</value><value>屌中屌</value></array></property><property name="listData"><list><value>于嵩楠</value><value>曾衛</value><value>楊煜</value><value>曾小賢</value></list></property><property name="setData"><set><value>停封</value><value>薄紙</value><value>關系</value></set></property><property name="mapData"><map><entry key="jack" value="杰克"></entry><entry><key><value>rose</value></key><value>肉絲</value></entry></map></property><property name="propsData"><props><prop key="高富帥">嫐</prop><prop key="白富美">嬲</prop><prop key="男屌絲">挊</prop></props></property></bean>集合的注入都是給<property>添加子標簽
??????????????數組:<array>
?????????????????????List:<list>
?????????????????????Set:<set>
?????????????????????Map:<map>?,map存放k?鍵值對,使用<entry>描述
?????????????????????Properties:<props>??<prop?key=""></prop>??
??????????????普通數據:<value>
??????????????引用數據:<ref>
(5)為應用指定多個spring配置文件
在實際應用里,隨著應用規模的增加,系統中 Bean 數量也大量增加,導致配置文件變得非常龐大、臃腫。為了避免這種情況的產生,提高配置文件的可讀性與可維護性,可以將
Spring 配置文件分解成多個配置文件。
包含關系的配置文件:多個配置文件中有一個總文件,總配置文件將各其它子文件通過<import/>引入。在 Java代碼中只需要使用總配置文件對容器進行初始化即可。
包含關系的配置文件:
? ? ? ? ?spring-total表示主配置文件 : 包含其他的配置文件的,主配置文件一般是不定義對象的。
? ? ? ? ?語法:<import resource="其他配置文件的路徑" />
? ? ? ? ?關鍵字:"classpath:" 表示類路徑(class文件所在的目錄),
? ? ? ? ? ? ? ?在spring的配置文件中要指定其他文件的位置, 需要使用classpath,告訴spring到哪去加載讀取文件。
? ? ? ?在包含關系的配置文件中,可以通配符(*:表示任意字符)
? ? ? ?注意: 主的配置文件名稱不能包含在通配符的范圍內
3.2.2基于注解的DI
(1)?定義 Bean 的注解@Component
@Component: 創建對象的, 等同于<bean>的功能
?? ? ?屬性:value 就是對象的名稱,也就是bean的id值,
?? ? ? ? ? value的值是唯一的,創建的對象在整個spring容器中就一個
?? ? 位置:在類的上面
?
?? @Component(value = "myStudent")等同于
?? ?<bean id="myStudent" class="com.bjpowernode.ba01.Student" />
?
?? spring中和@Component功能一致,創建對象的注解還有:
?? 1.@Repository(用在持久層類的上面) : 放在dao的實現類上面,
?? ? ? ? ? ? ? ?表示創建dao對象,dao對象是能訪問數據庫的。
?? 2.@Service(用在業務層類的上面):放在service的實現類上面,
?? ? ? ? ? ? ?創建service對象,service對象是做業務處理,可以有事務等功能的。
?? 3.@Controller(用在控制器的上面):放在控制器(處理器)類的上面,創建控制器對象的,
?? ? ? ? ? ? ? 控制器對象,能夠接受用戶提交的參數,顯示請求的處理結果。
?? 以上三個注解的使用語法和@Component一樣的。 都能創建對象,但是這三個注解還有額外的功能。
?? @Repository,@Service,@Controller是給項目的對象分層的。
(2) 簡單 類型屬性注入@Value
使用該注解完成屬性注入時,類中無需 setter。當然,若屬性有 setter,則也可將其加到 setter 上。
?@Value: 簡單類型的屬性賦值
? ? ?? ?屬性: value 是String類型的,表示簡單類型的屬性值
? ? ?? ?位置: 1.在屬性定義的上面,無需set方法,推薦使用。
? ? ?? ? ? ? ? ? ? ?2.在set方法的上面
(3)byType 自動注入@Autowired
使用該注解完成屬性注入時,類中無需 setter。當然,若屬性有 setter,則也可將其加到 setter 上。
?引用類型
? ? ??@Autowired: spring框架提供的注解,實現引用類型的賦值。
? ? ??spring中通過注解給引用類型賦值,使用的是自動注入原理 ,支持byName, byType
? ? ??@Autowired:默認使用的是byType自動注入。
? ? ?
? ? ?? 位置:1)在屬性定義的上面,無需set方法, 推薦使用
? ? ?? ? ? ? ? ? ?2)在set方法的上面
(4)byName 自動注入@Autowired 與@Qualifier
引用類型
如果要使用byName方式,需要做的是:
? ? ?? 1.在屬性上面加入@Autowired
? ? ?? 2.在屬性上面加入@Qualifier(value="bean的id") :表示使用指定名稱的bean完成賦值。
屬性:required ,是一個boolean類型的,默認true
? ? ? ? ? ?required=true:表示引用類型賦值失敗,程序報錯,并終止執行。
? ? ? ? ? required=false:引用類型如果賦值失敗, 程序正常執行,引用類型是null
(5)JDK 注解@Resource 自動注入
?引用類型
? ? ??@Resource: 來自jdk中的注解,spring框架提供了對這個注解的功能支持,可以使用它給引用類型賦值
? ? ? ? ? ? ? 使用的也是自動注入原理,支持byName, byType .默認是byName
? ? ?? 位置: 1.在屬性定義的上面,無需set方法,推薦使用。
? ? ?? ? ? ? ? ? ? 2.在set方法的上面
默認是byName: 先使用byName自動注入,如果byName賦值失敗,再使用byType
小結:
注入? --> 字段或setter方法
????????????? 普通值:@Value
????????????? 引用值:
???????????????????? 類型:@Autowired
???????????????????? 名稱1:@Autowired? @Qualifier("名稱")
???????????????????? 名稱2:@Resource("名稱")
3.2.3注解與XML對比
四、面向切面編程AOP
4.1 概述
4.1.1動態代理的實現方式
jdk動態代理,使用jdk中的Proxy,Method,InvocaitonHanderl創建代理對象。
? ? ? ? ? ? ?jdk動態代理要求目標類必須實現接口
? cglib動態代理:第三方的工具庫,創建代理對象,原理是繼承。 通過繼承目標類,創建子類。
? ? ? ? ? ? ?子類就是代理對象。 要求目標類不能是final的, 方法也不能是final的
4.1.2 動態代理的作用
? ??1)在目標類源代碼不改變的情況下,增加功能。
?? ?2)減少代碼的重復
?? ?3)專注業務邏輯代碼
?? ?4)解耦合,讓你的業務功能和日志,事務非業務功能分離。
4.1.3 AOP概述
AOP 為 Aspect Oriented Programming 的縮寫,意為:面向切面編程,可通過運行期動態代理實現程序功能的統一維護的一種技術。AOP 是 Spring 框架中的一個重要內容。利用 AOP
可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
? Aspect: 切面,給你的目標類增加的功能,就是切面。 像上面用的日志,事務都是切面。
? ? ? ? ? 切面的特點: 一般都是非業務方法,獨立使用的。
? Orient:面向, 對著。
? Programming:編程
? oop: 面向對象編程
? 怎么理解面向切面編程 ??
? ?1)需要在分析項目功能時,找出切面。
?? ?2)合理的安排切面的執行時間(在目標方法前, 還是目標方法后)
?? ?3)合理的安全切面執行的位置,在哪個類,哪個方法增加增強功能
? 術語:
? ?1)Aspect:切面,表示增強的功能, 就是一堆代碼,完成某個一個功能。非業務功能,
?? ? ? ? ? ? ?常見的切面功能有日志, 事務, 統計信息, 參數檢查, 權限驗證。
? ?2)JoinPoint:連接點 ,連接業務方法和切面的位置。 就某類中的業務方法
?? ?3)Pointcut : 切入點 ,指多個連接點方法的集合。多個方法
?? ?4)目標對象: 給哪個類的方法增加功能, 這個類就是目標對象
?? ?5)Advice:通知,通知表示切面功能執行的時間。
?? ?說一個切面有三個關鍵的要素:
?? ?1)切面的功能代碼,切面干什么
?? ?2)切面的執行位置,使用Pointcut表示切面執行的位置
?? ?3)切面的執行時間,使用Advice表示時間,在目標方法之前,還是目標方法之后。
4.1.4 AOP的實現
?aop是一個規范,是動態的一個規范化,一個標準
?? ?aop的技術實現框架:
?? ?1.spring:spring在內部實現了aop規范,能做aop的工作。
?? ? ? ? ? ? ?spring主要在事務處理時使用aop。
?? ??? ??? ??? ? 我們項目開發中很少使用spring的aop實現。 因為spring的aop比較笨重。
? ?2.aspectJ: 一個開源的專門做aop的框架。spring框架中集成了aspectj框架,通過spring就能使用aspectj的功能。
?? ? ?aspectJ框架實現aop有兩種方式:
?? ? ? 1.使用xml的配置文件 : 配置全局事務
?? ??? ?2.使用注解,我們在項目中要做aop功能,一般都使用注解, aspectj有5個注解。
4.1.5 AOP的好處
1.減少重復;
2.專注業務;
注意:面向切面編程只是面向對象編程的一種補充。
4.2 AspectJ對AOP的實現
4.2.1 AspectJ切入點表達式
4.2.2 AspectJ 基于注解的 AOP 實現
AspectJ 中常用的通知有五種類型:
1)前置通知
2)后置通知
3)環繞通知
4)異常通知
5)最終通知
(1)實現步驟
@Aspect : 是aspectj框架中的注解。
? ? ? 作用:表示當前類是切面類。
? ? ? 切面類:是用來給業務方法增加功能的類,在這個類中有切面的功能代碼
? ? ? 位置:在類定義的上面
切面類中的方法定義規范
? ? ?定義方法,方法是實現切面功能的。
? ? ?方法的定義要求:
? ? ?1.公共方法 public
? ? ?2.方法沒有返回值
? ? ?3.方法名稱自定義
? ? ?4.方法可以有參數,也可以沒有參數。
? ? ?? 如果有參數,參數不是自定義的,有幾個參數類型可以使用。
@Before: 前置通知注解
? ? ?? ?屬性:value ,是切入點表達式,表示切面的功能執行的位置。
? ? ?? ?位置:在方法的上面
? ? ??特點:
? ? ?? 1.在目標方法之前先執行的
? ? ?? 2.不會改變目標方法的執行結果
? ? ?? 3.不會影響目標方法的執行。
指定通知方法中的參數 : JoinPoint
? ? ??JoinPoint:業務方法,要加入切面功能的業務方法
? ? ?? ? 作用是:可以在通知方法中獲取方法執行時的信息, 例如方法名稱,方法的實參。
? ? ?? ? 如果你的切面功能中需要用到方法的信息,就加入JoinPoint.
? ? ?? ?這個JoinPoint參數的值是由框架賦予, 必須是第一個位置的參數
后置通知定義方法,方法是實現切面功能的。
? ? ??方法的定義要求:
? ? ??1.公共方法 public
? ? ??2.方法沒有返回值
? ? ??3.方法名稱自定義
? ? ??4.方法有參數的,推薦是Object ,參數名自定義
@AfterReturning:后置通知
? ? ?? ? 屬性:1.value 切入點表達式
? ? ?? ? ? ? ?2.returning 自定義的變量,表示目標方法的返回值的。
? ? ?? ? ? ? ? 自定義變量名必須和通知方法的形參名一樣。
? ? ?? ? 位置:在方法定義的上面
? ? ??特點:
? ? ?? 1. 在目標方法之后執行的。
? ? ?? 2. 能夠獲取到目標方法的返回值,可以根據這個返回值做不同的處理功能
? ? ? ? ? ?Object res = doOther();
? ? ? ?3. 可以修改這個返回值
? ??
? ? ?? 后置通知的執行
? ? ?? ? Object res = doOther();
? ? ?? ? 參數傳遞: 傳值, 傳引用
? ? ?? ? myAfterReturing(res);
? ? ?? ? System.out.println("res="+res)
環繞通知方法的定義格式
? ? ?? 1.public
? ? ?? 2.必須有一個返回值,推薦使用Object
? ? ?? 3.方法名稱自定義
? ? ?? 4.方法有參數,固定的參數 ProceedingJoinPoint
@Around: 環繞通知
? ? ?? ? 屬性:value 切入點表達式
? ? ?? ? 位置:在方法的定義什么
? ? ?特點:
? ? ?? ?1.它是功能最強的通知
? ? ?? ?2.在目標方法的前和后都能增強功能。
? ? ?? ?3.控制目標方法是否被調用執行
? ? ?? ?4.修改原來的目標方法的執行結果。 影響最后的調用結果
? ?
? ? ?? 環繞通知,等同于jdk動態代理的,InvocationHandler接口
? ? ?
? ? ?? 參數: ?ProceedingJoinPoint 就等同于 Method
? ? ?? ? ? ? ?作用:執行目標方法的
? ? ?? 返回值: 就是目標方法的執行結果,可以被修改。
? ? ?? 環繞通知: 經常做事務, 在目標方法之前開啟事務,執行目標方法, 在目標方法之后提交事務
異常通知方法的定義格式
? ? ??1.public
? ? ?? 2.沒有返回值
? ? ?? 3.方法名稱自定義
? ? ?? 4.方法有個一個Exception, 如果還有是JoinPoint
??@AfterThrowing:異常通知
? ? ?? ? ?屬性:1. value 切入點表達式
? ? ?? ? ? ? ? 2. throwinng 自定義的變量,表示目標方法拋出的異常對象。
? ? ?? ? ? ? ? ?? 變量名必須和方法的參數名一樣
? ? ??特點:
? ? ?? ?1. 在目標方法拋出異常時執行的
? ? ?? 2. 可以做異常的監控程序, 監控目標方法執行時是不是有異常。
? ? ?? ? ? 如果有異常,可以發送郵件,短信進行通知
? ? ?
? ? ?? 執行就是:
? ? ?? ?try{
? ? ?? ? ? ?SomeServiceImpl.doSecond(..)
? ? ?? ?}catch(Exception e){
? ? ?? ? ? ?myAfterThrowing(e);
? ? ?? ?}
?最終通知方法的定義格式
? ? ?? 1.public
? ? ?? 2.沒有返回值
? ? ?? 3.方法名稱自定義
? ? ?? 4.方法沒有參數, ?如果還有是JoinPoint
?@After :最終通知
? ? ?? ? 屬性: value 切入點表達式
? ? ?? ?位置: 在方法的上面
? ? ??特點:
? ? ?? 1.總是會執行
? ? ?? 2.在目標方法之后執行的
? ? ?
? ? ?? try{
? ? ?? ? ?SomeServiceImpl.doThird(..)
? ? ?? }catch(Exception e){
? ? ?
? ? ?? }finally{
? ? ?? ? ? myAfter()
? ? ??}
@Pointcut: 定義和管理切入點, 如果你的項目中有多個切入點表達式是重復的,可以復用的。
? ? ? ? ? ? ? ? ?可以使用@Pointcut
? ? ?? ? 屬性:value 切入點表達式
? ? ?? ?位置:在自定義的方法上面
? ? ??特點:
? ? ?? ?當使用@Pointcut定義在一個方法的上面 ,此時這個方法的名稱就是切入點表達式的別名。
? ? ?? ?其它的通知中,value屬性就可以使用這個方法名稱,代替切入點表達式了
?
總結
以上是生活随笔為你收集整理的spring基础知识(IOC、DI、AOP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php图片一句话木马使用方法
- 下一篇: 华为OD机试真题大全,用 Python