软件编程
位置:首页>> 软件编程>> java编程>> Spring创建bean实例的几种方式分享

Spring创建bean实例的几种方式分享

作者:蓝黑2020  发布时间:2022-02-21 22:08:19 

标签:Spring,创建,bean,方式

前言

Spring常见的创建bean实例的方式有:

1.通过bean的class属性创建实例 

  • 无参构造器

  • 带参构造器

2.工厂方法

  • 静态工厂方法

  • 实例工厂方法

3.工厂bean

关于每种方式的Spring配置,详见文末总结。

环境

  • Ubuntu 22.04

  • IntelliJ IDEA 2022.1.3

  • JDK 17.0.3

  • Spring 5.3.21 准备

创建Maven项目 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 目录下创建 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 目录下创建测试:

public class Test0705 {
}

通过bean的class属性创建实例(无参构造器)

注:这是最常见的创建bean的方式。我其它文档也用过相似代码。如果已熟悉可直接略过。

创建如下POJO:

  • Axe :Axe接口;

  • StoneAxe :Axe实现类;

  • SteelAxe :Axe实现类;

  • 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>
   ......

创建测试用例:

@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();
   }

运行测试,如下:

StoneAxe constructor
SteelAxe constructor
Person constructor
before getBean person
I am Tom
Stone axe!

通过bean的class属性创建实例(带参构造器)

注:这是较为常见的创建bean的方式。我其它文档也用过相似代码。如果已熟悉可直接略过。

创建如下POJO:

  • Book :Book接口;

  • PlayBook :Book实现类;

  • StudyBook :Book实现类;

  • 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>
   ......

创建测试用例:

@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();
   }

运行测试,如下:

......
PlayBook constructor
StudyBook constructor
Student constructor
before getBean student
I am Jerry
Play book!

工厂方法(静态工厂方法)

配置:

  • class 属性指向静态工厂类

  • factory-method 属性指向静态工厂方法

注:如果静态工厂方法需要参数,则通过 constructor-arg 来指定。

例如:

<bean id="dog" class="factory.AnimalFactory" factory-method="getAnimal">
       <constructor-arg value="dog"/>
       <property name="name" value="Snoopy"/>
   </bean>

当调用 ctx.getBean("dog") 时,Spring会调用 AnimalFactory 类的静态方法 getAnimal() ,并传入参数 "dog",创建一个Animal的实例并返回。

注:同普通的bean一样,其默认scope是 singleton ,多次调用 ctx.getBean("dog") 返回的是同一个实例(在Spring初始化时生产bean)。

完整例子如下:

创建如下POJO:

  • Animal :Animal接口;

  • Dog :Animal实现类;

  • Cat :Animal实现类;

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...");
   }
}

创建工厂类 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>

创建测试用例:

@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();
   }

运行测试,如下:

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...

工厂方法(实例工厂方法)

实例工厂方法跟静态工厂方法很相像,主要区别是:

  • 静态工厂方法:不用实例化工厂,只需直接调用工厂类的静态工厂方法;

  • 实例工厂方法:工厂方法不是静态的,因此需要通过 factory-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>

其它都一样。

完整例子如下:

创建如下POJO:

  • Fruit :Fruit接口;

  • Apple :Fruit实现类;

  • Banana :Fruit实现类;

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!");
   }
}

创建工厂类 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>
   ......

创建测试用例:

@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();
   }

运行测试,如下:

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是指实现了 FactoryBean 接口的类。

FactoryBean 接口有3个方法:

  • T getObject() throws :创建产品实例;

  • Class<?> getObjectType() :获取产品的类;

  • default boolean isSingleton() {return true;} :是否单例,默认值为true;

实现 FactoryBean 接口,则无需再配置 factory-method ,Spring知道如何创建产品(通过 getObject() 方法)。

比如:

<bean id="benz" class="factory.CarFactoryBean">
       <property name="type" value="benz"/>
   </bean>

注意:该配置看起来很像普通的bean,实际上因为 CarFactoryBean 实现了 FactoryBean 接口,当调用 ctx.getBean("benz") 方法时,返回的并不是 CarFactoryBean 的实例,而是其 getObject() 方法的返回值。

注:默认scope是 singleton ,多次调用 ctx.getBean("dog") 返回的是同一个实例。如果在 CarFactoryBean 中override isSingleton() 方法并返回false,则每次调用ctx.getBean("benz") 返回的是不同对象。

注:工厂bean跟其它bean有一点不同,即使是singleton,它也不是在Spring初始化时生产bean,而是在第一次调用 ctx.getBean() 时才生产bean。

完整例子如下:

创建如下POJO:

  • Car :Car接口;

  • Benz :Car实现类;

  • Audi :Car实现类;

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");
   }
}

创建工厂类 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>
   ......

创建测试用例:

@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();
   }

运行测试,如下:

before getBean benz audi
creating new Car object
Benz constructor
Go go go!
creating new Car object
Audi constructor
OOOO

<!-- 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>

来源:https://blog.csdn.net/duke_ding2/article/details/125648736

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com