Spring IoC : Instantiating beans

1、Instantiation with a constructor

【 通过一个构造方法来实例化 Bean 】

  • Java Bean
package io.malajava.ioc.beancreation;

import java.util.Date;

public class Human {

    private Integer id ; // 对象标识(zhi)符字段 ( Object Identifier Field )
    private String name ; // 用来保存姓名的字段
    private char gender ; // 用来保存性别的字段
    private Date birthdate ; // 用来保存 出生年月 对应的 Date 对象
    private boolean married ; // 用来表示是否已婚的字段 ( true 表示已婚 ;false 表示未婚 )

    public Human() {
        super();
    }

    public Human(Integer id, String name, char gender) {
        super();
        this.id = id;
        this.name = name;
        this.gender = gender;
    }

    /* 此处省略 所有 字段 对应的 getter 和 setter 方法 ,若要运行程序,请自行添加 */

    /* 建议重写 该类的 toString 方法,并在其中输出 各个字段的值 */

}
  • Configuration Metadata
<!-- 默认通过无参构造来创建 Date 实例  -->
    <bean id="date" class="java.util.Date" />

    <!-- 默认通过无参构造来创建 Human 实例 -->
    <bean id="firstHuman" class="io.malajava.ioc.beancreation.Human">
        <!-- 通过 property 为 Human 实例的各个属性注入数值 ( 通过 setter 实现注入 ) -->
        <property name="id" value="1001" />
        <property name="name" value="杨过" />
        <property name="gender" value="男" />
        <property name="married" value="false" />
        <property name="birthdate" ref="date" />
    </bean>

    <!-- 在 bean 标签内部 使用  constructor-arg 指定构造方法的参数,从而可以调用带有指定参数列表的构造方法 -->
    <bean id="secondHuman" class="io.malajava.ioc.beancreation.Human">
        <!-- constructor 表示 构造方法 ; arg 是 arguments 的缩写,表示参数 -->
        <constructor-arg name="id" value="2002" />
        <constructor-arg name="name" value="小龙女"/>
        <constructor-arg name="gender" value="女" />
    </bean>
注: 设以上内容存在于类路径下的 io/malajava/ioc/beancreation/creation-via-constructor.xml 文件中**
  • Testing
public class CreationViaConstructorTest {

    public static void main(String[] args) {

        // 指定 Configuration Metadata
        String configLocation = "classpath:io/malajava/ioc/beancreation/creation-via-constructor.xml" ;

        // 创建 Spring IoC 容器
        ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;

        // 从容器中获取 指定 id 对应的 bean , 并明确其类型
        Human first = iocContainer.getBean( "firstHuman" , Human.class );
        System.out.println( first ); // first.toString()

        Human second = iocContainer.getBean( "secondHuman" , Human.class );
        System.out.println( second ); // second.toString()

    }

}
2、Instantiation with a static factory method

【 通过一个静态工厂方法来实例化 Bean 】

  • Java Bean
package io.malajava.ioc.beancreation;

/**  单例模式 ( 饿汉式 ) */
public class Sun {

    // 在 Sun 类内部创建该类的实例 ( 自己内部创建自己的实例 )
    private static final Sun SUN = new Sun();

    // 将构造方法私有化,避免在 Sun 类外部创建 Sun 实例
    private Sun(){
        super();
    }

    // 提供一个 类方法 用来返回 Sun 类的惟一实例
    public static Sun getInstance() {
        return SUN  ;
    }
  • Configuration Metadata
 <!-- 通过 Sun 类的 getInstance() 方法来返回 Sun 实例 -->
    <bean id="sun" class="io.malajava.ioc.beancreation.Sun" factory-method="getInstance" />

    <!-- 通过调用  Calendar 类的 getInstance() 方法返回 Calendar 实例 -->
    <bean id="calendar" class="java.util.Calendar" factory-method="getInstance" />

这里,除了采用静态工厂方式返回Sun实例外,特别增加了一个采用静态工厂方法返回Calendar实例的配置,两者在返回实例的方式上是相同的(都使用静态方法)。不同的是我们的Sun类采用了单例模式,而Calendar类并没有采用单例模式。

另外请不要将单例模式跟 scope 中的 singleton 相混淆。

注: 设以上内容存在于类路径下的 io/malajava/ioc/beancreation/creation-via-static-factory.xml 文件中

