Spring创建bean实例的常用四种方式


Spring创建bean实质是:通过一个类的全限定类型用反射去创建对象,最后放入一个Map集合中,需要使用某个bean的话可以用id类查找。

1、创建一个properties文件,列出需要创建的对象的全限定类型

userService=com.zjhc.beanByHand.UserService
bookService=com.zjhc.beanByHand.BookService

2、创建一个bean工厂类,来通过反射创建对象

public class BeanFactory {
    //定义一个静态的配置文件对象
    private static Properties props;
    //定义一个存放对象的Map容器
    private static Map<String,Object> beans;

    //通过静态块给props赋值
    static{
        try {
            //实例化props对象
            props = new Properties();
            //通过类加载器获取加载配置文件的流,并且将文件加到输入流
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            //加载bean配置文件
            props.load(in);
            //实例化容器
            beans = new HashMap<String, Object>();
            //取出配置文件种所有的key
            Enumeration keys = props.keys();
            while(keys.hasMoreElements()){
                //取出每个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = props.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //将创建好的对象放入容器
                beans.put(key,value);
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError("配置文件初始化创建对象异常....");
        }
    }

    //根据bean的名称获取对象
    public static Object getBean(String beanName){
        return beans.get(beanName);
    }
}

测试:

public class UserService {
    public static void main(String[] args) {
        BookService bookService = (BookService) BeanFactory.getBean("bookService");
        System.out.println(bookService);
    }
}
public class BookService {
    public static void main(String[] args) {
        UserService userService = (UserService) BeanFactory.getBean("userService");
        System.out.println(userService);
    }
}

结果:

com.zjhc.beanByHand.UserService@7440e464
com.zjhc.beanByHand.BookService@7440e464

一、通过反射调用构造方法创建bean对象

调用类的构造方法获取对应的bean实例,是使用最多的方式,这种方式只需要在xml的bean元素中指定class属性,spring容器内部会自动调用该类型的构造方法来创建bean对象,将其放在容器中以供使用

  1. 语法:
<bean id="bean名称" name="bean名称或者别名" class="bean的完整类型名称">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
</bean>
  • constructor-arg用于指定构造方法参数的值
  • index:构造方法中参数的位置,从0开始,依次递增
  • value:指定参数的值
  • ref:当插入的值为容器内其他bean的时候,这个值为容器中对应bean的名称
  1. UserModel类
@Data
public class UserModel {

    private String name;
    private int age;

    public UserModel(){
        this.name = "我是通过反射调用UserModel的无参构造创建的";
    }

    public UserModel(String name,int age){
        this.name = name;
        this.age = age;
    }
}
  1. beans.xml
 <!--通过反射调用无参构造创建bean-->
    <bean id="userModel1" class="com.zjhc.model.UserModel"/>

    <!--通过反射调用有参构造创建bean-->
    <bean id="userModel2" class="com.zjhc.model.UserModel">
        <constructor-arg index="0" value="我是通过反射调用UserModel有参构造创建的"/>
        <constructor-arg index="1" value="11"/>
    </bean>
  1. 测试
@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }
  1. 结果
    在这里插入图片描述

二、通过静态工厂方法创建bean对象

我们可以创建静态工厂,内部提供一些静态方法来生成所需要的对象,将这些静态方法创建的对象交给spring以供使用

  1. 语法
<bean id="bean名称" name="" class="静态工厂完整类名" factory-method="静态工厂的方法">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
</bean>
  1. 创建静态工厂
public class UserModelStaticFactory {

    /**
     * 静态无参方法创建Usermodel
     * @return
     */
    public static UserModel builder1(){
        System.out.println(UserModel.class+".builder1()");
        UserModel userModel = new UserModel();
        userModel.setName("我是通过静态的UserModel无参方法创建的");
        return userModel;
    }

    /**
     * 静态有参方法创建Usermodel
     * @return
     */
    public static UserModel builder2(String name,int age){
        System.out.println(UserModel.class+".builder2()");
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
  1. beans.xml
  <!--通过静态无参方法创建bean对象-->
    <bean id="ceateBeanByStaticFactory1" class="com.zjhc.model.UserModelStaticFactory" factory-method="builder1"/>

    <!--通过静态有参方法创建bean对象-->
    <bean id="createBeanByStaticFactory2" class="com.zjhc.model.UserModelStaticFactory" factory-method="builder2">
        <constructor-arg index="0" value="我是通过静态的UserModel有参方法创建的"/>
        <constructor-arg index="1" value="27"/>
    </bean>
  1. 测试
 @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }

5.结果
在这里插入图片描述

三、通过实例工厂方法创建bean对象

让spring容器去调用某些对象的某些实例方法来生成bean对象放在容器中以供使用

  1. 语法
<bean id="bean名称" factory-bean="需要调用的实例对象bean名称" factory-method="bean对象中的方法">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
</bean>
  1. 创建实例工厂
public class CreateBeanByBeanInstanceFactory {

    public UserModel builder1(){
        UserModel userModel = new UserModel();
        userModel.setName("我是通过实例工厂的无参方法创建的");
        return userModel;
    }

