一、心動不如行動
一、創建項目
*注:在IDEA中我創建的Maven項目,不了解Maven的朋友可以看我之前的博客“我們一起走進Maven——知己知彼”,了解Maven后可以看我之前的博客“Maven的安裝與配置”,自行安裝,行動起來吧。






二、加載依賴
在pom.xml文件中添加Spring依賴和日志相關依賴
<dependencies>
<!--測試相關-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--Spring核心基礎依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--日志相關-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
三、項目結構
在main目錄下面創建java和resources目錄


四、基礎代碼實現(練手)
- 創建TestDao接口和實現類
- 獲得TestDao實現類的實例
- 在之前開發中,我們是直接new一個對象即可。即:`private TestDao dao = new TestDaoImpl();`
- 在學習Spring之后,將由Spring來創建對象的實例 --> 即:`IoC 控制反轉(Inverse of Control)`
之后需要實例對象時,從Spring工廠(容器)中獲得即可,需要將實現類的全限定名稱配置到xml文件中。
創建dao包,在dao包下創建TestDao接口和TestDao接口的實現類,結構如下圖:

TestDao接口代碼示例:
package dao;
public interface TestDao {
public void sayHello();
}
TestDaoImpl實現類代碼示例:
package dao;
public class TestDaoImpl implements TestDao{
@Override
public void sayHello() {
System.out.println("Hello,Spring!");
}
}
在resources資源目錄點擊右鍵,依次選擇New-->XML Configuration File-->Spring Config,創建applicationContext.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">
<!--把testDao對象的創建權交給Spring-->
<!-- <bean> 配置需要創建的對象
id :用於之后從Spring容器中獲得實例時使用的
class :需要創建實例的全限定類名-->
<bean id="testDao" class="dao.TestDaoImpl"></bean> </beans>
創建test包,在test包下創建測試類SpringTest

package test;
import dao.TestDao;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@Test
public void demo1(){
// 之前開發,自己手寫new出對象
TestDao dao= new TestDaoImpl();
dao.sayHello();
}
@Test
public void demo2() {
// 現在從spring容器中獲得對象實例
// 1 、獲得容器
//初始化Spring容器ApplicationContext,加載配置文件
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、獲得內容 ,注意此時不需要自己new出對象了,都是從spring容器中獲得
//通過容器獲取testDao實例
TestDao testDao = (TestDao) application.getBean("testDao");
testDao.sayHello();
}
}
- IoC(Inverse of Control)反轉控制的概念,就是將原本在程序中手動創建TestDaoImpl對象的控制權,交由Spring框架管理。
- 簡單說,就是創建TestDaoImpl對象的控制權被反轉到了Spring框架。
點擊測試方法左側的運行按鈕,選擇Run,測試代碼

運行后控制台顯示結果

項目運行成功!!!!!!!
五、Spring入門案例:DI(掌握)
- DI :Dependency Injection :依賴注入
- is a :是一個,繼承。
- has a:有一個,成員變量,依賴。
class B {
private A a; // B類依賴A類,B類使用A類。
}
依賴:一個對象需要使用另一個對象。
注入:通過setter方法進行另一個對象實例設置。
例如:
class BookServiceImpl {
// 之前開發:接口 = 實現類(service和dao耦合了,寫死了,知道具體的實現類是誰,那么我的具體實現類變化,那么這行代碼也得跟着變)
// private BookDao bookDao = new BookDaoImpl();
// spring之后(解耦:service實現類使用了dao的接口,這樣就不知道具體的實現類是誰了)
private BookDao bookDao;
setter方法
}
模擬spring執行過程
創建service實例:BookService bookService = new BookServiceImpl(); => IoC <bean>
創建dao實例:BookDao bookDao = new BookDaoImple(); => IoC
將dao設置給service:bookService.setBookDao(bookDao); => DI <property>
具體代碼實現:
實現步驟:
- 創建BookDao接口和實現類
- 創建BookService接口和實現類
- 將dao和service配置到 applicationContext.xml文件中
- 使用api測試
項目結構:

