一、目录

  1. 前言
  2. 创建 Bean 容器
  3. 加载 Bean 定义
  4. 创建 Bean
  5. Spring Bean 创建过程中的设计模式
  6. 总结

二、前言

2.1 Spring 使用配置

    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config-ioc.xml");
UserService userService = context.getBean("userService",UserService.class);
userService.sayHello("zhangsan");

而在 spring-config-ioc.xml 中只是简单的定义了 userService Bean:

    <bean id="userService" class="com.jd.spring.service.ioc.impl.UserServiceImpl">
</bean>

Spring 使用的版本为 3.2.6.RELEASE,下面我们通过源码一步步来了解下 Bean 的创建过程。

三、创建 Bean 容器

Spring 容器包括两类:BeanFactroy 和 ApplicationContext,ApplicationContext 扩展自 BeanFactory,在之上又增加了一些扩展功能,下面我们以 ClassPathXmlApplicationContext 为例来看下容器的创建过程。

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
//在此进行容器的创建,Bean的加载,创建
refresh();
}
}

refresh 实现步骤如下:

1.prepareRefresh

主要用来验证一些需要的系统变量。

2.obtainFreshBeanFactory

创建 BeanFactory,然后加载 Bean 定义

    protected final void refreshBeanFactory() throws BeansException {
//判断beanFactory是否为null
if (hasBeanFactory()) {
//如果之前已经创建了BeanFactory,调用Bean的destroySingletons方法
destroyBeans();
//将beanFactory设置为null
closeBeanFactory();
}
try {
//创建的容器类为DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//设置是否允许override,循环引用,QualifierAnnotationAutowireCandidateResolver
customizeBeanFactory(beanFactory);
//加载Bean定义
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
}

此时可以看到创建的 BeanFactory 为 DefaultListableBeanFactory,通过源码我们可以看到 BeanFactory 和 ApplicationContext 类关系图如下:

3.prepareBeanFactory

添加对 spel 的支持,默认的属性编辑器,同时设置忽略依赖的接口

    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

4.postProcessBeanFactory

5.invokeBeanFactoryPostProcessors

Bean 容器创建后执行,执行 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法。

6.registerBeanPostProcessors

注册 BeanPostProcessor,Bean 创建后执行。BeanPostProcessor提供 postProcessBeforeInitialization、postProcessAfterInitialization 初始化前、初始化后执行方法。

7.initMessageSource

初始化消息资源(国际化)。

8.initApplicationEventMulticaster

注册了 SimpleApplicationEventMulticaster 广播器。

9.onRefresh

初始化一些特殊的 Bean,留给子类来实现。

10.registerListeners

注册事件监听。

11.finishBeanFactoryInitialization

实例化所有单例非延迟加载 Bean,beanFactory.preInstantiateSingletons();

12.finishRefresh

    // Initialize lifecycle processor for this context.
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh(); // Publish the final event.
publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);

四、加载 Bean 定义

入口为 AbstractXmlApplicationContext.loadBeanDefinitions 方法,通过 XmlBeanDefinitionReader 来加载 BeanDefinitions。

4.1 获取资源文件

    Resource[] resources = ((ResourcePatternResolver)
resourceLoader).getResources(location);

获取资源文件分为如下几种情况:

  • 如果 locationPattern 是 classpath*:spring-config-ioc.xml 这种格式的话,那么最终通过 getClassLoader().getResources(path) 来获取资源文件;
  • 如果 locationPattern 是 classpath:spring-config-ioc.xml 这种格式的话,new ClassPathResource(location.substring(CLASSPATHURLPREFIX.length()), getClassLoader());
  • 如果 locationPattern 是 spring-config-ioc.xml 这种格式的话
        try {
// Try to parse the location as a URL...
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}

最终返回 new ClassPathContextResource(path, getClassLoader())。

4.2 加载 Bean 定义

加载 Bean 定义的入口为 XmlBeanDefinitionReader.loadBeanDefinitions,核心方法如下:

    Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);

