为了更加清楚地看到这两个接口之间的区别,我们在AccountDaoImpl和AccountServiceImpl类的无参构造方法中添加如下内容:
//AccountDaoImpl public AccountDaoImpl() { System.out.println("dao创建了"); } //AccountServiceImpl public AccountServiceImpl() { System.out.println("service创建了"); }对ui.Client类中的main方法添加如下代码:
Resource resource = new ClassPathResource("beans.xml"); BeanFactory factory = new DefaultListableBeanFactory(); BeanDefinitionReader bdr = new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory); bdr.loadBeanDefinitions(resource); System.out.println(factory.getBean("accountDao"));采用断点调试,我们可以发现:
对于ApplicationContext来说,执行ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");之后,立刻就会输出“service创建了”和“dao创建了”。
而对于BeanFactory来说,只有当执行到System.out.println(factory.getBean("accountDao"));之后,才会输出“dao创建了”。
这也就说明ApplicationContext是立即加载,BeanFactory是延迟加载。通常而言,ApplicationContext接口更加常用。此外,我们也可以自己指定单例模式还是多例模式。
三、Bean对象的管理细节 1.三种创建bean对象的方式
第一种方式:使用默认构造方法创建
在Spring配置文件中使用bean标签,如果只有id和class属性,就会使用默认构造方法(无参构造方法)创建对象。如果没有默认构造方法,则对象无法创建。例如,之前我们所使用的便是这第一种方式。
<bean></bean>
第二种方式:使用其他类(比如工厂类)中的方法创建对象,并存入Spring容器,该类可能是jar包中的类,无法通过修改源码来提供默认构造方法。
为了演示,我们在src/main/java目录新建factory包,在factory包下新建类InstanceFactory:
public class InstanceFactory { //非静态方法 public IAccountService getAccountService() { return new AccountServiceImpl(); } }instanceFactory对应的就是factory包下的InstanceFactory类的对象,accountService对应的是InstanceFactory类下的getAccountService方法返回的对象。factory-bean属性用于指定创建本次对象的factory,factory-method属性用于指定创建本次对象的factory中的方法。
<bean></bean> <bean factory-bean="instanceFactory" factory-method= "getAccountService"></bean>
第三种方式:使用其他类(比如工厂类)中的静态方法创建对象,并存入Spring容器,该类可能是jar包中的类,无法通过修改源码来提供默认构造方法。
为了演示,我们在src/main/java目录新建factory包,在factory包下新建类StaticFactory:
public class StaticFactory { //静态方法 public static IAccountService getAccountService() { return new AccountServiceImpl(); } }由于是静态方法,所以无需指定factory-bean属性。class属性指定创建bean对象的工厂类,factory-method方法指定创建bean对象的工厂类中的静态方法。
<bean factory-method="getAccountService"></bean> 2.bean对象的作用范围bean标签的scope属性(用于指定bean对象的作用范围),有如下取值:常用的就是单例和多例
singleton:单例(默认值)
prototype:多例
request:作用域Web的请求范围
session:作用于Web的会话范围
global-session:作用于集群的会话范围(全局会话范围),当不是集群环境时,它就是session
这里我们演示单例和多例:
<bean scope="singleton"></bean> <bean scope="prototype"></bean>此时即便Client类中的main方法使用ApplicationContext接口:
public static void main(String[] args) { //1.获取IoC核心容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); //2.根据id获取bean对象 //第一种方法:只传入id获取到对象之后强转为需要的类型 IAccountService accountService = (IAccountService) applicationContext.getBean("accountService"); System.out.println(accountService); //第二种方法:传入id和所需要类型的字节码,这样getBean返回的对象就已经是所需要的对象 IAccountDao accountDao = applicationContext.getBean("accountDao", IAccountDao.class); IAccountDao accountDao1 = (IAccountDao) applicationContext.getBean("accountDao"); System.out.println(accountDao == accountDao1); }使用断点调试,我们可以发现:
在执行到ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");时,就会输出“service创建了”,不会输出“dao创建了”。