加載依賴:
在pom.xml文件中添加Spring依賴和日志相關依賴
<dependencies>
<!--測試相關-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--Spring核心基礎依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--日志相關-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
BookDao接口和實現類
package dao;
public interface BookDao {
void save();
}
package dao;
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("實現添加功能");
}
}
BookService接口和實現類
package Service;
public interface BookService {
void addBook();
}
package Service;
import dao.BookDao;
import dao.BookDaoImpl;
public class BookServiceImpl implements BookService {
//方式一:之前,接口=實現類
//private BookDao bookDao= new BookDaoImpl();
//方式二:現在,接口+setter方法
private BookDao bookDao;
public void setBookDao(BookDao bookDao){
this.bookDao=bookDao;
}
@Override
public void addBook() {
this.bookDao.save();
}
}

將dao和service配置到 applicationContext.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">
<!-- <bean> 配置需要創建的對象
id :用於之后從Spring容器中獲得實例時使用的
class :需要創建實例的全限定類名-->
<!--
模擬spring執行過程
創建service實例:BookService bookService = new BookServiceImpl(); => IoC <bean>
創建dao實例:BookDao bookDao = new BookDaoImple(); => IoC
將dao實例設置給service實例:bookService.setBookDao(bookDao); => DI <property>
<property> 用於進行屬性注入
name : Bean的屬性名稱,通過setter方法獲得
setBookDao => BookDao => bookDao
ref :另一個Bean的id值的引用
-->
<!-- 創建service實例 -->
<bean id="bookServiceId" class="Service.BookServiceImpl">
<!-- 將dao實例設置給service實例 -->
<property name="bookDao" ref="bookDaoId"></property> <!-- 用於進行屬性注入 -->
</bean>
<!-- 創建dao實例 -->
<bean id="bookDaoId" class="dao.BookDaoImpl"></bean>
</beans>

使用api測試
創建test包,在test包下創建測試類SpringTest
package test;
import Service.BookService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@Test
public void Test1(){
// 之前開發,自己手寫new出對象
// BookService bookService = new BookServiceImpl();
// bookService.addBook();
}
@Test
public void Test2(){
// 現在從spring容器中獲得對象實例
// 1 、獲得容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、獲得內容 ,注意此時不需要自己new出對象了,都是從spring容器中獲得
BookService bookService = (BookService) applicationContext.getBean("bookServiceId");
bookService.addBook();
}
}
- DI:Dependency Injection 依賴注入,在Spring框架負責創建Bean對象時,動態的將依賴對象注入到Bean組件。
- getBean("bookServiceId"); 從spring容器中獲得指定名稱對象的實例時,會先判斷本實例對象是否需要使用其他實例化對象,由於設置了< property name="bookDao" ref="bookDaoId">< /property>,說明需要使用其他實例化對象,所以就根據其他Bean的id值的引用,去spring容器中獲得指定名稱對象的實例,相當於將dao實例設置給service實例。
運行后控制台顯示結果

這就成功了,開心一下,通過這兩個案例,多Spring有了初步的理解,加油!
六、Spring的核心API(了解)
api整體了解即可,之后不使用,在學習過程需要。