首先通过 documentLoader 获取到 xml 文件对应的 Document 对象,然后再解析 Document 对象,最终注册 registerBeanDefinitions。这里面的方法调用层级比较多,但是都相对比较简单,我就不一一列出了,我只列出一些核心,关键的代码,其它代码大家可以自己跟下。

在解析的时候 Spring 会留有解析前处理,解析后处理方法,供子类实现。

    //创建Bean解析的代理类,同时解析出在beans中定义的default属性,如default-lazy-init="default"
//default-autowire="default"
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);

解析 BeanDefinitions:

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//解析默认标签元素
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
//解析自定义标签
delegate.parseCustomElement(root);
}
}

如果节点元素的 namespaceURI 为http://www.springframework.org/schema/beans,那么认为是默认元素,否则认为是自定义元素。自定义元素通过 NameSpaceHandler 类类处理,不同的标签有不同的处理类。

默认元素主要包括如下 4 种:

  • import:解析 import 元素,然后加载 resource 指定的配置文件,过程同上
  • alias:解析别名
  • Bean:解析Bean,下面重点讲解
  • Beans:解析Beans,循环解析Beans下的元素,过程同上

解析 Bean 定义过程如下:

    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//将BeanDefinition注册到BeanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//注册完成后发送事件通知
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}

解析过程主要包括 3 部分:解析 Bean 定义,然后注册到 BeanFactory,最后发送注册完成通知。

4.2 解析 Bean 定义

    String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

parseBeanDefinitionElement 过程如下:

    className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);

1.创建 BeanDefinition 对象

创建 GenericBeanDefinition 对象。

2.解析 BeanDefinition 属性

解析 scope、singleton、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、factory-bean 属性。scope、singleton 不能同时存在。

3.解析 Meta 元素

解析 bean 下的 meta 元素,如

    <meta key="name" value="zhangsan"/>

通过 BeanDefinition.getAttribute 获取属性值。

4.解析 LookupOverride 子元素

解析 lookup 子元素并注册到 BeanDefinitions,BeanDefinition 持有 MethodOverrides 引用:

    private MethodOverrides methodOverrides = new MethodOverrides();

    MethodOverrides:
private final Set<MethodOverride> overrides = new HashSet<MethodOverride>(0);

5.解析 ReplacedMethod 子元素

解析 replace 子元素并注册到 BeanDefinitions。

6.解析构造器元素

解析构造器元素 constructor-arg。

7.解析属性元素

解析 property 属性,属性值:

    Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);

属性 name 的解析相对简单,属性 value 的解析比较复杂,涉及到 ref、value,还有可能是子元素 array、list、set、map、props,这里就不展开说明了,感兴趣的可以自己看下。

8.解析 Qualifier 元素

解析 Qualifier 元素。

4.3 注册 Bean 定义

通过 BeanDefinitionRegistry 来注册 BeanDefinition,最终是将 BeanDefinition 保存在 BeanFactory 中,

    this.beanDefinitionMap.put(beanName, beanDefinition);

BeanFactory持有beanDefinitionMap引用:

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

4.4 发送通知

bean 注册完成后,发送通知,Listener 需要实现 ReaderEventListener 接口,

    public void fireComponentRegistered(ComponentDefinition componentDefinition) {
this.eventListener.componentRegistered(componentDefinition);
}

五、创建 Bean

在创建 ApplicationContext 时会默认初始化所有非懒加载的单例 bean(BeanFactory 容器的话是在 getBean 时创建 bean 对象)。创建 bean 的入口为 AbstractBeanFactory.getBean 方法,核心代码如下:

        // Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);

首先从"缓存"中查找 bean 是否已经创建,如果创建的话直接返回创建的 bean,否则执行创建 bean 的逻辑。如果 scope 配置为 prototype,那么每次 getBean 时都会创建 bean。

1.getSingleton

从缓存中获取 bean,此处很关键,用来解决 Spring 循环依赖问题。

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

