Spring中bean的详解(基于xml文件)

Spring中bean的详解

这次分享的内容是Spring中bean的相关细节,主要从三个方面入手:

  1. 创建bean的三种方式
  2. bean对象的作用范围
  3. bean对象的生命周期

创建Bean的三种方式

  1. 使用默认构造的方式
    在spring的配置文件中使用bean标签,配以id和class属性之后,并且没有其他属性和标签时采用的就是这种方式
    此时如果类中没有默认构造则对象没法创建
    <bean id="accountService" class="org.zjb.service.impl.AccountServiceImpl"></bean>
  1. 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
    为什么要有这种方式呢?
    试想一下,有一种这样的情况,有个工厂类是我们导入的jar包,这个jar包的内容我们肯定是不能修改的,我们想要的并不是工厂类,而是通过该工厂类创建出来的方法,于是乎就有了这种方式.
    我们可以模拟一下:
/**
 * 模拟一个工厂类,该类可能是存在于一个jar包中的
 */
public class InstanceFactory {
    public IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}
	<!--先创建工厂类-->
    <bean id="instanceFactory" class="org.zjb.factory.InstanceFactory"></bean>
    <!--在指定工厂bean的id和创建对象的方法名-->
    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

  1. 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
    这种方式也比较好理解,和上面的基本一致
/**
 * 模拟一个静态工厂类,该类可能是存在于一个jar包中的
 */
public class StaticFactory {
    public static IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}
    <bean id="accountService" class="org.zjb.factory.StaticFactory" factory-method="getAccountService"></bean>

bean对象的作用范围

首先考虑一个问题,我们默认创建的对象是单例模式吗?
这个很好验证:

	<!--默认方式创建-->
    <bean id="accountService" class="org.zjb.service.impl.AccountServiceImpl"></bean>
/**
 * 模拟业务层
 */
public class Client {

    /**
     * 获取spring的ioc核心容器并根据id获取对象
     * @param args
     */
    public static void main(String[] args) {
        // 1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2.根据id获取bean对象
        IAccountService as1 = (IAccountService) ac.getBean("accountService");
        System.out.println(as1);
        IAccountService as2 = (IAccountService) ac.getBean("accountService");
        System.out.println(as2);
        System.out.println("as1 == as2 ? " + (as1 == as2));
    }

执行测试代码,得到结果如下:
结果
构造方法只执行了一遍,而且as1和as2对象是同一个对象,这些都说明默认方式创建的对象都是单例的.
能否多例模式创建对象?
可以的,也很简单,只需要将bean标签改写成如下方式即可:

    <bean scope="prototype" id="accountService" class="org.zjb.service.impl.AccountServiceImpl"></bean>

可以看出这个bean标签和上面相比多了一个scope属性,这个属性指定bean对象的作用范围,有如下取值

  • singleton : 单例的,也是默认值
  • prototype : 多例的
  • request : 作用于web应用的请求范围
  • session : 作用于web应用的会话范围
  • global-session : 作用于集群环境的会话(全局会话范围),当不是集群环境时,就是session

常用的就单例和多例.

bean对象的生命周期

单例对象

  • 出生 : 当容器创建时出生(立即)
  • 活着 : 只要容器还在,对象一直存活
  • 死亡 : 容器销毁,对象死亡
  • 总结 : 单例对象的生命周期和容器相同

现在我们来验证一下:
xml文件创建bean对象

    <bean scope="singleton" id="accountService" class="org.zjb.service.impl.AccountServiceImpl"
        init-method="init" destroy-method="destroy"
    ></bean>

init-method属性是指定bean对象创建时执行的方法,destroy-method属性是指定bean对象销毁时执行的方法.

我们在测试类中使用测试:

public class Client {

    /**
     * 获取spring的ioc核心容器并根据id获取对象
     * @param args
     */
    public static void main(String[] args) {
        // 1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2.根据id获取bean对象
        IAccountService as1 = (IAccountService) ac.getBean("accountService");
}

程序运行结果如下:
程序运行结果
并没有我们想要的结果,这是因为我们这里模拟的时候是使用main方法,当main方法执行完毕的时候,我们还没来的及销毁容器,就已经释放了程序的内存空间,所以这里的结果是这样的.

为了验证效果,我们需要主动释放容器对象,将测试代码改写:

public class Client {

    /**
     * 获取spring的ioc核心容器并根据id获取对象
     * @param args
     */
    public static void main(String[] args) {
        // 1.获取核心容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2.根据id获取bean对象
        IAccountService as1 = (IAccountService) ac.getBean("accountService");

        ac.close();
    }

}

观察上面代码,我们发现在创建容器对象的时候我们使用的是引用类型是实现类的,即ClassPathXmlApplicationContext,这是因为close方法在它的父接口ApplicationContext中并不存在.
程序运行结果

多例对象

我们将bean对象改成多例的,继续测试:

    <bean scope="prototype" id="accountService" class="org.zjb.service.impl.AccountServiceImpl"
        init-method="init" destroy-method="destroy"
    ></bean>

测试代码依旧使用上面的
得到结果为:
执行结果
可见随着容器对象的销毁,多例bean并没有被销毁
多例对象的生命周期如下 :

  • 出生 : 使用对象时才创建(延迟)
  • 活着 : 对象只要在使用过程中就一直活着
  • 死亡 : 当对象长时间不使用,且没有别的对象引用时,由java的垃圾回收机制回收
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值