上周主要了解了spring boot项目启动过程中,beanFactory的继承体系,以及beanFactory是怎么创建的。今天继续来看下beanFactory这个容器的详细信息,因为beanFactory属性和方法比较多,今天主要看下它比较重要的几个属性和方法。
一、属性
beanFactory负责管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期,再加上DefaultListableBeanFactory的父类也比较多,也导致了beanFactory属性非常的多。下面是我认为比较重要的一些属性,这些属性可能是定义在DefaultListableBeanFactory类中,也可能定义在其父类中,但是为了方便我就全部写到一起了,下面是代码:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
// 继承子父类的属性
// 创建bean实例的策略,使用的是cglib
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
// 是否自动尝试解析bean之间的循环引用
private boolean allowCircularReferences;
// 在依赖性检查和自动装配时忽略的依赖关系类型,存储的为Class对象
private final Set<Class<?>> ignoredDependencyTypes;
// 在依赖性检查和自动装配时忽略的依赖关系类型,存储的为Class对象。默认值忽略BeanFactory
private final Set<Class<?>> ignoredDependencyInterfaces;
// 当前正在创建的bean的名称,用于从用户指定的Supplier回调触发的getBean等调用的隐式依赖注册。
private final NamedThreadLocal<String> currentlyCreatedBean;
// 是否缓存bean的元数据,或者每次访问时重新获取
private boolean cacheBeanMetadata = true;
// 要在createBean中应用的BeanPostProcessors
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList();
// 从bean名称映射到合并的RootBeanDefinition
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);
// 已经创建至少一次的bean的名称
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap(256));
// 当前正在创建的bean的名称
private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation");
// 本身的属性值//
// 是否允许使用相同bean名称重新注册不同的bean定义,即注册的两个相同的名字的bean,且用后面的bean覆盖前面的
private boolean allowBeanDefinitionOverriding = true;
// 是否允许预加载
private boolean allowEagerClassLoading = true;
// 检查bean定义是否为一个autowire注入的解析器
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
// 根据依赖类型映射到相应的自动注入的值map集合
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
// 键值是bean名称,映射值为bean定义对象的map集合
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
// 以依赖类型的类对象为键,所有bean(单例非单例)的名称为值得map集合
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
// 以依赖类型的类对象为键,所有单例bean的名称为值的map集合
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
// bean定义的名称list,按照注册顺序
private volatile List<String> beanDefinitionNames = new ArrayList(256);
// 省略
....
}
看到这里我就记得上次中遇到的一个问题,就是同名bean的创建,当时日志显示的当前bean的类型不是期望的类型,因为allowBeanDefinitionOverriding的属性值默认为true。当然这个属性是可以修改的,有兴趣可以网上找一下相关方法。有些属性又会涉及到很多不太熟悉的类,比如AutowireCandidateResolver、BeanDefinition、RootBeanDefinition等等,AutowireCandidateResolver是检查bean是否通过Autowire注入的解析器。BeanDefinition描述了一个bean实例,它保存相关的属性值,构造函数参数值以及具体实现提供的更多信息。RootBeanDefinition表示合并的bean定义,它在运行时支持BeanFactory中的特定bean,它本质上是运行时的“统一”bean定义视图。反正遇到不清楚的就去看下源码的注解,有时不一定非要特别清楚,了解它的作用就行。接下来我们看下相关的一些方法吧,同样的,这些方法可能是DefaultListableBeanFactory类,也可能是其父类的。
二、相关方法
方法也非常多,一样选择几个来看。beanFactory负责bean的加载、实例化以及相互之间的关系,我们对应一个一个。
1、创建bean
创建bean的方法来自于AbstractAutowireCapableBeanFactory,下面我们看看源码,简单的分析一下大概的过程。
public <T> T createBean(Class<T> beanClass) throws BeansException {
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
return (T) createBean(beanClass.getName(), bd, null);
}
首先以类对象为参数创建出RootBeanDefinition实例,然后设置其为原型模式,即prototype,这样的目的就是为了避免它作为一个依赖bean存在,因为每个RootBeanDefinition创建都需要一个对应的bean的类对象。然后调用下面的方法
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
这个方法里面先执行resolveBeanClass(mbd, beanName)方法,即根据RootBeanDefinition实例和bean名称为参数,去解析对应的类对象,返回结果为bean名称的类对象。这个过程中会将已解析的Class存储在bean定义中以供进一步使用。然后执行prepareMethodOverrides方法,该方法主要为了验证并准备为此bean定义的方法覆盖,检查其是否存在具有指定名称的方法。然后是resolveBeforeInstantiation方法,即在实例化之前解析,这个方法为BeanPostProcessors提供返回代理对象而不是目标bean实例的机会,也就是说如果在实例化之间检验是否有这个bean的一个代理对象,有的话直接返回该代理对象,否则继续执行下面doCreateBean方法,我们看下doCreateBean源码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
1、这个方法先判断RootBeanDefinition是否为单例,如果为单例则从factoryBeanInstanceCache中移除该bean名称,否则执行2。
2、执行createBeanInstance方法创建bean实例,这个方法会使用适当的实例化策略为指定的bean创建新实例:比如工厂方法,构造函数自动装配或简单实例化,返回结果是一个bean的包装类对象。getWrappedInstance和getWrappedClass方法反别返回相应的bean对象和bean的类对象,并将该类对象赋值给resolvedTargetType。
3、接下来的同步代码块主要是为了允许post-processors(后处理器)修改合并的bean定义,即将MergedBeanDefinitionPostProcessors应用于指定的bean定义,并调用其postProcessMergedBeanDefinition方法。关于这点我也还不是太理解具体的作用。
4、判断是否支持earlySingletonExposure,即热缓存单例,以保证即使在BeanFactoryAware等生命周期接口触发时也能够解析循环引用。如果是则将创建新的单例工厂以构建指定的单例bean。
5、初始化bean实例,先执行populateBean方法,即使用bean定义中的属性值填充给定bean的包装类对象中的bean实例。然后执行initializeBean方法,初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器。
6、判断earlySingletonExposure属性值,如果为true,则获取早期的单例bean引用,如果不为空进行后续判断判断初始化后的exposedObject和第2步中的bean是否同一个bean,是将将早期单列bean引用赋值给exposedObject,否则继续进行其他判断。
7、执行registerDisposableBeanIfNecessary方法,将bean注册为一次性bean。最后返回相应bean实例。
当然我说是比较简单的,其实中间过程非常的复杂,因为涉及的方法很多,自己没办法每一个都贴一段代码,所以只能将就看吧。
2、初始化bean
初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器。这个在上面的createBean方法中有调用过,我们看下具体的代码
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
1、判断系统的securityManager是否为null,不为null执行AccessController.doPrivileged方法;否则执行2。
2、执行invokeAwareMethods方法,该方法两个参数,分别为bean名称beanName和实例bean。判断给定的bean是否为BeanNameAware实例,是则将bean实例名称设置为beanName;判断给定的bean是否为BeanClassLoaderAware实例,然后获取ClassLoader,不为空是则将ClassLoader引用赋值给bean的beanClassLoader变量;最后判断bean实例是否为BeanFactoryAware,是则调用setBeanFactory方法,将AbstractAutowireCapableBeanFactory实例赋值给bean的beanFactory变量。
3、将bean实例赋值给变量wrappedBean,然后判断RootBeanDefinition即mbd是否为null或者mbd为非合成,执行applyBeanPostProcessorsBeforeInitialization方法,该方法会获取到BeanPostProcessor实例,并执行各自的postProcessBeforeInitialization实现,其返回的bean实例可能是是原始实例的包装器对象。
4、执行invokeInitMethods方法,这个方法会将bean所有属性值都被设置,并了解它属于的bean工厂。这个需要检查该bean是否实现了InitializingBean或定义了一个自定义init方法,并调用必要的回调方法。看下面的代码:
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
先判断bean是否实现了InitializingBean,如果是,且满足其他判断条件,则执行afterPropertiesSet方法。如果mbd不为null,且bean实例的类对象不为NullBean,则从RootBeanDefinition实例获取initMethodName名称,如果满足判断条件,则执行invokeCustomInitMethod方法,该方法通过反射执行自定义的init方法。
5、执行mbd为null或者mbd.isSynthetic()为false的判断条件,满足条件执行applyBeanPostProcessorsAfterInitialization,即完成初始化后应用BeanPostProcessors方法,该方法和3中的applyBeanPostProcessorsBeforeInitialization方法比较相像,都是执行每个PostProcessor各自的postProcessAfterInitialization方法。最后返回wrappedBean,这个是一个原始bean的包装器对象。
其实初始化bean的方法应该算是创建bean的一个部分,我为了区分就单独拿出来了,今天主要就是了解beanFactory的成员变量以及两个方法,但是这两个方法比我想象的还是要复杂一点,代码还是蛮多的,关于其他的一些方法我们下次继续再看。
最后想说一下周五的一个面试情况,自己虽然投了十几份简历也就那么2、3家面试邀请,但是因为在异地,自己拒了一家。星期五我觉得很有必要去面一下,请假去了上海。周五面的是中通快递,地点很偏僻,面试体验也并不太好,当然自己也没有怎么准备(有点托大,后悔)。面试问题主要是Java基础,多线程我说没怎么用过面试官就没问了,其实这部分自己看得东西也蛮多的;然后spring cloud和dubbo对比,这个我没回答好,缺少实际的使用经验。mybatis的一点基础OGNL表达式和EL表达式的区别,我只记得OGNL能更好的防止SQL注入;redis持久化的两种方式,自认为答的还行,毕竟前段时间刚学了;然后就是Java基础,问的也不多,都是比较常规的,自己觉得回答都还OK。另外数据库索引方面的知识,面试官问索引最优实现以及给了一个场景自己判断需不需要加索引,怎么加索引,虽然自己学了,但是感觉回答的不是很好。面试时间挺短的,自己还等了HR半个小时,后来HR说初始先这样吧,我觉得应该是没戏了,毕竟HR都没面。感觉自己还是需要多出去面试一下,刷下经验。
网友评论