首先从 singletonObjects 中获取对象,如果 singletonObjects 不存在的话那么从 earlySingletonObjects 中获取对象,earlySingletonObjects 存放的是创建中的对象(bean 已创建,但是还未初始化完成),singletonFactories 存放的是 bean 和 ObjectFactory 的关系,在 bean 创建完成后会保存 bean 和 ObjectFactory 的关系。singletonFactories 和 earlySingletonObjects 互斥。

2.合并 BeanDefinition

3.创建 bean dependsOn 依赖的 beans

如果我们配置了 bean 标签的 depends-on 属性,那么在创建 bean 前会首先创建依赖的 beans。

4.创建单例对象

    resolveBeanClass(mbd, beanName);

    mbd.prepareMethodOverrides();

    // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
Object beanInstance = doCreateBean(beanName, mbd, args);
  • resolveBeforeInstantiation

在 bean 实例化前、后执行,可以更改 bean 的实例化对象,如配置:

    <bean class="com.jd.spring.processor.MyInstantiationAwareBeanPostProcessor"/>

MyInstantiationAwareBeanPostProcessor类实现InstantiationAwareBeanPostProcessor,然后重写postProcessBeforeInstantiation方法:

    public Object postProcessBeforeInstantiation(Class<?> beanClass,
String beanName) throws BeansException {
if (beanName != null && beanName.equals("helloWorldService")) {
return new HelloWorldServiceProxy();
}
return null;
}

这样的话 helloWorldService 对应的 bean 为 HelloWorldServiceProxy。

  • doCreateBean

创建 bean 的实现方法,下面我们通过单独的章节来重点说明。

5.创建原型对象

    try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); getObjectForBeanInstance,如果创建的bean为FactoryBean,调用FactoryBean.getObject方法生成最终的bean。

5.1 doCreateBean

方法入口为 AbstractAutowireCapableBeanFactory.doCreateBean,doCreateBean 核心方法如下:

    if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
} addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
}); populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
5.1.1 createBeanInstance

创建 bean 实例,其本质是通过反射调用默认或有参的构造方法来创建 bean 实例,下面我们来看下具体的实现细节。

    //获取beanClass,通过Class.forName来获取
Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
//如果配置了factory-method,那么通过工厂方法来创建bean,这个稍后分析下 if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 获取构造器,可能通过默认构造器来创建bean,也可能通过有参构造器来创建bean
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
} // No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);

instantiateUsingFactoryMethod

通过工厂方法来创建,如果我们在定义 bean 时配置了 factory-method 属性,如

   <bean id="userServiceFactory" class="com.jd.spring.service.ioc.impl.UserServiceFactory" ></bean>
<bean id="userService" class="com.jd.spring.service.ioc.impl.UserServiceImpl" factory-bean="userServiceFactory" factory-method="getUserService" >
<property name="userServiceB" ref="userServiceB"> </property>
</bean>

那么将会通过 userServiceFactory的getUserService 方法来创建 bean,instantiateUsingFactoryMethod 方法实现如下:

    protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, Object[] explicitArgs) { return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

核心步骤如下:

1.获取工厂 bean

    String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
factoryBean = this.beanFactory.getBean(factoryBeanName);
if (factoryBean == null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"factory-bean '" + factoryBeanName + "' returned null");
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// It's a static factory method on the bean class.
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}

也就是说如果配置了 factory-bean 属性,那么工厂类为配置的 factory-bean,否则工厂类为当前 bean,但是要求工厂方法为静态方法。

2.获取工厂方法

    rawCandidates = (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
candidate.getName().equals(mbd.getFactoryMethodName()) &&
mbd.isFactoryMethod(candidate)) {
candidateSet.add(candidate);
}
}
Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]);
AutowireUtils.sortFactoryMethods(candidates);

获取工厂类中的工厂方法,并进行方法排序,因为会存在方法重载的情况,排序规则如下:

    public static void sortFactoryMethods(Method[] factoryMethods) {
Arrays.sort(factoryMethods, new Comparator<Method>() {
public int compare(Method fm1, Method fm2) {
boolean p1 = Modifier.isPublic(fm1.getModifiers());
boolean p2 = Modifier.isPublic(fm2.getModifiers());
if (p1 != p2) {
return (p1 ? -1 : 1);
}
int c1pl = fm1.getParameterTypes().length;
int c2pl = fm2.getParameterTypes().length;
return (new Integer(c1pl)).compareTo(c2pl) * -1;
}
});
}

