[Spring]Spring的getBean路线-createB
前言
承上启下:
- Spring的
refresh
->finishBeanFactoryInitialization
(容器初始化单例非延迟加载Bean的入口). -
beanFactory.preInstantiateSingletons();
,Bean工厂开始加载Bean实例. - 获取beanName列表,循环对每个beanName进行
getBean
操作. -
getBean
中调用了doGetBean
进行了一些创建Bean的前置处理.最终在getSingleton
中调用了createBean
进行Bean的创建.
OK,下面进入今天的主题-createBean.
createBean的总体流程
- 解析Bean类型,获取Class: resolveBeanClass.
- 检查和准备Bean中的方法覆盖: prepareMethodOverrides.
- 应用实例化之前的后处理器: resolveBeforeInstantiation.
- 开始创建Bean: doCreateBean
1. resolveBeanClass-解析Bean类型,获取Bean的Class.
- AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 确认当前的Bean类是可以被解析的,并且支持克隆BeanDefinition,merged的BeanDefinition不在此方法的考虑范围
// 进入到里面,会发现器通过了类加载器进行了Class的获取
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
// 克隆一份BeanDefinition,用来设置上加载出来的对象
// 采用副本的原因是某些类可能需要动态加载Class
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 省略若干代码
}
容器在前面已经加载并注册好了
BeanDefinition
,它描述了关于Bean的信息,在此处Spring要开始将自己抽象出来的BeanDefinition
进行解析.这里思考一个问题,为什么Spring在加载Bean的时候选择了RootBeanDefinition
进行解析,而不是之前在加载BeanDefinition
的时候反复说到的GenericBeanDefinition
?
RootBeanDefinition
对应的是Java中的继承体系而制造的复合BeanDefinition
(Spring在定义Bean时,也支持定义继承关系).从各种容器加载出来的BeanDefinition
,最终都会通过getMergedLocalBeanDefinition
转化成RootBeanDefinition
.
RootBeanDefinition
可以合成有继承关系的BeanDefinition
(如果没有继承关系,那么自己便是代表parent).这里推荐一篇文章,希望可以带来更多的思考: 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)
OK,回到主题,拿到传进来的
RootBeanDefinition
后,Spring需要确认当前的Bean类是可以被解析的,即是否能通过类加载器进行载入.对于注解容器来说,在组件扫描的时候就通过ResourceLoader进行了资源的定位,所以在这里是可以确认可以被解析的.
考虑到健全性,Spring还是谨慎地进行了校验,毕竟不是所有的BeanDefinition
都是通过注解容器加载的.
- AbstractBeanFactory#resolveBeanClass
protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// 如果当前BeanDefinition存储beanClass属于Class实例,直接返回
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
// 如果当前BeanDefinition没有存储Class实例,那么尝试解析
return doResolveBeanClass(mbd, typesToMatch);
}
}
catch (PrivilegedActionException pae) {
ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
- AbstractBeanFactory#doResolveBeanClass
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// 获取BeanDefinition的className.
String className = mbd.getBeanClassName();
if (className != null) {
// 根据className解析成表达式
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
// 如果解析后的表达式为Class则直接返回
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
// 反射工具类加载Class
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
return mbd.resolveBeanClass(beanClassLoader);
}
这里Spring会获取到当前工厂的类加载器,然后从BeanDefinition中获取className.Spring会先对className做表达式解析,如果不是通过表达式进行解析,那么调用
ClassUtils.forName(className, dynamicLoader);
,如果className不存在,再使用类加载器进行加载.类于类加载器是一一对应的关系,Spring需要找到可以加载该类的类加载器,然后加载出Class对象.
2. 检查和准备Bean中的方法覆盖-prepareMethodOverrides
- AbstractAutowireCapableBeanFactory#createBean
// Prepare method overrides.
// 检查和准备Bean中的方法覆盖
try {
mbdToUse.prepareMethodOverrides();
}
- AbstractBeanDefinition#prepareMethodOverrides
主要针对
lookup methods
做校验和方法覆盖。现在用得比较少了.
如果对Lookup方法注入
有兴趣,可以在Spring的官网查看: 点我前往
- AbstractBeanDefinition#prepareMethodOverrides
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
// 检查查找方法是否存在,并确定其重载状态。
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
- AbstractBeanDefinition#prepareMethodOverride
验证并准备给定的方法是否被重写。检查是否存在具有指定名称的方法,如果找不到该方法,则将其标记为未重载。
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
// 如果不存在重载,在使用CGLIB增强阶段就不需要校验了
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
// 将替代标记为未过载,以避免arg类型检查的开销。
mo.setOverloaded(false);
}
}
3. 激活Bean实例化前的后置处理器-resolveBeforeInstantiation
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 解析BeanPostProcessors的BeanPostProcessorsBeforeInstantiation,试图返回一个需要创建Bean的代理对象
// resolveBeforeInstantiation只针对有自定义的targetsource.
// 因为自定义的targetsource不是Spring的bean,那么后续的初始化与该bean无关
// 因此直接可以进行代理
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);
}
- AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果beforeInstantiationResolved为false
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 如果注册了InstantiationAwareBeanPostProcessors的BeanPostProcessor.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 执行实现了该后置处理器接口的类中postProcessBeforeInitialization方法
// Spring在这里使用了责任链模式,如果有一个后置处理器可以返回Object,就会马上跳出循环
// 同时,如果第三方框架在此后置处理器对Bean执行了操作,那么将不会进入到doCreateBean中了.
// 注意传参,这里传入的是一个class和beanName.
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
如果当前的Bean实现了InstantiationAwareBeanPostProcessor接口,并且在postProcessBeforeInstantiation中返回了Object,那么Spring将不会执行
doCreateBean
进行实例化,而是将当前用户返回的bean实例直接返回。
AbstractAutoProxyCreator
这个AOP代理的BeanPostProcessor便是这样做的.
执行完before的操作后,如果返回了实例,那么继续执行after的操作.
其中,before和after的执行逻辑有点区别:
before方法执行的中断条件:
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
after方法执行的中断条件:
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
关注这个BeanPostPorcessor,在后续的学习中,我们仍能在过滤器中学习到这种职责链的设计原则.
我们来看看InstantiationAwareBeanPostProcessor的接口清单.默认返回null.
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
}
4. 开始创建Bean-doCreateBean
OK,再梳理一下思路,从createBean中,Spring分析了当前的Class是否能被类加载器加载,如果可以加载,返回当前
BeanDefinitino
的Class对象,接着进行了Lookup method
的检查,最后激活了InstantiationAwareBeanPostProcessors
的方法,如果以上方法都没中断,那么Spring将进行Bean的实例化-doCreateBean.
try {
// 创建bean的入口
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
总结
- 在createBean阶段,Spring会分析当前BeanDefinition的Class是否是可解析的.具体表现为用类加载器进行loadClass或者Class.forName
- 检查当前BeanDefinition的Lookup method是否存在,并且确认重载状态.
- 如果实现了
InstantiationAwareBeanPostProcessors
,激活此后置处理器,如果可以从此后置处理器中获取Bean实例,那么直接返回该Bean实例,不会进行doCreateBean
操作. - 开始Bean的实例化-doCreateBean.
doCreateBean篇幅较长,将拆分几篇文章进行讲解,如果觉得不错,请关注我的博客~