    public UserModel builder2(String name,int age){
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
  1. beans.xml
<!--实例工厂对象-->
<bean id="beanInstanceFactory" class="com.zjhc.model.CreateBeanByBeanInstanceFactory"/>
<!--通过实例工厂无参方法创建bean对象-->
<bean id="createBeanByBeabInstance1" factory-bean="beanInstanceFactory" factory-method="builder1"/>
<!--通过实例工厂有参方法创建bean对象-->
<bean id="createBeanByBeabInstance2" factory-bean="beanInstanceFactory" factory-method="builder2">
   <constructor-arg index="0" value="我是通过实例工厂的有参方法创建的"/>
   <constructor-arg index="1" value="28"/>
</bean>
  1. 测试
@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }
  1. 结果
    在这里插入图片描述

四、通过factoryBean创建bean对象

FactoryBean接口可以让spring容器通过这个接口的实现来创建我们需要的bean对象

  1. 接口源码
public interface FactoryBean<T> {

    /**
     * 返回创建好的对象
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回需要创建的对象的类型
     */
    @Nullable
    Class<?> getObjectType();

    /**
    * bean是否是单例的
    **/
    default boolean isSingleton() {
        return true;
    }
}

接口中有3个方法,前面2个方法需要我们去实现,getObject方法内部由开发者自己去实现对象的创建,然后将创建好的对象返回给Spring容器,getObjectType需要指定我们创建的bean的类型;最后一个方法isSingleton表示通过这个接口创建的对象是否是单例的,如果返回false,那么每次从容器中获取对象的时候都会调用这个接口的getObject() 去生成bean对象。

  1. 创建FactoryBean实现类
public class CreateBeanByFactoryBean implements FactoryBean<UserModel> {
    private int count = 1;

    @Nullable
    @Override
    public UserModel getObject() throws Exception {  //1
        UserModel userModel = new UserModel();
        userModel.setName("我是通过FactoryBean创建的第"+count+++ "对象");  //4
        userModel.setAge(29);
        return userModel;
    }

    @Nullable
    @Override
    public Class<?> getObjectType() {
        return UserModel.class;  //2
    }

    @Override
    public boolean isSingleton() {  //3
        return true;
    }
}

step1:返回了一个创建好的UserModel对象

step2:返回对象的Class对象

step3:返回true,表示创建的对象是单例的,那么我们每次从容器中获取这个对象的时候都是同一个对象

step4:此处用到了一个count,通过这个一会可以看出isSingleton不同返回值的时候从容器获取的bean是否是同一个
3. beans.xml

<!--通过FactoryBean创建bean对象-->
    <bean id="createBeanByFactoryBean" class="com.zjhc.model.CreateBeanByFactoryBean"/>
  1. 测试
  @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
        System.out.println("=======================================================");
        System.out.println("createBeanByFactoryBean:"+context.getBean("createBeanByFactoryBean"));
        System.out.println("createBeanByFactoryBean:"+context.getBean("createBeanByFactoryBean"));
    }
  1. 结果
    在这里插入图片描述
    注意最后4行输出,有3行输出的都是同一个createByFactoryBean,程序中通过getBean从spring容器中查找createByFactoryBean了3次,3次结果都是一样的,说明返回的都是同一个UserModel对象
  2. 测试非单例模式
    当这个方法返回false的时候,表示由这个FactoryBean创建的对象是多例的,那么我们每次从容器中getBean的时候都会去重新调用FactoryBean中的getObject方法获取一个新的对象。
    @Override
    public boolean isSingleton() {  //3
        return false;
    }
  1. 结果
    在这里插入图片描述
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring中,我们可以使用BeanFactory或者ApplicationContext来动态创建Bean实例。 1. 使用BeanFactory动态创建Bean实例 ```java DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Person.class); builder.addPropertyValue("name", "张三"); builder.addPropertyValue("age", 18); beanFactory.registerBeanDefinition("person", builder.getBeanDefinition()); Person person = (Person) beanFactory.getBean("person"); ``` 以上代码中,我们先创建一个DefaultListableBeanFactory实例,然后使用BeanDefinitionBuilder创建一个BeanDefinition,指定要创建Bean类型为Person,并设置Bean的属性值(name和age)。最后将BeanDefinition注册到BeanFactory中,然后通过getBean()方法获取动态创建的Person实例。 2. 使用ApplicationContext动态创建Bean实例 ```java GenericApplicationContext context = new GenericApplicationContext(); context.refresh(); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(Person.class); beanDefinition.getPropertyValues().add("name", "张三"); beanDefinition.getPropertyValues().add("age", 18); context.registerBeanDefinition("person", beanDefinition); Person person = (Person) context.getBean("person"); ``` 以上代码中,我们创建了一个GenericApplicationContext实例,并调用refresh()方法初始化容器。然后创建一个GenericBeanDefinition实例,设置Bean的类型为Person,并设置Bean的属性值(name和age)。最后将BeanDefinition注册到ApplicationContext中,然后通过getBean()方法获取动态创建的Person实例。 总的来说,使用Spring动态创建Bean实例的方法比较灵活,可以根据具体的需求来选择使用BeanFactory或者ApplicationContext。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一位不知名民工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值