- BeanFactory :這是一個
工廠,用於生成任意Bean。采取延遲加載,第一次調用getBean(); 時才會初始化Bean。(即實例化對象) - ApplicationContext :是BeanFactory的子接口,功能更強大。(國際化處理、事件傳遞、Bean自動裝配、各種不同應用層的Context實現)。
采取非延時加載,當配置文件被加載時,就進行對象的實例化。- ClassPathXmlApplicationContext 用於加載classpath(類路徑/src)下的xml
- 加載xml運行時位置 --> /WEB-INF/classes/xxx.xml
- FileSystemXmlApplicationContext 用於加載指定盤符下的xml
- 加載xml運行時位置 --> /WEB-INF/xxx.xml
- 通過java web學習過的 ServletContext.getRealPath(); 獲得具體盤符
- ClassPathXmlApplicationContext 用於加載classpath(類路徑/src)下的xml
示例代碼如下:
package test;
import Service.BookService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class SpringTest {
@Test
public void Test1(){
// 之前開發,自己手寫new出對象
// BookService bookService = new BookServiceImpl();
// bookService.addBook();
}
@Test
public void Test2(){
// 現在從spring容器中獲得對象實例
// 1 、獲得容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 采取非延時加載,當配置文件被加載時,就進行對象的實例化。
// 2、獲得內容 ,注意此時不需要自己new出對象了,都是從spring容器中獲得
BookService bookService = (BookService) applicationContext.getBean("bookServiceId");
bookService.addBook();
}
@Test
public void demo3() {
// 現在從spring容器中獲得對象實例,使用的是BeanFactory,里面需要一個Resource,該Resource又是一個接口,需要找它的實現類ClassPathResource
// 1 、獲得容器
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
// 2、獲得內容 ,注意此時不需要自己new出對象了,都是從spring容器中獲得
BookService bookService = (BookService) beanFactory.getBean("bookServiceId"); // 采取延遲加載,第一次調用getBean(); 時才會初始化Bean(即實例化對象)。
bookService.addBook();
}
}
七、裝配Bean:基於XML
3種bean實例化方式:
- 使用`默認構造方法`實例化
- 使用`靜態工廠方法`實例化
- 使用`實例工廠方法`實例化
使用默認構造方法實例化
格式:
<bean id="從Spring容器中獲得實例時使用的" class="需要創建實例的全限定類名"></bean> 例如:<bean id="userServiceId" class="Service.UserServiceImpl"></bean>
示例中用到的 UserService.java 和 UserServiceImpl.java 代碼同上面實例中的代碼,這里不再贅述!
在spring容器中進行配置:
applicationContext.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">
<!--第一種實例化Bean 的方式 :使用默認構造方法實例化,即要實例化的Bean必須要提供默認構造方法 -->
<bean id="userServiceId" class="Service.UserServiceImpl"></bean>
</beans>
測試代碼:
public class TestIoC {
@Test
public void demo01() {
// 之前開發,自己手寫new出對象
UserService userService = new UserServiceImpl(); // 直接手動創建實例
userService.addUser();
}
@Test
public void demo02() {
// 現在從spring容器中獲得對象實例
// 1 、獲得容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、獲得內容 ,注意此時不需要自己new出對象了,都是從spring容器中獲得
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
}
}
使用`靜態工廠方法`實例化
- 靜態工廠:常用與spring整合其他框架(工具)時。
- 靜態工廠:用於生成實例對象,所有的方法必須是static。
示例中用到的 UserService.java 和 UserServiceImpl.java 代碼同上面實例中的代碼,這里不再贅述!
格式:
<bean id="" class="工廠全限定類名" factory-method="靜態方法名稱">
在spring容器中進行配置:
applicationContext.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">
<!--第二種實例化Bean 的方式 :使用靜態工廠方法實例化
將自定義的靜態工廠創建的實例交給spring管理
class 自定義靜態工廠全限定類名
factory-method 靜態方法名
-->
<bean id="userServiceId" class="Service.MyBeanFactory" factory-method="createService"></bean>
</beans>
靜態工廠類代碼:
public class MyBeanFactory {
/**
* 創建實例的靜態工廠,所有的方法必須是靜態的(static)。
*
* @return
*/
public static UserService createService() {
return new UserServiceImpl();
}
// 還有創建其他實例的靜態工廠
// ......
}
測試代碼:
TestStaticFactory.java
/**
* 第二種實例化Bean 的方式 :使用靜態工廠方法實例化
*
*/
public class TestStaticFactory {
@Test
public void demo01() {
// 以前:使用自定義的靜態實例工廠
UserService userService = MyBeanFactory.createService();
userService.addUser();
}
@Test
public void demo02() {
// 現在:使用spring 工廠:將自定義的靜態工廠創建的實例交給spring管理
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userServiceId", UserService.class); // 這種方式底層會自動轉換
// UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
}
}
注意:當使用JDK版本為1.8時,運行上面的測試代碼會出現一個問題: java.lang.IllegalArgumentException,
問題解決鏈接:使用Junit測試一個 spring靜態工廠實例化bean 的例子,所有代碼都沒有問題,但是出現java.lang.IllegalArgumentException異常
小結:在以后的開發中,工廠類不需要我們去手寫,因為別人已經寫好了,我們通過編寫配置文件,把別人寫好的工廠類拿來,寫上要用的方法名,然后把它生產后的實例給Spring存起來,以后我們要用什么實例,跟Spring說一下,去拿就可以了。
使用`實例工廠方法`實例化
實例工廠:必須先有工廠的實例對象,然后通過實例對象去創建對象。特點:提供所有的方法都是“非靜態”的。
示例中用到的 UserService.java 和 UserServiceImpl.java 代碼同上面實例中的代碼,這里不再贅述!
在spring容器中進行配置:
applicationContext.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">
<!--第三種實例化Bean 的方式 :使用實例工廠方法實例化 -->
<!--創建工廠實例 -->
<bean id="myBeanFactoryId" class="com.itheima.c_inject.c_factory.MyBeanFactory" ></bean>
<!--通過工廠實例,獲得對象 factory-bean 工廠實例名稱 factory-method 普通方法名稱 -->
<bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>
</beans>
靜態工廠類代碼:
public class MyBeanFactory {
/**
* 創建實例的工廠,所有方法非靜態
*
* @return
*/
public UserService createService() {
return new UserServiceImpl();
}
// 還有創建其他實例的工廠
// ......
}
測試代碼:
TestFactory.java
package test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 第三種實例化Bean 的方式 :使用實例工廠方法實例化
* */
public class TestFactory {
@Test
public void demo01() {
// 以前:使用自定義的實例工廠
// 1、創建工廠實例
MyBeanFactory myBeanFactory = new MyBeanFactory();
// 2、通過工廠實例,獲得對象
UserService userService = myBeanFactory.createService();
userService.addUser();
}
@Test
public void demo02() {
// 現在:使用spring 工廠:將自定義的實例工廠創建的實例交給spring管理
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userServiceId", UserService.class); // 這種方式底層會自動轉換
// UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
}
}
-
一、Bean的種類
-
普通bean :之前操作的都是普通bean。例如:
< bean id="xxx" class="A" >,這句代碼的意思是:Spring直接創建A的實例,並返回。 -
FactoryBean :是一個特殊的bean,
具有工廠生成對象能力,但是只能生成特定的對象。
想要生產對象的bean 必須實現FactoryBean 接口,此接口提供方法getObject(); 用於獲得特定bean。- 示例:
< bean id="xxx" class="FB">,這句代碼的意思是:Spring會先創建FB實例,然后調用getObject(); 方法,並返回方法的返回值。
即相當於如下兩行代碼:
FB fb = new FB();
return fb.getObject();
- 示例:
-
BeanFactory 和 FactoryBean 對比?
- BeanFactory :是一個生產bean的工廠,用於生成任意的bean。
- FactoryBean :是一個特殊的bean,用於生成另一個特定的bean。
- 例如:ProxyFactoryBean ,此工廠bean用於生產代理對象的實例。
< bean id="xxx" class="….ProxyFactoryBean">,這句代碼的意思是:獲得代理對象的實例。即AOP使用。
- 例如:ProxyFactoryBean ,此工廠bean用於生產代理對象的實例。
-
spring容器中bean元素id和name屬性的區別?
-
在spring容器中添加以下配置:
示例:< bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"> -
bean節點中id和name的區別:
-
區別一:
- id : 指定唯一實例引用
- name : 可以指定多個實例引用,例如name="名稱1, 名稱2"
-
區別二:
-
id :id的命名要滿足XML對ID屬性命名規范
例如:必須以字母開始,可以使用字母、數字、連字符、下划線、句話、冒號 -
name : 如果Bean的名稱中含有特殊字符,就需要使用name屬性
例如 :< bean name="# boy" class="cn.itheima.ioc.Boy"/> -
因為name屬性可以相同,所以后出現Bean會覆蓋之前出現的同名的Bean。
-
總結:項目開發的時候,強烈要求用id,因為id可以表示唯一引用。
-
-
-
二、Bean的作用域
Bean 的作用域:用於確定spring所創建bean 的實例個數。

