- BeanFactory是Spring的早期接口,称为Spring的Bean工厂,ApplicationContext是后期更高级接口,称之为Spring容器;
- ApplicationContext在BeanFactory基础上对功能进行了扩展,例如:监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
- Bean创建的主要逻辑和功能都被封装在BeanFactory中,ApplicationContext不仅继承了BeanFactory,而且ApplicationContext内部还维护着BeanFactory的引用,所以,ApplicationContext与BeanFactory既有继承关系,又有融合关系。
- Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建,而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好。
实现类 | 功能描述 |
---|---|
ClassPathXmlApplicationContext | 加载类路径下的xml配置的ApplicationContext |
FileSystemXmlApplicationContext | 加载磁盘路径下的xml配置的ApplicationContext |
AnnotationConfigApplicationContext | 加载注解配置类的ApplicationContext |
Bean的常用配置
Xml配置方式 | 功能描述 |
---|---|
Bean的id和全限定名配置 | |
通过name设置Bean的别名,通过别名也能直接获取到Bean实例 | |
Bean的作用范围,BeanFactory作为容器时取值singleton和prototype | |
Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效 | |
Bean实例化后自动执行的初始化方法,method指定方法名 | |
Bean实例销毁前的方法,method指定方法名 | |
设置自动注入模式,常用的有按照类型byType,按照名字byName | |
指定哪个工厂Bean的哪个方法完成Bean的创建 |
beanName
例如:
配置UserDaolmpl由Spring容器负责管理
此时存储到Spring容器(singleObjects单例池Map
)中的Bean的beanName是testDaoService,值是TestDaoService对象,可以根据beanName获取Bean实例
applicationContext.getBean ( "testDaoService");
如果不配置id,则Spring会把当前Bean实例的全限定名作为beanName
applicationContext.getBean ( "com.hyl.service.TestDaoService");
如果起别名,在没有配置id的时候,默认第一个别名为beanName;
如果配置的有id,同时也起了别名,这时候别名对应的还是id名,beanName还是id。
默认情况下,单纯的Spring环境Bean的作用范围有两个: Singleton和Prototype
- singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
- prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。
Bean的延迟加载
当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的。
init-method="方法名1" destroy-method="方法名2"
public class UserDaoImpl implements UserDao,InitializingBean {
public UserDaoImpl() {
System.out.println ( "UserDaoImpl创建了...");
}
public void init() {
System.out.println("初始化方法...");
}
public void destroy () {
System.out.println("销毁方法...");
}
//执行时机早于init-method配置的方法
public void afterPropertiesSet ( ) throws Exception {
System. out.println ( "InitializingBean . . . " )
}
}
Spring的实例化方式主要如下两种:
构造方式实例化:底层通过构造方法对Bean进行实例化
工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
构造方式实例化Bean:
分为无参构造方法实例化和有参构造方法实例化,Spring中配置的几乎都是无参构;有参构造在实例化Bean时,需要参数的注入,通过标签,嵌入在 标签内部提供构造参数
工厂方式实例化Bean,可分为如下三种:
静态工厂方法实例化Bean
实例工厂方法实例化Bean
实现FactoryBean规范延迟实例化Bean
静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其静态方法配置给Spring即可。
//工厂类
public class UserDaoFactoryBean {
//非静态工厂方法
public static UserDao getUserDao(String name){
//可以在此编写一些其他逻辑代码
return new UserDaoImpl();
}
}
UserDaoImpl实例对象会存在于单例池中。
实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean。
//工厂类
public class UserDaoFactoryBean2 {
//非静态工厂方法
public UserDao getUserDao(String name){
//可以在此编写一些其他逻辑代码
return new UserDaoImpl();
}
}
在Spring容器创建时,就完成了Bean的实例化,单例池中既有工厂Bean实例,也有目标Bean实例.
注:
标签不仅仅是为构造方法传递参数,只要是为了实例化对象而传递的参数都可以通过 标签完成,例如上面通过工厂方法实例化Bean所传递的参数也是要通过 进行传递的
Spring提供的FactoryBean接口规范(源码)
package org.springframework.beans.factory;
public interface FactoryBean {
//获得实例对象方法
T getObject() throws Exception;
//获得实例对象类型方法
Class> getObjectType();
boolean isSingleton();
}
实现过程
定义工厂实现FactoryBean
public class UserDaoFactoryBean3 implements FactoryBean {
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class> getObjectType() {
return UserDao.class;
}
}
ps:
通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() ,此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。