一、前言
????????在上一节我们主要说了Spring在实例化bean前做的一些工作,主要是注册转换器以及属性解析器并且会冻结目前已经注册的BeandDefinition。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 1. 初始化此上下文的转换服务,用来自定义将Spring中的某个Bean的属性从一个类型转换到另外一个类型.
// 判断Bean工厂中是否存在名称为conversionService的转换服务bean,如果存在而且类型为ConversionService,则获取该Bean实例,并将其设置到BeanFactory中
/**
* 例如:
* (1)有如下的javaBean:
* public class Person {
* public String name;
* public Date birthday;
* ...
* }
* (2)有如下的xml配置:
* <bean name="person" class="com.wb.test.Person">
* <property name="name" value="wangbing"/>
* <property name="birthday" value="1999-03-03"/>
* </bean>
* (3)有如下的测试类:
* ApplicationContext acx = new ClasspathXmlApplicationContext("test.xml");
* Person person = (Person) acx.getBean("person");
* System.out.println(person.name);
* System.out.println(person.birthday); // 改行会报错,提示字符串类型不能转换为日期类型
*
* (4)可以通过定义如下名称的bean,将某种类型的属性值转换为另外一种类型.
* <bean name="conversionService" class="com.wb.test.MyConversionService" />
* public class MyConversionService implements ConversionService {
* // 实现是否能转换以及具体转换的方法。
* public boolean canConvert(Class<?> sourceType, Class<?> targetType) {}
* public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {}
* public <T> T convert(Object source, Class<T> targetType) {}
* // 可以在该方法中实现转换逻辑。如果源类型sourceType是String类型的话,将其转换为Date类型返回。
* public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {}
* }
*/
// 2.在Spring中,如果需要配置自定义的转换器,还可以直接利用Spring提供的ConversionServiceFactoryBean来完成。自己只需要实现具体的转换逻辑即可
/**
* (1)配置conversionService对应的工厂Bean:
* <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
* <property name="converters">
* <bean class="com.wb.test.MyConverter"/>
* </property>
* </bean>
* (2)然后自己去实现MyConverter即可:
* public class MyConverter implements Converter<String,Date> {
* @Override
* public Date convert(String source) {
* DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
* try {
* return format.parse((String) source);
* } catch (ParseException e) {
* e.printStackTrace();
* }
* return null;
* }
* }
*/
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)
&& beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
/**
* 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器,
* 主要用于注解属性值的解析例如:@Value("${app.name}")。
*/
// 值解析器设置的地方:在调用invokeBeanfactoryPostProcessor方法的时候,通过PropertySourcesPlaceholderConfigurer的后置处理方法设置进去的
if (!beanFactory.hasEmbeddedValueResolver()) {
// 调用resolvePlaceholders方法解析strVal对应的值
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
/**
* 初始化所有实现了LoadTimeWeaverAware接口的子类,用于类在加载进入jvm之前,动态增强类
* 这特别适用于Spring的JPA支持,其中load-time weaving加载织入对JPA类转换非常必要
*/
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时的类加载器.
beanFactory.setTempClassLoader(null);
// 缓存(冻结)所有的BeanName(注册的bean定义不会被修改或进一步做处理了,因为下面马上要创建Bean的实例对象了)
beanFactory.freezeConfiguration();
// 初始化所有的单实例Bean,包括创建单实例bean的全部过程
beanFactory.preInstantiateSingletons();
}
????????他真正去做实例化bean的还是在preInstantiateSingletons()方法中,接下来我们来分析一下这个方法的源码。
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// 创建BeanDefinitionNames的副本BeanNames用于后续的遍历,以允许init等方法注册新的bean定义.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有的beanNames,触发所有非懒加载单例bean的初始化,即:创建所有的单实例Bean
for (String beanName : beanNames) {
// 获取beanName对应的MergedBeanDefinition.在实例化之前将所有的beanDefiniton对象在转换成RootBeanDefinition,进行缓存,后续在需要马上实例化的时候直接获取定义信息,而定义信息中
// 如果包含了父类就需要先实例化父类。
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果bd对应的Bean实例满足:(不是抽象类 && 是单例 && 不是懒加载)
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断BeanName对应的Bean实例是否是FactoryBean.
/**
* BeanFactory 与FactoryBean的区别
* 相同点:都是用来创建bean对象的
* 不同点:
* 如果使用了BeanFactory那么就必须要严格遵循SpringBean的生命周期接口,例如从实例化 ——>初始化等等一系列方法,此流程非常的负责且麻烦
* 如果使用FactotyBean则创建bean就更加方便简单,不需要遵循spring的生命周期流程,
* 他主要有getObject():直接返回一个对象,isSingleton():判断是否是单例,getObjectTye():返回需要返回对象的类型三个方法。
*/
if (isFactoryBean(beanName)) {
// 通过beanName获取FactoryBean的实例,factoryBean的名称是:"&" + beanName
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// 判断这个FactoryBean是否需要紧急初始化.
// System.getSecurityManager()方法是获取系统权限管理器,Java为了防止恶意代码执行(修改,删除操作系统文件),做了权限管理,
// 默认的安全管理器配置文件是: $JAVA_HOME/jre/lib/security/java.policy
/**
* 在做访问控制决定时,如果遇到通过调用不带上下文参数(请参阅下文,以获取关于上下文参数的信息)的 doPrivileged 标记为“特权”的调用方,
* 则 checkPermission 方法将停止检查。如果该调用方的域具有指定的权限,则不进行进一步检查,并且 checkPermission 正常返回,
* 指示允许所请求的访问。如果该域不具有指定的权限,则通常抛出异常。
*
*
* AccessController.doPrivileged()方法的例子:
* 假设有这样一种情况:A程序想在 C:\\Users\\Jack\\Desktop\\test1? 这个目录中新建一个文件,但是它没有相应的权限,
* 但是它引用了另外一个Jar包B,刚好B有权限在C:\\Users\\Jack\\Desktop\\test1目录中新建文件,
* 还有更巧的是B在新建文件的时候采用的是AccessController.doPrivileged方法进行的,这种情况下,A就可以调用B的创建文件的方法进行创建文件了。
*/
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 如果需要紧急初始化,则通过beanName获取Bean的实例.
getBean(beanName);
}
}
}
else {
// 如果BeanName对应的Bean实例不是FactoryBean,则通过BeanName去获取Bean实例.
getBean(beanName);
}
}
}
/**
* 上一步for循环中已经创建完了所有的单实例Bean,这个for循环中,会拿出所有的单实例Bean,
* 然后遍历,判断单实例bean是否实现了SmartInitializingSingleton接口,如果实现了该接口,
* 则调用单实例Bean的afterSingletonsInstantiated方法
*/
for (String beanName : beanNames) {
// 获取beanName对应的bean实例
Object singletonInstance = getSingleton(beanName);
// 判断当前的bean是否实现了SmartInitializingSingleton接口.
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 触发SmartInitializingSingleton实现类的afterSingletonInstantiated方法.
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
/**
* 如果实现了SmartInitializingSingleton接口,则会调用afterSingletonInstantiated方法
* 例如@EventListener注解的实现原理,就是利用EventListenerMethodProcessor后置处理器完成的,
* 而在EventListenerMethodProcessor中就是实现了SmartInitializingSingleton接口
*/
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
? ? ? ? 以上的方法大概做了:
- 遍历所有的beanNames,触发所有非懒加载单例bean的初始化,即:创建所有的单实例Bean;
- 获取beanName对应的MergedBeanDefinition.在实例化之前将所有的beanDefiniton对象在转换成RootBeanDefinition,进行缓存,后续在需要马上实例化的时候直接获取定义信息,而定义信息中,如果对应的beanDefinition包含了父类那就需要实例化父类。
- 判断对应的bean不是抽象类 && 是单例 && 不是懒加载才会进行初始化;
- 判断是否是factoryBean,然后通过getBean()方法去初始化bean。
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
// 拿到真正的bean的beanName(去掉和&前缀和解析别名之后的)
String beanName = transformedBeanName(name);
// 从缓存中获取bean的实例对象.
Object beanInstance = getSingleton(beanName, false);
// 如果bean实例不为空,直接判断获取的bean实例是否为FactoryBean
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
// 如果缓存中不存在beanName对应的对象 && 父beanFactory为ConfigurableBeanFactory的实例,则调用父BeanFactory判断是否为FactoryBean
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
// 通过MergedBeanDefinition来判断beanName对应的Bean是否为FactoryBean.
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
// 获取beanName对应的Bean实例的类型
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
// 返回beanType是否为FactoryBean本身,(子类,或者子接口).
return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
}
?????????如果该bean已经初始化则去缓存中获取bean,并且判断给初始化出来的bean是不是FactoryBean,否则如果当前bean都不在当前bean容器中(存在父子容器),那就调用父容器来判断是否是FactoryBean,否则通过MergedBeanDefinition来判断beanName对应的Bean是否为FactoryBean。
一、FactoryBean和BeanFactory的区别
? ? ? ? 相信面试很多人会被问到这个问题,那他们到底有什么区别呢?
? ? ? ? 首先先说他们的相同点:都是用来创建bean对象的。
? ? ? ? 不同点:如果使用了BeanFactory那么就必须要严格遵循SpringBean的生命周期接口,例如从实例化 ——>初始化等等一系列方法,此流程非常的负责且麻烦,如果使用FactotyBean则创建bean就更加方便简单,不需要遵循spring的生命周期流程,他主要有getObject():直接返回一个对象,isSingleton():判断是否是单例,getObjectTye():返回需要返回对象的类型三个方法。
? ? ? ? 我们来看下一个beanfactory的配置实现:
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
public String getCarInfo() {
return carInfo;
}
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] split = carInfo.split(",");
car.setName(split[0]);
car.setBrand(split[1]);
car.setSpeed(Integer.valueOf(split[2]));
return car;
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
? ? ? ? 修改配置文件:
<?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.xsd">
<bean id="car" class="org.mqc.factorybean.MyFactoryBean" >
</bean>
</beans>
? ? ? ? 测试代码:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
Car car=(Car)context.getBean("car");
System.out.println(car);
}
}
?
? ? ? ? 接下来我们来看下如果是一个FactoryBean,Spring是如何进行初始化的。
? ? ? ? 如果是一个FactoryBean,Spring通过beanName获取FactoryBean的实例,factoryBean的名称是:"&" + beanName;
? ? ? ? 我们知道通过调用getBean之后,我们会调doGetBean()然后调用createBean,然后得到一个bean实例(如果对这块不是很熟悉的,可以先去看下之前的Spring源码解析(5)之bean实例化过程(上)_jokeMqc的博客-CSDN博客),然后就会调用getObjectForBeanInstance,我们来看下这个方法的源码:
? ? ? ? ? 我们来看下做了哪些事情:
- 调用父类AbstractBeanFactory的getObjectForBeanInstance方法获取bean实例;
- 首先会判断名字如果是&开头但是又不是FactoryBean则会提示报错,然后又会判断是否是NullBean;
- 如果不是工厂bean或者bean的名称也是不是以&开头,则直接返回上一步中已经创建好的bean对象,所以我们知道getObjectForBeanInstance是用来处理FactoryBean的;
- 会去缓存中找,如果找不到则会调用getObjectFromFactoryBean来回调FactoryBean的getObject方法。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 从ThreadLocal中获取当前正在创建的Bean的名称
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}
// 调用父类AbstractBeanFactory的getObjectForBeanInstance方法获取bean实例
return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 不为null而且以&开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 如果不是工厂bean或者bean的名称也是不是以&开头,则直接返回上一步中已经创建好的bean对象.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 先从FactoryBean对应的缓存factoryBeanObjectCache中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// bean定义不为空而且对应的class类为一个合成类.
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 回调FactoryBean的getObject方法
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
? ? ? ? 我们来看下getObjectFromFactoryBean的源码:
- 首先会判断该bean是不是单例的,如果是多例的,每次都会调用子类的getObject方法进行bean实例的创建;
- 根据名称从factoryBeanObjectCache缓存中获取由FactoryBean创建的bean实例,如果未获取到,则表示之前还没有创建过,则调用FactoryBean子类的getObject方法进行创建,后将创建成功的bean实例放入到factoryBeanObjectCache缓存中;
- 调用doGetObjectFromFactoryBean回调FactoryBean的getObject方法;
- 放入factoryBeanObjectCache缓存中;
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果是单例的
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
/**
* 首先根据名称从factoryBeanObjectCache缓存中获取由FactoryBean创建的bean实例。
* 如果未获取到,则表示之前还没有创建过,则调用FactoryBean子类的getObject方法进行创建,
* 然后将创建成功的bean实例放入到factoryBeanObjectCache缓存中
*/
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 回调FactoryBean的getObject方法
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
// bean创建之后进行一些校验操作
beforeSingletonCreation(beanName);
try {
// 使用factoryBean创建bean实例之前的后置处理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
// 将由FactoryBean创建的Bean实例放入到factoryBeanObjectCache缓存中
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 如果是多例的,每次都会调用子类的getObject方法进行bean实例的创建
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
????????
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 调用FactoryBean子类的getObject方法去获取bean实例.
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
// 未获取到bean时,返回一个空Bean。NullBean对象
object = new NullBean();
}
return object;
}
?????????可以看得到我们是回到getObject方法来创建实例,然后把创建好的实例对象放入到factoryBeanObjectCache缓存中。
?????????
? ? ? ? ?可以看得到我们的FactoryBean的实例是放在一级缓存中的,而我们通过BeanFactory的getObject()方法获取得到的bean是放在factoryBeanObjectCache缓存中的。
? ? ? ? 好了到这里factoryBean的源码已经分析完毕了,这里提出一个疑问?在Spring中如果我们要在一个单例bean中保存一个protype类型的bean,那该怎么操作?
|