- 取值:
- singleton 單例,默認值。
- prototype 多例,每執行一次getBean() 將獲得一個實例。例如:在struts整合spring時,需要配置action為多例。
- 配置示例:默認情況下會在容器啟動時初始化bean,但我們可以指定Bean節點的
lazy-init="true"來延遲初始化bean,這時候,只有第一次獲取bean會才初始化bean。- 例如:`< bean id="xxx" class="xxx" scope="xxx">`
例如:< bean id="xxx" class="service.UserServiceImpl" lazy-init="true">- 如果想對所有bean都應用延遲初始化,可以在根節點beans設置
default-lazy-init="true",
例如:< beans default-lazy-init="true“> - Portlet是基於java的web組件,由portlet容器管理,並由容器處理請求,生產動態內容。
- Portals使用portlets作為可插拔用戶接口組件,提供信息系統的表示層。
- 作為利用servlets進行web應用編程的下一步,portlets實現了web應用的模塊化和用戶中心化。
在spring容器中進行配置:
applicationContext.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">
<bean id="userServiceId" class="com.itheima.d_scope.UserServiceImpl" scope="prototype"></bean>
</beans>
測試代碼:
TestScope.java
public class TestScope {
@Test
public void demo01() {
// 現在:使用spring 工廠
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = applicationContext.getBean("userServiceId", UserService.class);
// 這種方式底層會自動轉換
UserService userService2 = applicationContext.getBean("userServiceId", UserService.class);
// 這種方式底層會自動轉換
// 默認Bean的作用域是單例,所以打印的對象的地址是一樣的
// System.out.println(userService1); // service.UserServiceImpl@2ac273d3
// System.out.println(userService2); // service.UserServiceImpl@2ac273d3
// 現在在配置文件中添加scope屬性,值為prototype,此時Bean的作用域變為多例了,再次打印,輸出地址不一樣了
System.out.println(userService1);
//service.UserServiceImpl@66480dd7
System.out.println(userService2);
//service.UserServiceImpl@52a86356
}
}
-
三、Bean的生命周期
Bean 的生命周期詳情
- instantiate bean 對象實例化。
- populate properties 封裝屬性。
- 如果Bean實現 BeanNameAware,則表示執行
setBeanName。 - 如果Bean實現 BeanFactoryAware 或者 ApplicationContextAware,則表示設置實例工廠(
setBeanFactory)或者上下文對象(setApplicationContext)。 - 如果存在類實現 BeanPostProcessor(后處理Bean),則表示執行
postProcessBeforeInitialization。 - 如果Bean實現 InitializingBean,則表示執行
afterPropertiesSet。 - 調用
,則表示指定初始化方法init。 - 如果存在類實現 BeanPostProcessor(處理Bean),則表示執行
postProcessAfterInitialization。 - 執行業務處理
- 如果Bean實現 DisposableBean,則表示執行
destroy。 - 調用
,則表示指定銷毀方法customerDestroy。