先按方法修饰符进行排序,public 方法在前,non-public 方法在后;再按照方法参数个数进行排序,方法参数多的在前,少的在后。

然后按照配置的 ConstructorArguments 来匹配工厂方法。

3.反射执行方法创建 bean

beanInstance = beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, factoryBean, factoryMethodToUse, argsToUse);

最终通过反射创建 bean,factoryMethod.invoke(factoryBean, args);

autowireConstructor

使用有参的构造方法来创建 bean:

    Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
AutowireUtils.sortConstructors(candidates);

取得 beanClass 下的构造方法,同样进行排序,排序规则也是先按方法修饰符进行排序,public 方法在前,non-public 方法在后;再按照方法参数个数进行排序,方法参数多的在前,少的在后。

然后按照配置的 ConstructorArguments 来匹配构造方法,匹配规则是按照构造方法参数个数和参数类型进行匹配。

    if (explicitArgs == null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}

将匹配到的构造方法进行缓存,防止后续重复计算。找到匹配的构造方法后,然后通过反射创建 bean。

beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);

instantiateBean

使用默认的构造方法来创建 bean,同样也是通过反射创建 bean,代码如下:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
5.1.2 applyMergedBeanDefinitionPostProcessors
5.1.3 addSingletonFactory

如果对象为单例,并且允许提前曝光,并且 bean 正在创建中,那么将 bean 和 ObjectFactory 放入到 singletonFactory 中,此处的作用是用来解决循环依赖的问题。

5.1.4 填充属性

populateBean 核心代码如下:

//获取bean配置下的子元素property
PropertyValues pvs = mbd.getPropertyValues(); //如果指定了自动注入的模式,获取自动注入的属性
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
} // Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
} pvs = newPvs;
} //设置属性值
applyPropertyValues(beanName, mbd, bw, pvs);

autowireByName

autowire="byName" 根据名称自动注入,使用自动注入的好处是可以解决<bean> 标签下 <property> 标签过多的问题。

    //查找所有未配置的属性,在bean class中存在,但是未在xml配置文件中配置的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName); //获取bean
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName); }
}

autowireByType

autowire="byType" 根据类型自动注入。通过 DefaultListableBeanFactory.doResolveDependency 来获取属性的值,然后同样添加到 pvs,pvs.add(propertyName, bean);

在获取值的时候会根据 type 类型来做相应处理,如Array、Collection、Map,我们以常见的注入 bean 属性为例来看下实现代码:

//根据类型查找候选的bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(type, "", descriptor);
}
return null;
}
if (matchingBeans.size() > 1) {
String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); //如果根据类型匹配到多个bean,并且没有指定primaryBeanName属性的话那么会抛出类似expected single matching bean but found 2 这样的异常
if (primaryBeanName == null) {
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(primaryBeanName);
}
return matchingBeans.get(primaryBeanName);
}
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
if (autowiredBeanNames != null) {
autowiredBeanNames.add(entry.getKey());
}
return entry.getValue();

applyPropertyValues

TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

遍历配置的 property 子元素,然后获取 value/ref 对应的值

String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); //获取属性值,可能为字符串,也可能是bean,list,map
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
} // Set our (possibly massaged) deep copy.
try {
//deepCopy为PropertyValue集合,记录了属性名和属性值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}

上面最重要的两步为转换属性的值和设置属性的值,下面我们分别来看下。

  • convertForProperty

转换属性的值:

private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
if (converter instanceof BeanWrapperImpl) {
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
else {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
}
} public Object convertForProperty(Object value, String propertyName) throws TypeMismatchException {
//获取属性描述符,记录了属性的数据类型,如String,List,Map
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
if (pd == null) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"No property '" + propertyName + "' found");
}
return convertForProperty(propertyName, null, value, pd);
}

