前言:

  • Spring容器创建bean对象,一般通过反射机制查找bean元素的class属性值来找到要实例化的类,从而实例化bean对象。这便是调用构造方法来实例化bean对象

  • 在某些情况下,若采用简单的xml配置文件方式,比如写大量的bean元素,会大大增加工作量。Spring容器还添加了一些bean元素的属性来减少配置文件的编写工作量。比如,静态工厂方法(factory-method属性)、实例化工厂方法(factory-bean属性、factory-method属性)

  • 此外,Spring还提供了FactoryBean接口来支持开发人员自定义实例化bean对象的方式

案例源码:码云仓库的base-003子项目

1、调用构造方法创建bean对象

  • 解释:

    • 调用类的构造方法获取对应的bean实例
    • 在配置文件中,只需设置好bean元素的class属性,Spring容器会自动调用构造方法来创建bean对象
  • 基本格式:

    <bean id="bean名称" name="bean名称或者别名" class="完整类路径"><constructor-arg index="0" value="bean的值" ref="引用的bean名称" /><constructor-arg index="1" value="bean的值" ref="引用的bean名称" />....
    </bean>
    
    • constructor-arg:用于指定构造方法参数的值

      • index:构造方法中参数的位置,从0开始,依次递增
      • value:
        • 给构造参数设置值,值的类型只能为简单类型,如byte,int,long,float,double,boolean,Byte,Long,Float,Double,枚举等;
        • Spring容器在注入属性时,会自动将value值转换为对应的类型
      • ref:当插入的值为容器内其他bean的时候,这个值为容器中对应bean的名称
    • 不指定constructor-arg,则Spring容器会调用默认无参构造方法来创建bean对象;若指定constructor-arg,则调用有参构造方法来创建bean对象
    • 指定constructor-argindex要和实体类的属性一一对应,不可缺少
  • 案例

    • 实体类

      package com.spring.study;public class Dog {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Dog() {this.name = "小白";this.age = 1;}public Dog(String name, int age) {this.name = name;this.age = age;}
      }
      
    • 配置文件

      <?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="dog1" class="com.spring.study.Dog"/><!--    调用有参构造方法创建bean对象--><bean id="dog2" class="com.spring.study.Dog"><constructor-arg index="0" value="大黄"/><constructor-arg index="1" value="2"/></bean>
      </beans>
      
    • 测试类

      package com.spring.test;import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestConstructor {public static void main(String[] args) {// 1、定义bean配置文件位置String classPathXml = "classpath:applicationContext.xml";// 2、创建ClassPathXmlApplicationContext容器,给容器指定需要加载的bean配置文件ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);// 3、获取容器中所有bean对象//获取所有bean对象的bean名称String[] beanNames = context.getBeanDefinitionNames();//打印输出bean对象for (String beanName : beanNames){Dog dog = context.getBean(beanName,Dog.class);System.out.println(String.format("bean名称:%s,bean对象的name值:%s,bean对象的age值:%d",beanName,dog.getName(),dog.getAge()));}}
      }
      
    • 运行结果

      bean名称:dog1,bean对象的name值:小白,bean对象的age值:1
      bean名称:dog2,bean对象的name值:大黄,bean对象的age值:2
      

2、静态工厂方法创建bean对象

  • 解释:

    • 创建静态工厂,内部提供一些静态方法来生成所需要的bean对象,将这些静态方法创建的对象交给spring容器以供使用
  • 基本格式:

    <bean id="bean名称" class="静态工厂完整类路径" factory-method="静态工厂的方法名"><constructor-arg index="0" value="bean的值" ref="引用的bean名称" /><constructor-arg index="1" value="bean的值" ref="引用的bean名称" />....
    </bean>
    
    • factory-method:其值为被调用的bean对象的方法名,用该方法来返回所需要的bean对象。该方法必须为静态方法
  • 案例

    • 实体类为Dog类

    • 静态工厂

      package com.spring.study;public class DogStaticFactory {/*** 静态无参方法创建Dog对象* @return*/public static Dog buildOne(){System.out.println("==============静态无参buildOne方法被调用==============");return new Dog();}/*** 静态有参方法创建Dog对象* @param name* @param age* @return*/public static Dog buildTwo(String name, int age){System.out.println("==============静态有参buildTwo方法被调用==============");return new Dog(name, age);}
      }
      
    • 配置文件

      <?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="dog1" class="com.spring.study.DogStaticFactory" factory-method="buildOne"/><!--    通过工厂调用静态有参方法创建bean对象--><bean id="dog2" class="com.spring.study.DogStaticFactory" factory-method="buildTwo"><constructor-arg index="0" value="二狗子"/><constructor-arg index="1" value="3"/></bean>
      </beans>
      
    • 测试类

      package com.spring.test;import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestStaticFactory {public static void main(String[] args) {// 1、定义bean配置文件位置String classPathXml = "classpath:dogStaticFactory.xml";// 2、创建ClassPathXmlApplicationContext容器,给容器指定需要加载的bean配置文件ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);// 3、获取容器中所有bean对象//获取所有bean对象的bean名称String[] beanNames = context.getBeanDefinitionNames();//打印输出bean对象for (String beanName : beanNames){Dog dog = context.getBean(beanName,Dog.class);System.out.println(String.format("bean名称:%s,bean对象的name值:%s,bean对象的age值:%d",beanName,dog.getName(),dog.getAge()));}}
      }
      
    • 运行结果

      ==============静态无参buildOne方法被调用==============
      ==============静态有参buildTwo方法被调用==============
      bean名称:dog1,bean对象的name值:小白,bean对象的age值:1
      bean名称:dog2,bean对象的name值:二狗子,bean对象的age值:3
      

3、实例工厂方法创建bean对象

  • 解释:

    • 使Spring容器去调用某些已实例化的bean对象的实例方法来生成所需要的bean对象
  • 基本格式:

    <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名称" />....
    </bean>
    
    • factory-bean:其值为要调用的bean对象的bean名称
    • factory-method:其值为被调用的bean对象的方法名,用该方法来返回所需要的bean对象
    • 流程:容器通过factory-bean的值找到某个bean对象,然后根据factory-method的值来确定要调用该bean对象的某个方法,最后调用该方法来返回所需要的bean对象
  • 案例

    • 实体类为Dog类

    • 实例工厂类

      package com.spring.study;public class DogInstanceFactory {/*** 通过调用无参构造方法创建bean对象* @return*/public Dog buildOne(){System.out.println("==============buildOne方法被调用==============");return new Dog();}/*** 通过调用有参构造方法创建bean对象* @param name* @param age* @return*/public Dog buildTwo(String name, int age){System.out.println("==============buildTwo方法被调用==============");return new Dog(name, age);}
      }
      
    • 配置文件

      <?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="dogIntanceFactory" class="com.spring.study.DogInstanceFactory"/><!--    通过工厂调用无参构造方法创建bean对象--><bean id="dog1" factory-bean="dogIntanceFactory" factory-method="buildOne"/><!--    通过工厂调用有参构造方法创建bean对象--><bean id="dog2" factory-bean="dogIntanceFactory" factory-method="buildTwo"><constructor-arg index="0" value="狗剩"/><constructor-arg index="1" value="4"/></bean>
      </beans>
      
    • 测试类

      package com.spring.test;import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestInstanceFactory {public static void main(String[] args) {// 1、定义bean配置文件位置String classPathXml = "classpath:dogInstanceFactory.xml";// 2、创建ClassPathXmlApplicationContext容器,给容器指定需要加载的bean配置文件ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);// 3、获取容器中所有bean对象//获取所有bean对象的bean名称String[] beanNames = new String[]{"dog1","dog2"};//打印输出bean对象for (String beanName : beanNames){Dog dog = context.getBean(beanName,Dog.class);System.out.println(String.format("bean名称:%s,bean对象的name值:%s,bean对象的age值:%d",beanName,dog.getName(),dog.getAge()));}}
      }
      
    • 运行结果

      ==============buildOne方法被调用==============
      ==============buildTwo方法被调用==============
      bean名称:dog1,bean对象的name值:小白,bean对象的age值:1
      bean名称:dog2,bean对象的name值:狗剩,bean对象的age值:4
      

4、实现FactoryBean接口创建bean对象

  • 一般情况下,Spring容器通过反射机制利用bean元素的class属性指定实现类来实例化Bean。在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑

  • 以Bean结尾,表示它是一个Bean。不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该bean对象的bean名称从BeanFactory中获取的实际上是FactoryBean的getObject方法返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在bean对象的bean名称前面加一个&符号来获取。以Dog类举例,

    Dog dog = new ClassPathXmlApplicationContext("classpath:dogFactoryBean.xml).getBean("&dog2"))
    
  • FactoryBean接口源码

    package org.springframework.beans.factory;import org.springframework.lang.Nullable;public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";/*** 返回创建好的对象*/@NullableT getObject() throws Exception;/*** 返回需要创建的对象的类型*/@NullableClass<?> getObjectType();/*** bean对象是否是单例对象**/default boolean isSingleton() {return true;}
    }
    
    • getObject方法,由开发人员实现bean对象的创建方式,并返回bean对象给Spring容器
    • getObjectType方法,由开发人员指定需要创建的bean的类型
    • isSingleton方法,表示通过这个接口创建的对象是否是单例的,如果返回false,那么每次从容器中获取对象都会调用getObject方法去生成新的bean对象。默认是单例对象。
  • 基本格式:

    <bean id="bean名称" class="FactoryBean接口实现类" />
    
    • 格式同bean元素
  • 案例

    • 实体类即Dog类

    • FactoryBean接口实现类

      package com.spring.study;import org.springframework.beans.factory.FactoryBean;public class DogFactoryBean implements FactoryBean<Dog> {/*** 设置是否为单例对象*/private boolean singleton;public boolean getSingleton() {return singleton;}public void setSingleton(boolean singleton) {this.singleton = singleton;}/*** 返回已创建的对象--调用无参构造方法创建的bean对象* @return* @throws Exception*/@Overridepublic Dog getObject() throws Exception {if (this.singleton){System.out.println("=========即将打印单例对象=========");}else{System.out.println("=========即将打印非单例对象=========");}return new Dog();}/*** 返回需要创建的对象的类型* @return*/@Overridepublic Class<?> getObjectType() {return Dog.class;}/*** 设置bean对象是否为单例* @return*/@Overridepublic boolean isSingleton() {return this.singleton;}public DogFactoryBean(boolean singleton) {this.singleton = singleton;}public DogFactoryBean() {}
      }
      
      • 私有属性singleton为布尔类型,默认值为false,所以该实现类的getObject方法返回的bean对象默认为非单例对象
    • 配置文件

      <?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"><!--    定义DogFactoryBean对象,要获取的Dog对象为非单例对象--><bean id="dog1" class="com.spring.study.DogFactoryBean"/><!--    定义DogFactoryBean对象,要获取的Dog对象为单例对象--><bean id="dog2" class="com.spring.study.DogFactoryBean"><constructor-arg index="0" value="true"/></bean></beans>
      
    • 测试类

      package com.spring.test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestFactoryBean {public static void main(String[] args) {// 1、定义bean配置文件位置String classPathXml = "classpath:dogFactoryBean.xml";// 2、创建ClassPathXmlApplicationContext容器,给容器指定需要加载的bean配置文件ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);// 3、获取容器中所有的bean对象的bean名称String[] beanNames = context.getBeanDefinitionNames();// 4、打印输出bean对象的内存地址,以此来判断在单例模式下,获得的bean对象是否为同一个对象for (String beanName : beanNames){for (int i = 0; i < 2; i++){System.out.println(String.format("bean名称:%s,bean对象内存地址:%s",beanName,context.getBean(beanName)));}}System.out.println("FactoryBean实现类对象:" + context.getBean("&dog2"));}
      }
      
    • 运行结果

      =========即将打印非单例对象=========
      bean名称:dog1,bean对象内存地址:com.spring.study.Dog@cd2dae5
      =========即将打印非单例对象=========
      bean名称:dog1,bean对象内存地址:com.spring.study.Dog@3a883ce7
      =========即将打印单例对象=========
      bean名称:dog2,bean对象内存地址:com.spring.study.Dog@4973813a
      bean名称:dog2,bean对象内存地址:com.spring.study.Dog@4973813a
      FactoryBean实现类对象:com.spring.study.DogFactoryBean@6321e813
      
      • 从运行结果打印的内存地址来看,若为单例模式,则每次创建bean对象时,从头到尾,只调用一次getObject方法且使用同一个bean对象;若为非单例模式,则每次创建bean对象时,都需要调用getObject方法并创建新的bean对象

    参考:Java充电社、甜菜波波

IOC容器创建bean对象的4种方式相关推荐

  1. java class 生成对象_Java反射机制(创建Class对象的三种方式)

    1:SUN提供的反射机制的类: java.lang.Class java.lang.reflect.Constructor java.lang.reflect.Field java.lang.refl ...

  2. JDBC 创建连接对象的三种方式 、 properties文件的建立、编辑和信息获取

    创建连接对象的三种方式 //第一种方式Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/m ...

  3. JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试

    Spring框架学习路线 Spring的IOC Spring的AOP,AspectJ Spring的事务管理,三大框架的整合 Spring框架概述 什么是Spring?  Spring是分层的Java ...

  4. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

  5. spring创建复杂对象的三种方式

    什么是复杂对象? 复杂对象是指我们通过new创建不了的对象,此对象的创建还需要别的条件,如jdbc的Connection.mybatis的sqlSesscionFactory. 一.factoryBe ...

  6. JavaScript 创建类/对象的几种方式

    在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的. JS对象是一种复合类型,它允许你通过变量 ...

  7. 创建javascript对象的几种方式

    ECMAScript提供的对象有:String.Date.Array.Boolean.Math.Number.RegExp.Global 程序中需要用到很多自定义的js对象 1.直接创建 var ob ...

  8. Opencv显示创建Mat对象的七种方式

    方式一: [cpp] view plain copy #include<iostream> #include<opencv2/opencv.hpp> using namespa ...

  9. java 给对象创建实例_Java中创建(实例化)对象的五种方式

    Java中创建(实例化)对象的五种方式1.用new语句创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3.运用反 ...

最新文章

  1. 如何批量转移大量的邮件?
  2. PySide教程:一个简单的点击“.NET研究”按钮示例
  3. TF-IDF与余弦相似性的应用(二):找出相似文章
  4. 波卡链Substrate (6)Babe协议一“基本概念”
  5. 匿名电子病例信息不全?深度学习能更好的判断出种族(代码开源)
  6. 切换node版本 nvm 的基本使用 -- 以及安装公司特有的镜像源
  7. BundleFusion那些事儿
  8. 简单快速的用SpringBoot访问静态资源(图片、html)
  9. HDU 1012 u Calculate e(简单阶乘计算)
  10. OKB突破7.2USDT,再创12月新高
  11. 利用google closure管理javascript模块依赖
  12. Enjin ERC-1155和游戏多重宇宙
  13. echarts设置标题样式_EChart 标题 title 样式,x轴、y轴坐标显示,调整图表位置等...
  14. 【算法工程师】成为一名优秀的机器学习算法工程师所需知识及资料汇总-附思维导图
  15. 红外遥控切歌(好运来/天空之城)、红外模块的应用
  16. bittorrent协议
  17. 微信电脑版多用户登录
  18. 【Jmeter】Jmeter登录带验证码平台
  19. 第一节:(2)逻辑芯片工艺特性指标
  20. 苏州大学在职研究生计算机专业,苏州大学在职研究生入学须知

热门文章

  1. 微信小程序wepy框架开发资源汇总
  2. 智慧交通行业发展现状及竞争格局发展前景分析
  3. 程序员学英语要避免这几个坑
  4. 编写一个python程序、将日期作为输入并打印该日期_Python学习之路——day01
  5. 关于stimusoft report 报表一行记录有的高度高,有的高度低,错落的问题解决
  6. Python中测试代码的介绍
  7. 例程实作----庖丁解羊(上) (转)
  8. 标准舆情监测平台解决方案及流程,TOOM舆情监测工作计划有哪些?
  9. 儒竞科技创业板IPO过会:拟募资9.8亿 海尔是重要客户
  10. Navicat Premium教程:如何使用 Navicat 远程管理数据库?