  • Testing
public class CreationViaStaticFactoryTest {

    public static void main(String[] args) {

        // 指定 Configuration Metadata
        String configLocation = "classpath:io/malajava/ioc/beancreation/creation-via-static-factory.xml" ;

        // 创建 Spring IoC 容器
        ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;

        // 从容器中获取 指定 id 对应的 bean ,并明确其类型
        Calendar c = iocContainer.getBean( "calendar" , Calendar.class );
        System.out.println( c );

        Sun s = iocContainer.getBean( "sun" , Sun.class );
        System.out.println( s );

    }

}
3、Instantiation using an instance factory method

【 使用一个实例工厂方法来实例化 Bean 】

  • Java Bean
package io.malajava.ioc.beancreation;

public class Car {

    private String brand ;

    public Car() {
        super();
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

}
  • Factory

注意这里的 CarFactory 也是一个 Java Bean ,为了强调实例工厂,所以单独列出来。

package io.malajava.ioc.beancreation;

import java.util.Random;

public class CarFactory {

    private final String[] brands = { "秦" , "汉" , "唐" , "宋" ,  "元" , "明"  } ;
    private final Random rand = new Random();

    public Car produce() {
        Car c = new Car();
        int index = rand.nextInt( brands.length ) ;
        String b = brands[ index ] ;
        c.setBrand(  b );
        return c ;
    }

}
  • Configuration Metadata
<!-- 声明一个 CarFactory 类型的 bean -->
    <bean id="carFactory" class="io.malajava.ioc.beancreation.CarFactory" />

    <!-- 指定 通过  carFactory 的  produce 方法 来创建 Car 类型的 bean -->
    <bean id="car" factory-bean="carFactory" factory-method="produce" />

注: 设以上内容存在于类路径下的 io/malajava/ioc/beancreation/creation-via-instance-factory.xml 文件中**

  • Testing
public class CreationViaInstanceFactoryTest {

    public static void main(String[] args) {

        // 指定 Configuration Metadata
        String configLocation = "classpath:io/malajava/ioc/beancreation/creation-via-instance-factory.xml" ;

        // 创建 Spring IoC 容器
        ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;

        // 从容器中获取 指定 id 对应的 bean , 并明确其类型
        Car c = iocContainer.getBean( "car" , Car.class );
        System.out.println( c ); // c.toString()

        System.out.println( c.getBrand() );

    }

}
4、Customizing instantiation logic with a FactoryBean

【 通过FactoryBean实现自定义实例化逻辑 】

4.1、理解使用FactoryBean方式创建实例的过程
  • Java Bean
package io.malajava.ioc.beancreation;

public class Bus {

    private String brand ; // 表示"铭牌"的字段

    public Bus() {
        super();
        System.out.println( "[ Bus ] - [ public Bus() ]" );
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        System.out.println( "[ Bus ] - [ public void setBrand(String) ]" );
        this.brand = brand;
    }

}

  • FactoryBean
package io.malajava.ioc.beancreation;

import org.springframework.beans.factory.FactoryBean;

/** 实现 FactoryBean 接口并指定 类型参数 为 Bus */
public class BusFactoryBean implements FactoryBean<Bus> {

    private String name ;

    public BusFactoryBean() {
        super();
        System.out.println( "[ BusFactoryBean ] - [ public BusFactoryBean() ]");
    }

    @Override
    public Bus getObject() throws Exception {
        System.out.println( "[ BusFactoryBean ] - [ public Bus getObject() throws Exception ]" );
        Bus bus = new Bus();
        bus.setBrand( name );
        return bus ;
    }

    @Override
    public Class<?> getObjectType() {
        return Bus.class ; // 与 getObject() 方法的返回类型相同
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println( "[ BusFactoryBean ] - [ public void setName(String) ]" );
        this.name = name;
    }

}
  • Configuration Metadata
 <bean id="bus" class="io.malajava.ioc.beancreation.BusFactoryBean" >
        <property name="name" value="比亚迪" />
    </bean>

注: 设以上内容存在于类路径下的 io/malajava/ioc/beancreation/creation-via-factory-bean.xml 文件中

  • Testing
public class CreationViaFactoryBeanTest1 {