最终通过 typeConverterDelegate 代理类来执行:

this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);

转换过程如下:

1.查找是否定义了数据类型对应的自定义属性编辑器PropertyEditor,如果定义了自定义的PropertyEditor,则通过getValue获取值 2.判断是否定义了ConversionService,通过conversionService.convert来转换属性值3.convertToTypedArray

int arrayLength = Array.getLength(input);
Object result = Array.newInstance(componentType, arrayLength);
for (int i = 0; i < arrayLength; i++) {
Object value = convertIfNecessary(
buildIndexedPropertyName(propertyName, i), null, Array.get(input, i), componentType);
Array.set(result, i, value);
}

4.convertToTypedCollection

convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
Object element = it.next();
String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
Object convertedElement = convertIfNecessary(indexedPropertyName, null, element,
(elementType != null ? elementType.getType() : null) , elementType);
try {
convertedCopy.add(convertedElement);
}

遍历集合中的元素,然后生成转换后的集合。如果是 List 的话生成 ArrayList,Set 的话如果是排序 Set 的话生成 TreeSet,否则生成 LinkedHashSet

5.convertToTypedMap

//如果map类型为SortedMap,那么创建TreeMap;否则创建LinkedHashMap
convertedCopy = CollectionFactory.createApproximateMap(original, original.size()); while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object key = entry.getKey();
Object value = entry.getValue();
String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key,
(keyType != null ? keyType.getType() : null), keyType);
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value,
(valueType!= null ? valueType.getType() : null), valueType);
try {
convertedCopy.put(convertedKey, convertedValue);
}
}
  • setPropertyValues
 //deepCopy为PropertyValue集合,记录了属性名和属性值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :
pd.getWriteMethod());
writeMethod.invoke(this.object, value);

其实现本质就是获取属性对应的 set 方法,然后调用反射进行设置。需要注意情况如下:

1.如果定义了属性,但是未存在相应set方法,则抛出异常

Bean property 'name' is not writable or has an invalid setter method

2.如果属性为List,Map等集合属性,首先通过相应的read方法来获取已有值,然后再合并新的值。

5.1.5 bean 初始化
    invokeAwareMethods(beanName, bean);
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

1.执行 Aware 方法

    if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}

2.执行 BeanPostProcessor.postProcessBeforeInitialization

执行 BeanPostProcessor 的初始化前方法,BeanPostProcessor 需要在 xml 中配置,如

    <bean class="com.jd.spring.processor.MyBeanPostPrcessor"/>

3.执行 bean 初始化方法

    ((InitializingBean) bean).afterPropertiesSet();
invokeCustomInitMethod(beanName, bean, mbd);

首先执行 afterPropertiesSet 方法(如果实现 InitializingBean 接口的话),然后再执行自定义的初始化方法 init-method。

4.执行 BeanPostProcessor.postProcessAfterInitialization

执行 BeanPostProcessor 的初始化后方法,BeanPostProcessor 需要在 xml中 配置,如

    <bean class="com.jd.spring.processor.MyBeanPostPrcessor"/>

bean 初始化过程结果如下:

