`

Spring基本用法4——创建Bean的三种方式

阅读更多

        前言:在大多数情况下,Spring容器直接通过new关键字调用构造器来创建Bean实例,而class属性指定了Bean实例的实现类。因此,<bean../>元素必须指定Bean实例的class属性,但这并不是实例化Bean的唯一方法,本文介绍三种实例化Bean的方法。

本篇文章重点关注以下问题:

  • 调用构造器创建Bean;
  • 调用静态工厂方法创建Bean;
  • 调用实例工厂方法创建Bean。

1. 使用构造器创建Bean

        使用构造器创建Bean有两种可能情况,一是不采用构造注入,Spring底层调用Bean类的无参数构造器来创建实例,二是采用构造注入时,Spring容器使用带对应参数的构造器来创建Bean。

1.1 不采用构造注入

        不采用构造注入时,Spring底层会调用Bean类的无参数构造器来创建实例,因此要求该Bean类提供无参数的构造器。在这种情况下class元素是必须的(除非采用继承),class属性的值就是Bean实例的实现类。

       当Spring使用默认构造器来创建Bean实例时,Spring对Bean实例的所有属性执行默认初始化,即所有基本类型的值初始化为0或false;所有引用类型的值初始化为null。同时,Spring会根据配置文件决定的依赖关系,先实例化被依赖的Bean实例,然后为Bean注入依赖关系,最后将一个完整的Bean实例返回给程序。

1.2 采用构造注入

         如果采用构造注入,则要求配置文件为<bean../>元素添加<constructor-arg../>子元素,每个<constructor-arg../>子元素配置一个构造器参数。Spring容器将使用带对应参数的构造器来创建Bean实例,Spring调用构造器传入的参数即可用于初始化Bean的实例,最后也将一个完整的Bean实例返回给程序。

       注:对于 使用构造器创建Bean的实例可见http://super-wangj.iteye.com/admin/blogs/2383803一文,在此不过多阐述。

2. 使用静态工厂方法创建Bean

       使用静态工厂方法创建Bean实例时,需指定两个属性:

  • class:该属性的值为静态工厂类的类名。(Spring通过该属性知道由哪个工厂类来创建Bean)
  • factory-method:该属性指定静态工厂方法来生产Bean实例。(工厂方法必须是静态的)
       注:如果静态工厂方法需要参数,则使用<constructor-arg../>元素传入。

2.1 定义Bean:一个接口及其两个实现

       首先是定义Person接口:

public interface Person {
    public void testBeing();
}

       然后是其两个实现类Chinese.java和American.java

      Chinese.java:

public class Chinese implements Person {
    private String name;
    // name的setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    // 实现接口必须实现的testBeing方法
    public void testBeing() {
        System.out.println("我是中国人,名字是:" + name);
    }
}

        American.java

public class American implements Person {
    private String name;
    // name的setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public void testBeing() {
        System.out.println("我是美国人,名字是:" + name);
    }
}

 

2.2 编写静态工厂类

         下面的PersonFactory静态工厂包含了一个getBeing(byte mode)静态工厂方法,该方法用于返回一个Person实例,具体是Chinese对象还是American对象需根据传入的参数决定。

public class PersonFactory {
    
    public static final byte COUNTRY_CHINA = 0;     // 代表中国人
    public static final byte COUNTRY_AMERI = 1;     // 代表美国人
    
    /**
     * 返回Being实例的静态工厂方法
     * arg参数决定返回哪个Person类的实例
     * @param mode
     * @return
     */
    public static Person getBeing(byte mode) {
        // 根据传入的参数,确定返回哪个实例
        if (mode == COUNTRY_CHINA) {
            return new Chinese();
        }
        if (mode == COUNTRY_AMERI) {
            return new American();
        }
        
        throw new RuntimeException("配置有误");
    }
}

2.3 按静态工厂方法的方式配置Chinese Bean和American 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-4.3.xsd">
    
<!-- 下面配置驱动Spring调用PersonFactory的静态getBeing()方法来创建Bean
     该bean元素包含的constructor-arg元素用于为静态工厂方法指定参数, -->
<bean id="chinese" class="com.wj.chapter4.staticFactory.PersonFactory" factory-method="getBeing">
    <!-- 配置静态工厂方法的参数,0代表中国人 -->
    <constructor-arg value="0"/>
    <!-- 驱动Spring以"熊燕子"为参数来执行chinese的setName()方法 -->
    <property name="name" value="熊燕子"/>
</bean>

<bean id="american" class="com.wj.chapter4.staticFactory.PersonFactory" factory-method="getBeing">
    <!-- 配置静态工厂方法的参数,1代表美国人 -->
    <constructor-arg value="1"/>
    <!-- 驱动Spring以"wj"为参数来执行american的setName()方法 -->
    <property name="name" value="wj"/>
</bean>
    
</beans>

        由上述配置文件可看出,chinese和american两个Bean配置的class属性和factory-method属性完全相同——这是因为这两个实例都是由同一个静态工厂类、同一个静态工厂方法生产得到的。配置这两个Bean实例时指定的静态工厂方法的参数值不同(一个是0,一个是1),并以此为依据生产不同的对象。

        一旦为<bean../>元素指定了factory-method属性,Spring就不再调用构造器来创建Bean实例,而是调用静态工厂方法来创建Bean实例。如果同时指定了class和factory-method属性,Sring会调用静态工厂方法来创建Bean。

2.4 编写测试代码,查看测试结果

public class TestMain {
    
    // 1.指明xml配置文件位置,便于Spring读取,从而知道Bean的相关信息
    private static final String PATH_XML = "com/wj/chapter4/staticFactory/applicationContext-createBean.xml";
    
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        // 2.以类加载路径下的配置文件创建ClassPathResource实例
        ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH_XML);
        // 3.测试获取Chinese对象
        Person chinese = ctx.getBean("chinese" , Person.class);
        chinese.testBeing();
        // 4.测试获取American对象
        Person american = ctx.getBean("american" , Person.class);
        american.testBeing();
    }
}

        运行结果为:

2.5 小结 

         使用静态工厂方法创建实例时必须提供工厂类,工厂类包含产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对配置文件进行如下改变:

  • class属性的值不再是Bean实例的实现类,二是生成Bean实例的静态工厂方法;
  • 使用factory-method属性指定创建Bean实例的静态工厂方法;
  • 如果静态工厂方法需要参数,则使用<constructor-arg..>元素指定静态工厂方法的参数。

        注:通过静态工厂方法创建了Bean实例后,Spring依然可以管理该Bean实例的依赖关系,包括为其注入所需的依赖Bean、管理其生命周期等。

3. 使用实例工厂方法创建Bean

       实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,而调用实例工厂方法则需要工厂实例。所以,配置实例工厂方法与配置静态工厂方法基本类似,只有一点区别:配置静态工厂方法使用class指定静态工厂类,而配置实例工厂方法则使用factory-bean指定工厂实例。

       使用实例工厂方法时,配置Bean实例的<bean../>元素无需class属性,因为Spring容器不再直接实例化该Bean,Spring容器仅仅调用实例工厂的工厂方法,由工厂方法负责创建Bean实例。

       采用实例工厂方法创建Bean的<bean../>元素时,需要指定如下两个属性:

  • factory-bean:该属性的值为工厂Bean的id;
  • factory-method:该属性指定实例工厂的工厂方法。

       注:与静态方法类似,如果需要在调用实例工厂方法时传入参数,则使用<constructor-arg../>元素确定参数值。

3.1  定义Bean:一个接口及其两个实现

       首先是Person接口: 

public interface Person {
    // 定义一个打招呼的方法
    public void sayHello();
}

       然后是Person接口的两个实现类:Chinese.java和American.java 

       Chinese.java: 

public class Chinese implements Person {
    
    private String name;
    // name的setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    // 实现Person接口方法
    @Override
    public void sayHello() {
        System.out.println("你好,我是中国人,名字是:" + name);
    }
}

         American.java: 

public class American implements Person {
    
    private String name;
    // name的setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    // 实现Person接口方法
    @Override
    public void sayHello() {
        System.out.println("你好,我是美国人,名字是:" + name);
    }
}

 

3.2 编写实例工厂

        PersonFactory是负责产生Person对象的实例工厂,该工厂类里提供了一个getPerson()方法,该方法根据传入的mode参数决定产生哪种Person对象。

public class PersonFactory {
    
    public static final byte COUNTRY_CHINA = 0;     // 代表中国人
    public static final byte COUNTRY_AMERI = 1;     // 代表美国人
    
    /**
     * 实例工厂方法(非静态)
     * mode参数决定返回哪个Person的实例
     * @param mode
     * @return
     */
    public Person getPerson(byte mode) {
        // 根据传入的参数,确定返回哪个实例
        if (mode == COUNTRY_CHINA) {
            return new Chinese();
        }
        if (mode == COUNTRY_AMERI) {
            return new American();
        }
        
        throw new RuntimeException("配置有误");
    }
}

 

3.3 按实例工厂方法的方式配置Chinese Bean和American Bean

       配置实例工厂创建Bean与配置静态工厂创建Bean基本类似,只需将原来的静态工厂类改为现在的工厂实例即可。

!-- 配置工厂Bean,该Bean负责产生其他Bean实例 -->
<bean id="personFactory" class="com.wj.chapter4.instanceFactory.PersonFactory"/>

<!-- 下面配置驱动Spring调用personFactory Bean的getPerson()方法来创建Bean
该bean元素包含的constructor-arg元素用于为工厂方法指定参数. -->
<bean id="chinese" factory-bean="personFactory" factory-method="getPerson">
    <!-- 配置实例工厂方法的参数,0代表中国人. -->
    <constructor-arg value="0"/>
    <!-- 驱动Spring以"熊燕子"为参数来执行chinese的setName()方法 -->
    <property name="name" value="熊燕子"/>
</bean>

<bean id="american" factory-bean="personFactory" factory-method="getPerson">
    <!-- 配置实例工厂方法的参数,1代表美国人. -->
    <constructor-arg value="1"/>
    <!-- 驱动Spring以"wj"为参数来执行american的setName()方法 -->
    <property name="name" value="wj"/>
</bean>

3.4 编写测试代码,查看测试结果

public class SpringTest {
    
    // 1.指明xml配置文件位置,便于Spring读取,从而知道Bean的相关信息
    private static final String PATH_XML = "com/wj/chapter4/instanceFactory/applicationContext-createBean.xml";
    
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        // 2.以类加载路径下的配置文件创建ClassPathResource实例
        ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH_XML);
        // 3.测试获取Chinese对象
        Person p1 = ctx.getBean("chinese", Person.class);
        p1.sayHello();
        // 4.测试获取American对象
        Person p2 = ctx.getBean("american", Person.class);
        p2.sayHello();
    }
}

     测试结果如下:

3.5 小结 

        可以发现,调用实例工厂方法创建Bean,与调用静态工厂创建Bean的用法基本类似。区别如下:

  1. 配置实例工厂方法创建Bean,必须使用将实例工厂配置成Bean实例;而配置静态工厂方法创建Bean,则无需配置工厂Bean。
  2. 配置实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean;而配置静态工厂方法创建Bean,则使用class元素确定静态工厂类。
  3. 都需要使用factory-method属性指定产生Bean实例的工厂方法;
  4. 工厂方法如果需要参数,都使用<constructor-arg../>元素指定参数值;
  5. 普通的设置注入,都使用<property../>元素确定参数值。

 

代码下载地址:http://pan.baidu.com/s/1jIKH9Y2,密码:6jd9

  • 大小: 13.5 KB
  • 大小: 15.8 KB
分享到:
评论

相关推荐

    实例化Spring bean的两种工厂方法

    本篇将详细探讨两种工厂方法——实例工厂方法和静态工厂方法,用于创建Spring Bean。 首先,我们要理解Spring Bean的概念。Spring Bean是Spring IoC容器管理的对象,这些对象的生命周期、依赖关系以及初始化行为由...

    二、Spring源码分析——BeanFactory

    《Spring源码分析——BeanFactory》 在Java的IoC(Inversion of Control)和DI(Dependency Injection)领域,Spring框架扮演着至关重要的角色。BeanFactory是Spring的核心组件之一,它是容器的基石,负责管理应用...

    4Spring自动装配——annotation resource方式

    在Spring框架中,自动装配(Auto-Wiring)是一种简化依赖注入(Dependency Injection,DI)配置的方式,它允许Spring容器自动管理Bean之间的依赖关系。本文将深入探讨如何通过注解(Annotation)和`@Resource`来实现...

    spring學習筆記——Helloworld

    在本篇“Spring学习笔记——HelloWorld”中,我们将探讨Spring框架的基础知识,以及如何创建一个简单的Spring应用程序。Spring是一个广泛使用的Java企业级应用开发框架,它提供了丰富的功能,包括依赖注入、AOP...

    三、Spring源码分析——ApplicationContext

    《Spring源码分析——ApplicationContext》 在Java世界中,Spring框架是不可或缺的一部分,它以其强大的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)特性,极大地...

    Spring学习笔记(9)----让Spring自动扫描和管理Bean

    在Spring框架中,自动扫描和管理Bean是一种便捷的方式,它允许开发者无需显式配置每个Bean,而是通过指定包路径来让Spring自动发现和管理Bean。本文将深入探讨这个主题,帮助你更好地理解和应用这一功能。 首先,让...

    Spring依赖注入——java项目中使用spring注解方式进行注入.rar

    1. 创建Bean:首先,你需要在Spring配置文件中声明你的bean,或者使用`@Component`、`@Service`、`@Repository`、`@Controller`等注解来标记类,让Spring自动扫描并管理。 2. 注解注入:在需要注入依赖的类中,使用...

    征服 Redis + Jedis + Spring (三)—— 列表操作

    在实际应用中,如果你需要在 Spring 中使用 Jedis 和 Redis 的列表功能,可以创建一个 Redis 配置类,配置 JedisConnectionFactory 并注入到 RedisTemplate 中。例如: ```java @Configuration public class Redis...

    Spring MVC Ibatis Bean 根据mysql数据表——代码生成工具

    标题中的“Spring MVC Ibatis Bean 根据mysql数据表——代码生成工具”就是这样的一个工具,它能够根据MySQL数据库中的表结构,快速生成符合Spring MVC和Ibatis框架的代码。 Rapid-generator-0.2v可能是这个工具的...

    普通类调用Spring bean对象

    我们可以创建一个配置类,然后在其中声明bean,使用`@ComponentScan`扫描包含普通类的包,这样Spring就能自动管理普通类。同时,也可以在配置类中使用`@Bean`注解创建bean实例,然后在普通类中通过`@Autowired`注入...

    spring学习:依赖注入的几种方式讨论

    Spring Boot引入了一种更智能的依赖注入方式——自动配置。自动配置是通过`@EnableAutoConfiguration`注解启动的,它根据项目中的类路径和特定条件自动配置Bean。例如,如果类路径下存在`MongoClient`的jar,Spring ...

    【框架源码篇 04】Spring源码手写篇-Bean定义配置化

    在本篇【框架源码篇 04】中,我们将深入探讨Spring框架的核心概念——Bean定义配置化。Spring是Java领域最广泛使用的依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称...

    Spring从入门到入土——快速上手Spring

    命名为beans.xml测试结果以及总结IOC创建对象方式通过无参构造方法来创建User.javabeans.xml测试结果通过有参构造方法来创建UserT.javabeans.xml 有三种方式测试总结Spring的配置别名Bean的配置import 相关文章推荐...

    Spring入门操作代码,bean

    这个压缩包文件“Spring入门操作代码,bean”显然包含了关于如何使用Spring框架进行基本操作的示例代码,主要涉及的是Spring框架的核心概念——Bean管理。 首先,Spring的核心理念是依赖注入(Dependency Injection...

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    Spring 使用 `java.lang.reflect.Proxy` 类来创建动态代理,并通过实现 `java.lang.reflect.InvocationHandler` 接口来处理代理对象的方法调用。在 Spring AOP 中,`org.springframework.aop.framework....

    撸一撸Spring Framework-IoC-BeanDefinition(csdn)————程序.pdf

    在Spring Framework中,IoC(Inversion of Control,控制反转)是核心概念之一,它使得应用程序的组件不再直接创建依赖对象,而是由Spring容器来管理和维护。BeanDefinition就是实现这一概念的关键元素,它包含了...

    Spring整合JMS——实现收发消息

    总结来说,Spring整合JMS和ActiveMQ的过程包括:配置ConnectionFactory,定义Destination,创建MessageListener容器,以及使用JmsTemplate发送消息。通过这种方式,你可以构建一个健壮的、异步的消息传递系统,提高...

    小读spring ioc源码(一)——整体介绍

    Spring提供了多种策略来创建Bean实例,如使用无参构造函数、工厂方法或者Prototype模式。这里会涉及BeanFactory和ApplicationContext接口,以及InstantiationStrategy接口。 3. **依赖注入** 依赖注入是Spring的...

    spring源码阅读——1.spring-core-3.2.9

    2. **Bean容器**:Spring的IoC(Inversion of Control)容器是管理bean的工厂,负责创建、装配和管理bean。在`io.xml`配置文件中,我们可以看到bean的定义和它们之间的关系。每个bean都有唯一的ID,可以被其他bean...

    征服Spring AOP—— Schema

    本文将深入探讨“Spring AOP——Schema”,这是Spring AOP的一种配置方式,通过XML schema定义切面和通知。 首先,我们需要理解AOP的基本概念。面向切面编程是一种编程范式,旨在提高软件的模块化程度,将关注点...

Global site tag (gtag.js) - Google Analytics