    public static void main(String[] args) {

        // 指定 Configuration Metadata
        String configLocation = "classpath:io/malajava/ioc/beancreation/creation-via-factory-bean.xml" ;

        // 创建 Spring IoC 容器
        ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;

        // 从容器中获取 指定 id 对应的 bean
        Object o = iocContainer.getBean( "bus" ); // 未指定类型
        System.out.println( o );
        System.out.println( o.getClass() );

        Bus bus = iocContainer.getBean( "bus" , Bus.class ); // 指定类型
        System.out.println( bus.getBrand() );

    }

}

通过运行 CreationViaFactoryBeanTest1 类的 main 方法可以看到以下输出:

[ BusFactoryBean ] - [ public BusFactoryBean() ]
[ BusFactoryBean ] - [ public void setName(String) ]
[ BusFactoryBean ] - [ public Bus getObject() throws Exception ]
[ Bus ] - [ public Bus() ]
[ Bus ] - [ public void setBrand(String) ]
io.malajava.ioc.beancreation.Bus@503d687a
class io.malajava.ioc.beancreation.Bus
比亚迪

由以上输出可知,Spring IoC 容器先根据配置文件中的内容将 BusFactoryBean 实例化,并为该实例注入相关属性的值(如setName)。随后调用该实例的 getObject() 方法来获取 Bus 实例。

而在 BusFactoryBean 中显式调用了 Bus 类的构造 和 setBrand 方法,因此可以看到以下输出:

[ Bus ] - [ public Bus() ]
[ Bus ] - [ public void setBrand(String) ]

至此,我们基本了解了使用 FactoryBean 方式来实例化 Bean 的步骤。

#4.2、利用FactoryBean方式来创建任意时刻对应的Date对象
  • Java Bean
因为这里使用的是 java.util.Date 类,因此无需再定义新的类。
  • FactoryBean
package io.malajava.ioc.beancreation;

import org.springframework.beans.factory.FactoryBean;

import java.util.Calendar;
import java.util.Date;

public class DateFactoryBean implements FactoryBean<Date> {

    private final Calendar calendar = Calendar.getInstance();

    private int year ; // 表示年份的字段,比如 2018
    private int month ; // 表示月份的字段,取值范围是 [ 1  , 12 ]
    private int date ;  // 表示日期的字段,取值范围是 [ 1  , 31 ]
    private int hours ; // 表示小时的字段,取值范围是 [ 0 , 23 ]
    private int minutes ; // 表示分钟的字段,取值范围是 [ 0 , 59 ]
    private int seconds ; // 表示秒数的字段,取值范围是 [ 0 , 60 ]

    @Override
    public Date getObject() throws Exception {
        calendar.clear(); // 清除所有 日历字段 ( Calendar Field ) 的值
        calendar.set( year , month - 1 , date , hours , minutes , seconds );
        Date date = calendar.getTime() ;
        return date ;
    }

    @Override
    public Class<?> getObjectType() {
        return Date.class;
    }

    /*
    此处省略所有字段的 getter 和 setter ,若要运行测试代码,请自行补全。

    另外,应该在 setter 中对取值范围予以检查,
    比如 分钟的取值范围是 [0,59] ,则其 setter 应该采用以下方式来实现:

    public void setMinutes(int minutes) {
        if( minutes >= 0 && minutes <= 50 ) { // 使用判断保证数据有效性
            this.minutes = minutes;
        }
    }

    */

}
  • Configuration Metadata
 <bean id="date" class="io.malajava.ioc.beancreation.DateFactoryBean">
        <property name="year" value="1996" />
        <property name="month" value="7" />
        <property name="date" value="4" />
        <property name="hours" value="8" />
        <property name="minutes" value="20" />
        <property name="seconds" value="30" />
    </bean>

注: 设以上内容存在于类路径下的 io/malajava/ioc/beancreation/creation-via-factory-bean.xml 文件中

  • Testing
public class CreationViaFactoryBeanTest {

    public static void main(String[] args) {

        // 指定 Configuration Metadata
        String configLocation = "classpath:io/malajava/ioc/beancreation/creation-via-factory-bean.xml" ;

        // 创建 Spring IoC 容器
        ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;

        // 从容器中获取 bean
        Date date = iocContainer.getBean( "date" , Date.class );
        System.out.println( date );

        DateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH??ss" );
        System.out.println( df.format( date ) );

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值