-
四、Bean 的初始化和銷毀
目標方法執行前和執行后,將進行Bean的初始化或銷毀。
示例:<bean id="xxx" class="xxx" init-method="初始化的方法名稱" destroy-method="銷毀的方法名稱"></bean>
示例代碼如下:
編寫目標類代碼:
UserService.java
public interface UserService {
void addUser();
}
UserServiceImpl.java
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("e_lifecycle add user");
}
public void myInit() {
System.out.println("我的初始化方法");
}
public void myDestory() {
System.out.println("我的銷毀方法");
}
}
在spring容器中進行配置:
applicationContext.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">
<!--
init-method 用於配置初始化方法,用於准備數據等使用場景
destroy-method 用於配置銷毀方法,用於清理資源等使用場景
-->
<bean id="userServiceId" class="service.UserServiceImpl"
init-method="myInit" destroy-method="myDestory"></bean>
</beans>
編寫測試代碼:
public class TestLifecycle {
@Test
public void demo01() throws Exception {
// 現在:使用spring 工廠(spring 容器)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser(); // 要想使我的銷毀方法也執行,必須要求:
// 1.容器必須先close,我的銷毀方法才會執行;
// 2.必須是單例的(spring所創建該bean的實例個數只有一個)即bean中的scope配置成默認即可。
// 因為此close方法在接口 ApplicationContext 中沒有定義,而在實現類中提供了該方法,我們可以使用反射,因為反射最后執行的就是實現類中的方法。
applicationContext.getClass().getMethod("close").invoke(applicationContext); } }
-
五、BeanPostProcessor 后處理Bean
- 是由spring提供的一種機制,只要實現類實現此接口BeanPostProcessor,並將該實現類提供給spring容器,spring容器將自動執行兩個方法:在初始化方法前執行before()方法,在初始化方法后執行after()方法。配置格式:
這句代碼的意思就是:把實現類提供給了spring容器。
- Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
- spring提供工廠勾子,用於修改實例對象,可以生成代理對象。(是AOP底層)
谷歌翻譯:Factory hook(勾子),允許自定義修改新的bean實例,例如:檢查標記接口或用代理包裝它們。
我們來模擬這句話的意思:
before() => postProcessAfterInitialization(Object bean, String beanName) after() => postProcessBeforeInitialization(Object bean, String beanName) A a = new A(); a = B.before(a); // 將a的實例對象傳遞給后處理bean,可以什么都沒做,也可以做一些事情,比如:生成jdk代理對象並返回給a,這樣a就從實例對象變成代理對象了,此時的a就具有了AOP功能;再比如,如果把null返回給a,再用a去調用方法,就會出現空指針異常。 a.init(); a = B.after(a); // 以下是AOP演示: // 我們現在在后處理Bean 代碼執行完之后,把jdk代理對象返回給a。讓a在調用addUser()之前先做一些事情 // 之前要做的事情 a.addUser(); // 在目標方法的前后可以做一些事情,例如:開啟事務、提交事務、性能監控(前后時間)等等 // 之后要做的事情 a.destroy();
目標類示例代碼如下:
UserService.java
public interface UserService {
void addUser();
}
UserServiceImpl.java
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("e_lifecycle add user");
}
public void myInit() {
System.out.println("我的初始化方法");
}
public void myDestory() {
System.out.println("我的銷毀方法");
}
}
實現類示例代碼如下:
MyBeanPostProcessor.java
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("執行了前方法:" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
System.out.println("執行了后方法:" + beanName);
// 傳入的參數bean是我們的目標對象,此時我們的目標對象只有一個接口,那么我們的代理對象也只有一個接口
// 生成jdk代理對象
return Proxy.newProxyInstance(
MyBeanPostProcessor.class.getClassLoader(), // 代理對象
bean.getClass().getInterfaces(), // 目標對象
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---開啟事務---");
Object obj = method.invoke(bean, args); // 執行目標方法,本例中的目標方法是addUser
System.out.println("---關閉事務---");
return obj;
}
}); // 代理的處理程序
}
}
在spring容器中進行配置:
applicationContext.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">
<!--
init-method 用於配置初始化方法,用於准備數據等使用場景
destroy-method 用於配置銷毀方法,用於清理資源等使用場景
-->
<bean id="userServiceId" class="service.UserServiceImpl"
init-method="myInit" destroy-method="myDestory"></bean>
<!-- 將后處理的實現類注冊給spring -->
<bean class="com.itheima.e_lifecycle.MyBeanPostProcessor"></bean>
</beans>
測試示例代碼如下:
TestLifecycle.java
public class TestLifecycle {
@Test
public void demo01() throws Exception {
// 現在:使用spring 工廠(spring 容器)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
// 要想使我的銷毀方法也執行,必須要求:
// 1.容器必須先close,我的銷毀方法才會執行;
// 2.必須是單例的(spring所創建該bean的實例個數只有一個)即bean中的scope配置成默認即可。
// 因為此close方法在接口 ApplicationContext 中沒有定義,而在實現類中提供了該方法,我們可以使用反射,因為反射最后執行的就是實現類中的方法。
applicationContext.getClass().getMethod("close").invoke(applicationContext);
}
}
- 運行結果截圖:

