Spring為singleton?bean注入prototype?bean
注:不想看具體代碼的話,可以直接看每個測試的總結(jié)。
環(huán)境
- Ubuntu 22.04
- IntelliJ IDEA 2022.1.3
- JDK 17.0.3
- Spring 5.3.21
準(zhǔn)備
創(chuàng)建Maven項目 test0707 。
修改 pom.xml 文件,添加依賴:
......
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.21</version>
</dependency>
......創(chuàng)建如下POJO:
Book:Book接口;PlayBook:Book實現(xiàn)類;StudyBook:Book實現(xiàn)類;Student1:Student1持有Book;
package pojo;
public interface Book {
public void show();
}
package pojo;
public class PlayBook implements Book{
public PlayBook() {
System.out.println("PlayBook constructor");
}
@Override
public void show() {
System.out.println("Play book!");
}
}
package pojo;
public class StudyBook implements Book{
public StudyBook() {
System.out.println("StudyBook constructor");
}
@Override
public void show() {
System.out.println("Study book!");
}
}
package pojo;
public class Student1 {
private String name;
private Book book;
public void setName(String name) {
this.name = name;
}
public void setBook(Book book) {
this.book = book;
}
public Book getBook() {
return book;
}
public Student1() {
System.out.println("Student1 constructor");
}
public void readBook() {
System.out.println("I am " + name);
book.show();
}
}在 src/main/resources 目錄下創(chuàng)建 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="playBook" class="pojo.PlayBook" scope="prototype"/>
<bean id="studyBook" class="pojo.StudyBook" scope="prototype"/>
<bean id="student1" class="pojo.Student1">
<property name="name" value="Jerry"/>
<property name="book" ref="playBook"/>
</bean>
</beans>在 src/test/java 目錄下創(chuàng)建測試:
public class Test0707 {}
測試0
創(chuàng)建測試用例:
@Test
public void test0() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
運行測試,如下:
Student1 constructor
PlayBook constructor
總結(jié):
- singleton的bean會在Spring初始化時創(chuàng)建實例(如本例中的
student1) - ;prototype的bean不會在Spring初始化時創(chuàng)建實例(如本例中的
studyBook);若把A注入B(B是singleton), - 則A在Spring初始化時隨著B一起創(chuàng)建實例(如本例中的
playBook)。 - 接上條,若把A注入B(B是singleton),如果A是singleton,則A在B之前創(chuàng)建實例。如果A是prototype,則A在B之后創(chuàng)建實例;
測試1
創(chuàng)建測試用例:
@Test
public void test1() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean student1 playBook");
var student1 = ctx.getBean("student1", Student1.class);
var student2 = ctx.getBean("student1", Student1.class);
System.out.println(student1 == student2);
var book1 = ctx.getBean("playBook", PlayBook.class);
var book2 = ctx.getBean("playBook", PlayBook.class);
System.out.println(book1 == book2);
}
運行測試,如下:
Student1 constructor
PlayBook constructor
before getBean student1 playBook
true
PlayBook constructor
PlayBook constructor
false
總結(jié):
singleton的bean,只在Spring初始化時創(chuàng)建實例, getBean() 不會創(chuàng)建實例;prototype的bean,不在Spring初始化時創(chuàng)建實例(注入例外),每次 getBean() 都會創(chuàng)建實例;
測試2
創(chuàng)建測試用例:
@Test
public void test2() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean student1");
var student1 = ctx.getBean("student1", Student1.class);
var student2 = ctx.getBean("student1", Student1.class);
System.out.println(student1 == student2);
System.out.println(student1.getBook() == student2.getBook());
}
運行測試,如下:
Student1 constructor
PlayBook constructor
before getBean student1
true
true
總結(jié):
把prototype的bean注入到singleton,多次調(diào)用 getBean() 獲取后者時,得到的是同一實例,同理,其持有的前者,也是同一實例。
測試3
多次調(diào)用 getBean() 方法獲取singleton bean時,對于所注入的prototype的bean,如果希望每次都獲取一個新的bean實例,可以使用 lookup-method 來配置。
例如:
<lookup-method name="getBook" bean="playBook"/>
完整例子如下:
創(chuàng)建POJO Student2 :
package pojo;
public abstract class Student2 {
private String name;
// private Book book;
public void setName(String name) {
this.name = name;
}
// public void setBook(Book book) {
// this.book = book;
// }
//
// public Book getBook() {
// return book;
// }
public abstract Book getBook();
public Student2() {
System.out.println("Student2 constructor");
}
public void readBook() {
System.out.println("I am " + name);
// book.show();
getBook().show();
}
}在 applicationContext.xml 文件中注冊bean:
<bean id="student2" class="pojo.Student2">
<property name="name" value="Jerry"/>
<!-- <property name="book" ref="playBook"/>-->
<lookup-method name="getBook" bean="playBook"/>
</bean>創(chuàng)建測試用例:
@Test
public void test3() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean student2");
var student1 = ctx.getBean("student2", Student2.class);
var student2 = ctx.getBean("student2", Student2.class);
System.out.println(student1 == student2);
System.out.println(student1.getBook() == student2.getBook());
}運行測試,如下:
......
Student2 constructor
before getBean student2
true
PlayBook constructor
PlayBook constructor
false
總結(jié):
Student2是抽象類,getBook()是抽象方法;Student2并不持有Book,只需使用getBook()方法來得到Book;- 在Spring配置中使用
lookup-method來指定方法名字(name屬性)和所獲取的bean(bean屬性);getBook()是Spring實現(xiàn)的,相當(dāng)于調(diào)用了 getBean()方法來得到實例,所以每次都能獲取一個新的實例(當(dāng)然前提是bean必須是prototype的);- singleton bean在Spring初始化時創(chuàng)建實例,lookup的bean不會隨著一起創(chuàng)建實例,只有在顯式調(diào)用lookup方法時才會
getBean()(類似懶加載);
到此這篇關(guān)于Spring為singleton bean注入prototype bean的文章就介紹到這了,更多相關(guān)Spring 注入prototype bean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot利用JSR303實現(xiàn)參數(shù)驗證的方法實例
這篇文章主要給大家介紹了關(guān)于Spring Boot利用JSR303實現(xiàn)參數(shù)驗證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
Java線程的創(chuàng)建介紹及實現(xiàn)方式示例
這篇文章主要為大家介紹了Java線程的創(chuàng)建介紹及實現(xiàn)方式示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
Java異常處理之try...catch...語句的使用進階
這篇文章主要介紹了Java異常處理之try...catch...語句的使用進階,重點在于牽扯相關(guān)IO使用時的資源調(diào)配情況,需要的朋友可以參考下2015-11-11
spring中@RestController和@Controller的區(qū)別小結(jié)
@RestController和@Controller這兩個注解用于創(chuàng)建Web應(yīng)用程序的控制器類,那么這兩個注解有哪些區(qū)別,本文就來介紹一下,并用示例代碼說明,感興趣的可以了解一下2023-09-09
如何修改json字符串中某個key對應(yīng)的value值
這篇文章主要介紹了如何修改json字符串中某個key對應(yīng)的value值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Mybatis動態(tài)SQL?foreach批量操作方法
這篇文章主要介紹了Mybatis動態(tài)SQL?foreach批量操作方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
Java 凍結(jié)或解除凍結(jié)Excel中的行和列的方法
這篇文章主要介紹了Java 凍結(jié)或解除凍結(jié)Excel中的行和列的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03