0003 - 基于xml的Spring Bean 的创建过程的更多相关文章

  1. Spring 源码(11)Spring Bean 的创建过程(2)

    Spring Bean 的创建过程介绍了FactoryBean 的创建方式,那么接下来介绍不是FactoryBean的创建方式,在创建过程中,又会分为单例的Bean的创建,原型类型的Bean的创建等. ...

  2. Spring 源码(12)Spring Bean 的创建过程(3)

    继续上一篇Spring Bean的创建过程的解读,上一篇介绍了Spring在创建过程中doGetBean方法,在执行过程中会调用getSingleton方法并且设置一个lambda表达式,这个lamb ...

  3. Spring 源码(13)Spring Bean 的创建过程(4)

    Spring Bean的创建过程非常的复杂,上一篇重点介绍了Spring在创建Bean的过程中,使用InstantiationBeanPostProcessor进行提前创建Bean,我们可以通过CGL ...

  4. spring bean的创建过程

    spring的核心容器包括:core.beans.context.express language四个模块.所以对于一个简单的spring工程,最基本的就是依赖以下三个jar包即可: <depe ...

  5. Spring 源码(9)Spring Bean的创建过程的前期准备

    回顾总结 到目前为止,Spring源码中AbstractApplicationContext#refresh方法的已经解读到第11个方法finishBeanFactoryInitialization, ...

  6. Spring 源码(10)Spring Bean 的创建过程(1)

    Spring Bean的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化,BeanDefinition元数据的冻结等操作,都是为了在创建Bean的过程中保证Bean的正确的创建 ...

  7. Spring 源码(17)Spring Bean的创建过程(8)Bean的初始化

    知识回顾 Bean的创建过程会经历getBean,doGetBean,createBean,doCreateBean,然后Bean的创建又会经历实例化,属性填充,初始化. 在实例化createInst ...

  8. Spring 源码(14)Spring Bean 的创建过程(6)对象的提前暴露

    知识回顾 解析完Bean信息的合并,可以知道Spring在实例化Bean之后,属性填充前,对Bean进行了Bean的合并操作,这里的操作主要做了对Bean对象标记了@Autowired.@Value. ...

  9. Spring 源码(14)Spring Bean 的创建过程(5)

    到目前为止,我们知道Spring创建Bean对象有5中方法,分别是: 使用FactoryBean的getObject方法创建 使用BeanPostProcessor的子接口InstantiationA ...

随机推荐

  1. Android 音视频深入 十五 FFmpeg 推流mp4文件(附源码下载)

    源码地址https://github.com/979451341/Rtmp 1.配置RTMP服务器 这个我不多说贴两个博客分别是在mac和windows环境上的,大家跟着弄 MAC搭建RTMP服务器h ...

  2. Spring MVC 复习笔记05

    1. 上传图片 1.1 springmvc中对多部件类型解析 在 页面form中提交enctype="multipart/form-data"的数据时,需要springmvc对mu ...

  3. 第一章02: 常用的DOS命令

    win+R=命令框 +输入CMD ,进入命令行.或者控制台 DOS命令如下: cd命令 1. CD.. = 返回上级目录 2. cd\ = 直接退到根目录 3.cd (地址)= 直接到指定文件 切盘符 ...

  4. Opencv undefined reference to `cv::imread() Ubuntu编译

    Ubuntu下编译一个C++文件,C++源程序中使用了opencv,opencv的安装没有问题,但是在编译的过程中出现如下错误: undefined reference to `cv::imread( ...

  5. javascript 跨域请求详细分析(终极跨域解决办法)

    自从我接触前端以来,接手的项目里面很大部分都是前后端分离的,后端只提供接口,前端根据后端接口渲染出实际页面.个人觉得这是一个挺好的模式,前后端各自负责各自的模块,分工明确,而且也给前端更大的发挥空间. ...

  6. Linux系统基本操作命令

    1.文件与文件夹(目录)操作命令 可以参考:http://www.runoob.com/linux/linux-command-manual.html 1)rm:删除命令 例:$  rm  -i  文 ...

  7. design

    type Config struct { Item lock } func (*Config) getItem(){ } func (*Config) SetItem(){ } channel : - ...

  8. VBA消息框

    MsgBox函数显示一个消息框,并等待用户点击一个按钮,然后根据用户点击该按钮的动作执行. 语法 MsgBox(prompt[,buttons][,title][,helpfile,context]) ...

  9. useradd语法2

    在Linux中 useradd 命令用来创建或更新用户信息. useradd 命令属于比较难用的命令 (low level utility for adding users),所以 Debian 系的 ...

  10. Curl追踪请求延时问题

    背景原因:测试环境发现一个连接内网访问和外网访问延迟差别很大,内网访问很快.外网访问很慢.于是我们用curl来诊断问题所在的区域! 命令如下: curl -o /dev/null -s -w %{ti ...