Spring創(chuàng)建bean實(shí)例的幾種方式分享
前言
Spring常見的創(chuàng)建bean實(shí)例的方式有:
1.通過bean的class屬性創(chuàng)建實(shí)例
- 無參構(gòu)造器
- 帶參構(gòu)造器
2.工廠方法
- 靜態(tài)工廠方法
- 實(shí)例工廠方法
3.工廠bean
關(guān)于每種方式的Spring配置,詳見文末總結(jié)。
環(huán)境
- Ubuntu 22.04
- IntelliJ IDEA 2022.1.3
- JDK 17.0.3
- Spring 5.3.21 準(zhǔn)備
創(chuàng)建Maven項(xiàng)目 test0705 。
修改 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>
......
在 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">
</beans>
在 src/test/java 目錄下創(chuàng)建測試:
public class Test0705 {
}通過bean的class屬性創(chuàng)建實(shí)例(無參構(gòu)造器)
注:這是最常見的創(chuàng)建bean的方式。我其它文檔也用過相似代碼。如果已熟悉可直接略過。
創(chuàng)建如下POJO:
Axe:Axe接口;StoneAxe:Axe實(shí)現(xiàn)類;SteelAxe:Axe實(shí)現(xiàn)類;Person:Person持有Axe;
package pojo;
public interface Axe {
public void chop();
}
package pojo;
public class StoneAxe implements Axe{
public StoneAxe() {
System.out.println("StoneAxe constructor");
}
@Override
public void chop() {
System.out.println("Stone axe!");
}
}
package pojo;
public class SteelAxe implements Axe{
public SteelAxe() {
System.out.println("SteelAxe constructor");
}
@Override
public void chop() {
System.out.println("Steel axe!");
}
}
package pojo;
public class Person {
private String name;
private Axe axe;
public void setAxe(Axe axe) {
this.axe = axe;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("Person constructor");
}
public void useAxe() {
System.out.println("I am " + name);
axe.chop();
}
}
在 applicationContext.xml 中注冊bean:
......
<bean id="stoneAxe" class="pojo.StoneAxe"/>
<bean id="steelAxe" class="pojo.SteelAxe"/>
<bean id="person" class="pojo.Person">
<property name="name" value="Tom"/>
<property name="axe" ref="stoneAxe"/>
</bean>
......
創(chuàng)建測試用例:
@Test
public void test1() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean person");
var person = ctx.getBean("person", Person.class);
person.useAxe();
}
運(yùn)行測試,如下:
StoneAxe constructor SteelAxe constructor Person constructor before getBean person I am Tom Stone axe!
通過bean的class屬性創(chuàng)建實(shí)例(帶參構(gòu)造器)
注:這是較為常見的創(chuàng)建bean的方式。我其它文檔也用過相似代碼。如果已熟悉可直接略過。
創(chuàng)建如下POJO:
Book:Book接口;PlayBook:Book實(shí)現(xiàn)類;StudyBook:Book實(shí)現(xiàn)類;Student:Student持有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 Student {
private String name;
private Book book;
public Student(String name, Book book) {
System.out.println("Student constructor");
this.name = name;
this.book = book;
}
public void readBook() {
System.out.println("I am " + name);
book.show();
}
}
在 applicationContext.xml 中注冊bean:
......
<bean id="playBook" class="pojo.PlayBook"/>
<bean id="studyBook" class="pojo.StudyBook"/>
<bean id="student" class="pojo.Student">
<constructor-arg index="0" value="Jerry"/>
<constructor-arg index="1" ref="playBook"/>
</bean>
......
創(chuàng)建測試用例:
@Test
public void test2() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean student");
var student = ctx.getBean("student", Student.class);
student.readBook();
}
運(yùn)行測試,如下:
......
PlayBook constructor
StudyBook constructor
Student constructor
before getBean student
I am Jerry
Play book!
工廠方法(靜態(tài)工廠方法)
配置:
class屬性指向靜態(tài)工廠類factory-method屬性指向靜態(tài)工廠方法
注:如果靜態(tài)工廠方法需要參數(shù),則通過 constructor-arg 來指定。
例如:
<bean id="dog" class="factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="dog"/>
<property name="name" value="Snoopy"/>
</bean>
當(dāng)調(diào)用 ctx.getBean("dog") 時(shí),Spring會調(diào)用 AnimalFactory 類的靜態(tài)方法 getAnimal() ,并傳入?yún)?shù) "dog",創(chuàng)建一個(gè)Animal的實(shí)例并返回。
注:同普通的bean一樣,其默認(rèn)scope是 singleton ,多次調(diào)用 ctx.getBean("dog") 返回的是同一個(gè)實(shí)例(在Spring初始化時(shí)生產(chǎn)bean)。
完整例子如下:
創(chuàng)建如下POJO:
Animal:Animal接口;Dog:Animal實(shí)現(xiàn)類;Cat:Animal實(shí)現(xiàn)類;
package pojo;
public interface Animal {
public void cry();
}
package pojo;
public class Dog implements Animal{
private String name;
public void setName(String name) {
this.name = name;
}
public Dog() {
System.out.println("Dog constructor");
}
@Override
public void cry() {
System.out.println("I am " + name);
System.out.println("Wang wang...");
}
}
package pojo;
public class Cat implements Animal{
private String name;
public void setName(String name) {
this.name = name;
}
public Cat() {
System.out.println("Cat constructor");
}
@Override
public void cry() {
System.out.println("I am " + name);
System.out.println("Miao Miao...");
}
}
創(chuàng)建工廠類 AnimalFactory :
package factory;
import pojo.Animal;
import pojo.Cat;
import pojo.Dog;
public class AnimalFactory {
public static Animal getAnimal(String type) {
System.out.println("creating new Animal object");
if (type.equalsIgnoreCase("dog")) {
return new Dog();
} else if (type.equalsIgnoreCase("cat")) {
return new Cat();
} else {
return null;
}
}
}
在 applicationContext.xml 中注冊bean:
<bean id="dog" class="factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="dog"/>
<property name="name" value="Snoopy"/>
</bean>
<bean id="cat" class="factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="cat"/>
<property name="name" value="Kitty"/>
</bean>
創(chuàng)建測試用例:
@Test
public void test3() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean dog cat");
var animal1 = ctx.getBean("dog", Animal.class);
animal1.cry();
var animal2 = ctx.getBean("cat", Animal.class);
animal2.cry();
}
運(yùn)行測試,如下:
creating new Animal object
Dog constructor
creating new Animal object
Cat constructor
before getBean dog cat
I am Snoopy
Wang wang...
I am Kitty
Miao Miao...
工廠方法(實(shí)例工廠方法)
實(shí)例工廠方法跟靜態(tài)工廠方法很相像,主要區(qū)別是:
- 靜態(tài)工廠方法:不用實(shí)例化工廠,只需直接調(diào)用工廠類的靜態(tài)工廠方法;
- 實(shí)例工廠方法:工廠方法不是靜態(tài)的,因此需要通過
factory-bean來指定工廠類的實(shí)例。
比如:
<bean id="fruitFactory" class="factory.FruitFactory"/>
<bean id="apple" factory-bean="fruitFactory" factory-method="getFruit">
<constructor-arg value="apple"/>
<property name="name" value="Fuji"/>
</bean>
其它都一樣。
完整例子如下:
創(chuàng)建如下POJO:
Fruit:Fruit接口;Apple:Fruit實(shí)現(xiàn)類;Banana:Fruit實(shí)現(xiàn)類;
package pojo;
public interface Fruit {
public void describe();
}
package pojo;
public class Apple implements Fruit {
private String name;
public void setName(String name) {
this.name = name;
}
public Apple() {
System.out.println("Apple constructor");
}
@Override
public void describe() {
System.out.println("I am " + name);
System.out.println("Juicy!");
}
}
package pojo;
public class Banana implements Fruit {
private String name;
public void setName(String name) {
this.name = name;
}
public Banana() {
System.out.println("Banana constructor");
}
@Override
public void describe() {
System.out.println("I am " + name);
System.out.println("Sweet!");
}
}創(chuàng)建工廠類 FruitFactory :
package factory;
import pojo.Apple;
import pojo.Banana;
import pojo.Fruit;
public class FruitFactory {
public Fruit getFruit(String type) {
System.out.println("creating new Fruit object");
if (type.equalsIgnoreCase("apple")) {
return new Apple();
} else if (type.equalsIgnoreCase("banana")) {
return new Banana();
} else {
return null;
}
}
}在 applicationContext.xml 中注冊bean:
......
<bean id="fruitFactory" class="factory.FruitFactory"/>
<bean id="apple" factory-bean="fruitFactory" factory-method="getFruit">
<constructor-arg value="apple"/>
<property name="name" value="Fuji"/>
</bean>
<bean id="banana" factory-bean="fruitFactory" factory-method="getFruit">
<constructor-arg value="banana"/>
<property name="name" value="Pisang"/>
</bean>
......
創(chuàng)建測試用例:
@Test
public void test4() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean apple banana");
var fruit1 = ctx.getBean("apple", Fruit.class);
fruit1.describe();
var fruit2 = ctx.getBean("banana", Fruit.class);
fruit2.describe();
}
運(yùn)行測試,如下:
creating new Fruit object
Apple constructor
creating new Fruit object
Banana constructor
before getBean apple banana
I am Fuji
Juicy!
I am Pisang
Sweet!
工廠bean
工廠bean是指實(shí)現(xiàn)了 FactoryBean 接口的類。
FactoryBean 接口有3個(gè)方法:
T getObject() throws:創(chuàng)建產(chǎn)品實(shí)例;Class<?> getObjectType():獲取產(chǎn)品的類;default boolean isSingleton() {return true;}:是否單例,默認(rèn)值為true;
實(shí)現(xiàn) FactoryBean 接口,則無需再配置 factory-method ,Spring知道如何創(chuàng)建產(chǎn)品(通過 getObject() 方法)。
比如:
<bean id="benz" class="factory.CarFactoryBean">
<property name="type" value="benz"/>
</bean>
注意:該配置看起來很像普通的bean,實(shí)際上因?yàn)?CarFactoryBean 實(shí)現(xiàn)了 FactoryBean 接口,當(dāng)調(diào)用 ctx.getBean("benz") 方法時(shí),返回的并不是 CarFactoryBean 的實(shí)例,而是其 getObject() 方法的返回值。
注:默認(rèn)scope是 singleton ,多次調(diào)用 ctx.getBean("dog") 返回的是同一個(gè)實(shí)例。如果在 CarFactoryBean 中override isSingleton() 方法并返回false,則每次調(diào)用ctx.getBean("benz") 返回的是不同對象。
注:工廠bean跟其它bean有一點(diǎn)不同,即使是singleton,它也不是在Spring初始化時(shí)生產(chǎn)bean,而是在第一次調(diào)用 ctx.getBean() 時(shí)才生產(chǎn)bean。
完整例子如下:
創(chuàng)建如下POJO:
Car:Car接口;Benz:Car實(shí)現(xiàn)類;Audi:Car實(shí)現(xiàn)類;
package pojo;
public interface Car {
public void run();
}
package pojo;
public class Benz implements Car{
public Benz() {
System.out.println("Benz constructor");
}
@Override
public void run() {
System.out.println("Go go go!");
}
}package pojo;
public class Audi implements Car{
public Audi() {
System.out.println("Audi constructor");
}
@Override
public void run() {
System.out.println("OOOO");
}
}創(chuàng)建工廠類 FactoryBean :
package factory;
import org.springframework.beans.factory.FactoryBean;
import pojo.Audi;
import pojo.Benz;
import pojo.Car;
public class CarFactoryBean implements FactoryBean {
private String type;
public void setType(String type) {
this.type = type;
}
@Override
public Object getObject() throws Exception {
System.out.println("creating new Car object");
if (type.equalsIgnoreCase("benz")) {
return new Benz();
} else if (type.equalsIgnoreCase("audi")) {
return new Audi();
} else return null;
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
}在 applicationContext.xml 中注冊bean:
......
<bean id="benz" class="factory.CarFactoryBean">
<property name="type" value="benz"/>
</bean>
<bean id="audi" class="factory.CarFactoryBean">
<property name="type" value="audi"/>
</bean>
......
創(chuàng)建測試用例:
@Test
public void test5() {
var ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("before getBean benz audi");
var car1 = ctx.getBean("benz", Car.class);
car1.run();
var car2 = ctx.getBean("audi", Car.class);
car2.run();
}
運(yùn)行測試,如下:
before getBean benz audi
creating new Car object
Benz constructor
Go go go!
creating new Car object
Audi constructor
OOOO
總結(jié)
......
<!-- 通過bean的class屬性創(chuàng)建bean實(shí)例(無參構(gòu)造器) -->
<bean id="stoneAxe" class="pojo.StoneAxe"/>
<bean id="steelAxe" class="pojo.SteelAxe"/>
<bean id="person" class="pojo.Person">
<property name="name" value="Tom"/>
<property name="axe" ref="stoneAxe"/>
</bean>
<!-- 通過bean的class屬性創(chuàng)建bean實(shí)例(帶參構(gòu)造器) -->
<bean id="playBook" class="pojo.PlayBook"/>
<bean id="studyBook" class="pojo.StudyBook"/>
<bean id="student" class="pojo.Student">
<constructor-arg index="0" value="Jerry"/>
<constructor-arg index="1" ref="playBook"/>
</bean>
<!-- 通過靜態(tài)工廠方法創(chuàng)建bean實(shí)例 -->
<bean id="dog" class="factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="dog"/>
<property name="name" value="Snoopy"/>
</bean>
<bean id="cat" class="factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="cat"/>
<property name="name" value="Kitty"/>
</bean>
<!-- 通過實(shí)例工廠方法創(chuàng)建bean實(shí)例 -->
<bean id="fruitFactory" class="factory.FruitFactory"/>
<bean id="apple" factory-bean="fruitFactory" factory-method="getFruit">
<constructor-arg value="apple"/>
<property name="name" value="Fuji"/>
</bean>
<bean id="banana" factory-bean="fruitFactory" factory-method="getFruit">
<constructor-arg value="banana"/>
<property name="name" value="Pisang"/>
</bean>
<!-- 通過工廠bean創(chuàng)建bean實(shí)例 -->
<bean id="benz" class="factory.CarFactoryBean">
<property name="type" value="benz"/>
</bean>
<bean id="audi" class="factory.CarFactoryBean">
<property name="type" value="audi"/>
</bean>
......
此外,有幾點(diǎn)說明:
使用工廠bean來管理的bean,即使scope是 singleton ,也并不是在Spring初始化時(shí)生產(chǎn)對象的,而是在第一次調(diào)用 ctx.getBean() 方法時(shí)生產(chǎn)的。
Spring整合MyBatis,使用了 SqlSessionFactoryBean 、 MapperFactoryBean ,這兩個(gè)就是工廠bean,它們實(shí)現(xiàn)了 FactoryBean 接口。前者生產(chǎn) SqlSessionFactory ,后者生產(chǎn) Mapper 。比如:
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- <property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="mapperLocations" value="classpath:dao/*.xml"/>
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
</bean>
<bean id="myMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="dao.MyMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>到此這篇關(guān)于Spring創(chuàng)建bean實(shí)例的幾種方式分享的文章就介紹到這了,更多相關(guān)Spring創(chuàng)建bean 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nacos-SpringBoot框架啟動(dòng)不加載bootstrap.yml的解決
這篇文章主要介紹了Nacos-SpringBoot框架啟動(dòng)不加載bootstrap.yml的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
SpringCloud+SpringBoot項(xiàng)目搭建結(jié)構(gòu)層次的實(shí)例
這篇文章詳細(xì)介紹了SpringCloud項(xiàng)目的架構(gòu)層次及其搭建經(jīng)驗(yàn),包括Controller層、Service層、Repository層、Entity層、DTO層、Exception層等,通過文字和圖片的形式,幫助讀者理解如何組織和實(shí)現(xiàn)一個(gè)SpringBoot項(xiàng)目的不同層次2025-01-01
Spring注解驅(qū)動(dòng)之ApplicationListener用法解讀
這篇文章主要介紹了Spring注解驅(qū)動(dòng)之ApplicationListener用法解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Spring實(shí)戰(zhàn)之使用@Resource配置依賴操作示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之使用@Resource配置依賴操作,結(jié)合實(shí)例形式分析了Spring使用@Resource配置依賴具體步驟、實(shí)現(xiàn)及測試案例,需要的朋友可以參考下2019-12-12
初識Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符
Java是一種強(qiáng)類型語言,每個(gè)變量都必須聲明其數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10