- 問題1:后處理bean作用某一個目標類,還是所有目標類?
答:所有。 - 問題2:如何只作用一個?
答:通過獲取"參數2"beanName進行控制。例如:"xxx".equals(method.getName());
-
六、依賴注入Bean 的屬性(xml)
- 注入依賴對象可以采用:
手工裝配或自動裝配。在實際應用中建議使用手工裝配,因為自動裝配會產生未知情況,開發人員無法預見最終的裝配結果。- 手動裝配:一般進行配置信息都采用手動裝配。
- 基於xml裝配基於注解裝配 => 之后講解
- 構造方法注入
- 屬性setter方法注入
- 接口注入(spring不支持)
- 基於xml裝配基於注解裝配 => 之后講解
- 自動裝配:在struts 和spring 整合的時候使用自動裝配。
- byType:按類型裝配
- byName:按名稱裝配
- constructor:按構造裝配
- autodetect:不確定裝配(即自動裝配)
- 手動裝配:一般進行配置信息都采用手動裝配。
構造方法
Bean對象類:
public class User {
private Integer uid;
private String username;
private Integer age;
public User(Integer uid, String username) { // 構造方法一
super();
this.uid = uid;
this.username = username;
}
public User(String username, Integer age) { // 構造方法二
super();
this.username = username;
this.age = age;
}
// 省略getter 和 setter 方法
// ......
在spring容器中進行配置:
applicationContext.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">
<!--6.5.1、構造方法注入
<constructor-arg> 用於配置構造方法的一個參數argument
name :參數的名稱
value :設置普通數據
ref :設置引用數據,一般是另一個bean 的id值
index :參數的索引號,從0開始 。如果只有索引,匹配到了多個構造方法時,默認使用第一個。
type :確定參數類型
例如1:name屬性開發中不常用,因為使用該屬性需要關聯要實例化對象的源碼,否則name的值你就不知道。而一般開發中我們我們不會得到源碼。
<constructor-arg name="username" value="李曉藝"></constructor-arg>
<constructor-arg name="age" value="26"></constructor-arg>
例如2:類型type 和 索引index (這兩者結合使用)
<constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
注意:在開發中為了指定執行的是哪個構造方法,一般使用index屬性和type屬性結合的方式。
-->
<bean id="userId" class="entity.User">
<constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
</bean>
</beans>
setter方法
在spring容器中進行配置:
applicationContext.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">
<!--6.5.2、setter方法注入
* 注入的是普通數據 時
<property name="" value="值"></property>
等效
<property name="">
<value>值</value>
</property>
* 注入的是引用數據時
<property name="" ref="另一個bean的id"></property>
等效
<property name="">
<ref bean="另一個bean的id"></ref>
</property>
-->
<bean id="personId" class="entity.Person">
<property name="pname" value="曉藝"></property>
<property name="age">
<value>26</value>
</property>
<property name="homeAddr" ref="homeAddrId"></property>
<property name="companyAddr">
<ref bean="companyAddrId"></ref>
</property>
</bean>
<bean id="homeAddrId" class="entity.Address">
<property name="addr" value="山西運城"></property>
<property name="tel" value="911"></