1.创建bean的三种方式

1.1 使用默认构造函数创建

使用这种方式创建对象时,配置文件的beans标签内只有idclass两个属性,这种方式会自动调用类的默认构造函数,也就是无参构造函数来创建Bean对象,如果类中没有默认构造函数,那么程序就会报错。需要被创建对象的类的代码如下,它是我们之前一直用的Service层的接口实现类:

package com.eastnotes.service.impl;

import com.eastnotes.service.AccountService;

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements AccountService {

    public AccountServiceImpl(){
        System.out.println("对象被创建了");
    }

    public void saveAccount(){
        System.out.println("Dao的saveAccount方法被调用了");
    }
}

配置文件的内容如下:

<bean id="accountService" class="com.eastnotes.service.impl.AccountServiceImpl"></bean>

1.2 使用普通类中的函数创建

假如我们需要一个类的对象,但是这个对象不是我们可以直接创建的,而是有一个工厂类提供的,这个工厂类中由一个方法返回了我们需要的对象,那么我们该怎样获取这个对象呢?

首先写一个普通工厂类,该工厂类有一个返回我们所需对象的方法:

package com.eastnotes.factory;

import com.eastnotes.service.AccountService;
import com.eastnotes.service.impl.AccountServiceImpl;

/**
 * 模拟一个工厂类,该类可能存在于Jar包中,我们无法更改,也就无法通过,编写默认构造函数的方式创建对象。
 */
public class InstanceFactory {
    public AccountService getAccountService(){
        return new AccountServiceImpl();
    }
}

然后在配置文件中写入:

<bean id="instanceFactory" class="com.eastnotes.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

factory-bean属性指明了能够提供对象的工厂类,factory-method对象指明了能够返回对象的方法。

1.3 使用普通类中的静态方法创建对象

首先还是模拟一个普通的工厂类,该类中有一个静态方法:

package com.eastnotes.factory;

import com.eastnotes.service.AccountService;
import com.eastnotes.service.impl.AccountServiceImpl;

/**
 * 模拟一个工厂类,该类可能存在于Jar包中,我们无法更改,也就无法通过,编写默认构造函数的方式创建对象。
 */
public class StaticFactory {
    public static AccountService getAccountService(){
        return new AccountServiceImpl();
    }
}

配置文件应该这样来写:

<bean id="accountService" class="com.eastnotes.factory.StaticFactory" factory-method="getAccountService"></bean>

总结来说,如果遇到某个jar包中的某个方法,你希望通过Spring容器来获取的话,就可以使用以上两种方式来实现。

2.Bean的作用范围

Spring所创建的Bean对象,默认是单例的。如果需要调整的话,那我们需要使用bean标签的scope属性,该属性的作用就是制定bean的作用范围。它的取值有如下几个:

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

3.Bean对象的生命周期

3.1 单例对象的生命周期

单例对象的声明周期与容器相同,具体表现为三个方面:

  • 出生:当容器创建时bean对象出生
  • 活着:只要容器还在,对象就一直活着
  • 死亡:容器销毁、对象死亡

我们可以使用bean标签的两个属性(初始化方法:init-method,销毁方法:destory-method),指定对象的声明周期方法。首先我们在被创建对象的类中先定义两个方法:

public void init(){
    System.out.println("初始化了");
}

public void destory(){
    System.out.println("销毁了");
}

然后更改这个bean标签:

<bean id="accountService" class="com.eastnotes.service.impl.AccountServiceImpl" init-method="init" destroy-method="destory"></bean>

然后运行表现层代码,可以得到输出:

对象被创建了
初始化了

可以发现,虽然我们指定了初始化方法和销毁方法,但是在执行的时候,只执行了初始化方法,这是由于我们是在main方法中执行的创建容器并获取对象,当main方法执行完毕之后,内存全部释放,容器还没有来得及调用销毁方法就结束了,此时我们可以调用容器对象的close方手动执行销毁方法:

public static void main(String[] args) {
    //1.通过读取类路径下的配置文件,获取核心容器对象
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

    //2.获取AccountService对象,手动类型转换(因为本来获取的是Object)
    AccountService as = (AccountService) ac.getBean("accountService");

    ac.close();
}

这里需要注意,close方法是ClassPathXmlApplicationContext中的方法,ApplicationContext类中是没有的,因此在获取对象的时候,将其用自己的类型接收对象就可以了。

3.2 多例对象的生命周期

我们也将其生命周期总结为三个阶段:

  • 出生:使用对象的时候,也就是调用容器对象的getBean方法的时候,对象才会出生。
  • 活着:对象在使用着,他就一直活着。
  • 死亡:由于Spring不知道你什么时候用完这个对象,只有当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器来进行回收。