Spring's getBean method source code analysis

Spring's getBean method source code analysis

TSMYK Java technology programming
text will introduce the following areas

  1. FactoryBean interface
  2. BeanFactory interface
  3. The difference between BeanFactory interface and FactoryBean interface
  4. Source code analysis of getBean method
  5. Spring cyclic dependency solution

    related articles

Source code analysis of bean registration in
Spring Spring bean creation process source code analysis
Spring AOP function use detailed
Spring AOP annotation method source code analysis
Spring AOP creation proxy source code analysis
Spring transaction use detailed
Spring transaction initialization source code analysis
Spring transaction commit and rollback Source code analysis

Preface

In the article Spring source code analysis of bean registration and Spring bean creation process source code analysis understands the bean registration and creation process. What happens when the corresponding bean is obtained through the getBean method?

Let's take a look at the internal implementation of the getBean method. Before entering the getBean method, let's take a look at the FactoryBean interface, because the implementation class of this interface will be processed separately inside the getBean method.

FactoryBean

This interface is very similar to the BeanFactory interface, but its function is completely different. Let’s take a look at the definition of the javadoc document. The general meaning is: if a bean implements this interface, when the bean is obtained through the getBean method, it does not return itself. Instead, it returns the return value of its getObject() method; in addition, FactoryBeans can support singletons and prototypes modes. Its source code is as follows, with only three methods:


public interface FactoryBean<T> {
    // 返回 bean 的实例,即调用 getBean 方法获取到的实例就是该方法的返回值 
    T getObject() throws Exception;

    // 返回 bean 的类型
    Class<?> getObjectType();

    // 该 bean 是否是单例模式
    boolean isSingleton();
}

So what is the use of this FactoryBean interface? Through the source code analysis of the Spring bean creation process, it is known that the instantiation of the bean is achieved using reflection and CGLIB. However, in some cases, the process of instantiating the bean is more complicated. If you follow the traditional way, you need to configure it in the configuration file <bean> Provides a lot of configuration information. The flexibility of the configuration method is limited. At this time, a simple scheme may be obtained by using the coding method. Therefore, the user can customize the logic of instantiating the bean by implementing this interface.

chestnut

Let's look at a chestnut first. Now there is a User object. The traditional way is configured as follows in the configuration file:


public class User {

    private String name;
    private int age;
    private int sex;
    private double money;
    private String job;

    // setter / getter / toString
}
<bean id="user" class="main.tsmyk.pojo.User">
    <property name="name" value="zhangsan"/>
    <property name="age" value="20"/>
    <property name="job" value="java"/>
    <property name="money" value="10000"/>
    <property name="sex" value="1"/>
</bean>

test:


ApplicationContext context = new ClassPathXmlApplicationContext("myspring.xml");
User user = (User) context.getBean("user");
System.out.println(user);
结果:User{name='zhangsan', age=20, sex=1, money=10000.0, job='java'}

From the printed result, you can see that the attributes of the User object are all attached with values

However, if the User object has a lot of properties and you don't want to write a lot of <property> tags, you can implement it through the FactoryBean interface. Inside the interface, the properties of the User object are parsed and assigned according to certain rules. As follows:


public class UserFactoryBean implements FactoryBean<User> {

    private String user;

    @Override
    public User getObject() throws Exception {
        User user = new User();
        String[] userInfos = this.user.split(";");
        user.setName(userInfos[0]);
        user.setAge(Integer.parseInt(userInfos[1]));
        user.setJob(userInfos[2]);
        user.setMoney(Double.parseDouble(userInfos[3]));
        user.setSex(Integer.parseInt(userInfos[4]));
        return user;
    }

    @Override
    public Class<User> getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
}

In the getObject method of this class, the properties of the User object are parsed and assigned. When the bean is obtained through the getBean method, the User object returned by the getObject method is obtained. The configuration is as follows:


<bean id="userFactory" class="main.tsmyk.beans.UserFactoryBean">
    <property name="user" value="zhangsan;20;java;10000;1"/>
</bean>

test:


ApplicationContext context = new ClassPathXmlApplicationContext("myspring.xml");
User user1 = (User) context.getBean("userFactory");
System.out.println(user1);
结果:User{name='zhangsan', age=20, sex=1, money=10000.0, job='java'}

It can be seen that it is the same as the traditional method above. It is also verified that the getBean method obtains the return value of the getObject method, not the FactoryBean instance itself; however, if you want to obtain the FactoryBean instance itself, it is also possible, just add the & symbol before the bean name, that is getBean("&userFactory")

test:


ApplicationContext context = new ClassPathXmlApplicationContext("myspring.xml");
UserFactoryBean userBean = (UserFactoryBean) context.getBean("&userFactory");
System.out.println(userBean.getUser());

结果:zhangsan;20;java;10000;1

Knocking on the blackboard: So, when getting an instance through the getBean(String beanName) method, the beanName may start with &. If the beanName starts with &, it means that the FactoryBean interface is being processed

Spring itself also provides many implementations of the FactoryBean interface, such as the JndiObjectFactoryBean class:


public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean<Object>, BeanFactoryAware, BeanClassLoaderAware {
    private Object jndiObject;
    // 其他复杂的计算,为 jndiObject 赋值
    @Override
    public Object getObject() {
        return this.jndiObject;
    }
}

The well-known third-party ORM framework Mybatis also provides an implementation of this interface SqlSessionFactoryBean:


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    // 其他配置
</bean>
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
  private SqlSessionFactory sqlSessionFactory;
  @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }
  // 其他方法
}

So when you get through the getBean method, you get SqlSessionFactory instead of SqlSessionFactoryBean

BeanFactory

Now let’s take a look at an interface BeanFactory that is very similar to FactoryBean. BeanFactory is the core interface of the Spring IOC container. It defines the main functions of the container, such as creating beans, obtaining beans, etc. It is used to manage beans, that is, it is Used to instantiate, locate, configure objects in the application and establish dependencies between these objects. Its source code is as follows:


public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch);
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}

You can see that the basic functions of the container are defined. Note that it has an attribute FACTORY_BEAN_PREFIX = "&" which is the prefix used to represent the beanName of the FactoryBean interface.

to sum up

At this point, you can see from the source code, although FactoryBean and BeanFactory are very similar, but their roles are completely different.
FactoryBean can be regarded as a factory, and use it to create some complex beans.
BeanFactory defines the basic functions of the Spring container. Subclass to achieve, used to manage beans

getBean method

User user = (User) beanFactory.getBean("user");


    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }

Next, look at the doGetBean method, which is a bit complicated:


protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly){
    // 提取对应的 beanName,处理别名和FactoryBean接口的实现类,即 beanName 以 & 开头
    final String beanName = transformedBeanName(name);
    Object bean;
    // 尝试从缓存中或者ObjectFactory中获取
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("......");
        }
        // 这里主要处理 FactoryBean,有时候并不是返回实例本身,而是返回指定方法返回的实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    // 缓存中不存在该bean的实例
    else {
        // 这里bean的作用域是原型模式,且存在循环依赖,出现循环依赖,则抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 如果当前的的beanDefinitionMap即配置文件不包含该bean,则从parentBeanFactory 中查找
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                // 这个 args 是 getBean(beanName, args...) 方法传入的
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        // 如果不仅仅是做类型检查,则是创建bean,则进行标记,标记该bean以创建
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }
        // 将配置文件中GenericBeanDefinition转换为RootBeanDefinition,如果beanName是子bean的话,会合并父类的属性
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);

        // 处理依赖,如果存在依赖,则递归实例化依赖的bean
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
            for (String dep : dependsOn) {
                if (isDependent(beanName, dep)) {
                        throw new BeanCreationException("........");
                }
                registerDependentBean(dep, beanName);
                getBean(dep);
            }
        }
        //实例化 bean
        if (mbd.isSingleton()) {
            // 实例化单例的bean
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {                   
                    return createBean(beanName, mbd, args);
                });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        else if (mbd.isPrototype()) {
            // 实例化原型的bean
            Object prototypeInstance = null;
            try {
                beforePrototypeCreation(beanName);
                prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
                afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }
        else {
            // 指定的 score 上实例化bean
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    beforePrototypeCreation(beanName);
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    });
                bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
            }
        }
    }
    // 处理参数类型的转换
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        return getTypeConverter().convertIfNecessary(bean, requiredType);
    }
    return (T) bean;
}

As can be seen from the above code, the process of the doGetBean method is very clear, and each step is processed by the corresponding method. Its process is mainly as follows:

  1. When dealing with beanName, why do you want to deal with beanName, because beans can have aliases, and when the FactoryBean interface is introduced above, when obtaining the bean, the & prefix needs to be added, so the & should be removed here.

  2. Try to load the bean from the cache, because the singleton bean will only be loaded once. If the bean does not exist in the cache, it will try to load the bean from singletonFactories. What is this singletonFactories? In the source code analysis of the Spring bean creation process, it is known that there may be dependency injection when the bean is created. When creating a dependent bean, in order to avoid circular dependencies, when the bean is created, it will not wait until the bean creation is completed. Put the ObjectFactory that created the bean in the singletonFactories cache. Once the next bean is created, you need to rely on the previous bean to get the ObjectFactory directly from the singletonFactories cache to create it.

For example, A depends on B, and A --> B. Now create an instance beanA of A. During the creation process, put the ObjectFactory created by A in the singletonFactories cache. Now that A depends on B, you must create an instance beanB of B. , BeanA will continue to be created after beanB is created;
if it is found that B also depends on A, B --> A, then when beanB is created, beanA will also be created first, because before the creation of A instance beanA , The ObjectFactory of A has been put into the cache, now you can just go to the cache to take out the ObjectFactory. Just imagine, if you didn’t put the ObjectFactory of A in the cache beforehand, then when creating B, create A first , When A is found to depend on B, then B will be created again, which will cause a circular dependency and instantiation will fail.

So Spring uses this method to solve the circular dependency between beans, but it only deals with singleton circular dependencies, prototypes or other exceptions will be thrown

3. Create bean
3.1 Find bean from parent class
3.2 Convert GenericBeanDefinition to RootBeanDefinition, because when loading bean from configuration file, it is saved in GenericBeanDefinition mode.
3.3 Processing dependency
3.4 Create singleton bean
3.5 Create prototype bean
3.6 Create other score
3.7 Parameter type conversion of the bean acting on

4. Processing the bean of the FactoryBean interface

Whether the process is very clear, it will be clearer through the flowchart:
Spring's getBean method source code analysis

Let's take a look at each part.

1. Extract beanName

When obtaining a bean through the getBean method, the name of the bean can start with &, that is, the FactoryBean instance itself is obtained. In addition, the bean has aliases, and a bean can have multiple aliases, etc., so the name of the bean must be extracted first. , The method transformedBeanName:


final String beanName = transformedBeanName(name);

protected String transformedBeanName(String name) {
    String beanName = BeanFactoryUtils.transformedBeanName(name);
    return canonicalName(beanName);
}

// 使用工具类 BeanFactoryUtils 来转名字
public static String transformedBeanName(String name) {
    String beanName = name;
    // 如果 beanName 以 & 开头,则去掉 &
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    // 返回去掉 & 后的 beanName
    return beanName;
}

// 返回原始的bean的名字,解决别名
public String canonicalName(String name) {
    String canonicalName = name;
    String resolvedName;
    // while 循环,因为 bean 的别名可以有多个
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

2. Try to get the bean instance from the cache


Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    // 处理 FactoryBean
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

// 获取 bean
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从缓存中获取bean,该缓存singletonObjects用来存放已经创建完毕的bean的实例
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果缓存中没有,且该 bean 正在创建
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) { 
            // 从正在创建bean的缓存中获取,该 earlySingletonObjects 缓存是用来存放正在创建且还没有创建完毕的bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果此时还是获取不到实例,且允许从ObjectFactory中获取,解决循环引用
            if (singletonObject == null && allowEarlyReference) {
                // 从 ObjectFactory 中获取对应的工厂,使用工厂创建创建对象,因为之前在创建该bean的时候且还没有创建完毕的时候,已经把该bean的 ObjectFactory 放入到缓存中
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                // 获取到工厂之后,进行创建bean的实例,并放入到对应的缓存中
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    // 如果缓存中没有,且该bean没有正在创建,则直接返回 nul
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

In this method, we will try to solve the circular dependency. This method will involve three map type caches:

  1. Cache singletonObjects is used to store bean instances that have been created
  2. The cache earlySingletonObjects is used to store beans that are being created and have not yet been created
  3. The cached ObjectFactory is used to store the corresponding factory, because the bean’s ObjectFactory has been placed in the cache when the bean was created before and before the creation is complete,
    so the main logic of the above method is to get the instance from singletonObjects first, if If it cannot be obtained, the bean has not been created; if it cannot be obtained, it means the bean is not being created, and then obtain the corresponding factory from the ObjectFactory to create it. If it still cannot be obtained at the end, it returns null

3. Processing FactoryBean

After obtaining the bean instance, you need to process methods such as FactoryBean and factory-method. After obtaining the bean instance from different scores, the method will be executed:


protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

    // 如果 bean 的实例不是 FactoryBean 类型,即是一般的 bean ,可以直接返回
    // 如果 beanName 是以 & 开头,则也直接返回,因为 beanName 以 & 开头,表示返回工厂实例本身
    // BeanFactoryUtils.isFactoryDereference : name != null && name.startsWith("&")
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd == null) {
        // 尝试从 FactoryBean 缓存中获取bean
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // 到这里,已经明确了 bean的实例一定是 FactoryBean 类型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}
// 通过 FactoryBean 来获取 bean 实例
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 忽略了其他代码
    // doGetObjectFromFactoryBean -> factory.getObject(),返回的是 FactoryBean 的 getObject 方法的返回值
    object = doGetObjectFromFactoryBean(factory, beanName);
    return object;
}

4. Create the bean

After the above steps, if there is no instance from the cache, the bean will be instantiated. Before creation, if the bean has dependent beans, the dependent beans will be processed first:

4.1 Dealing with dependent beans


String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException("循环依赖异常");
        }
        // 注册循环依赖
        registerDependentBean(dep, beanName);
        // 创建依赖的 bean
        getBean(dep); // return doGetBean(name);
    }
}

4.2 Create bean


if (mbd.isSingleton()) {
    // 创建单例的bean
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            return createBean(beanName, mbd, args);
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
    // 创建原型的bean 
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
    // 创建其他score的bean
    String scopeName = mbd.getScope();
    final Scope scope = this.scopes.get(scopeName);
    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
        public Object getObject() throws BeansException {
        beforePrototypeCreation(beanName);
        try {
            return createBean(beanName, mbd, args);
        }
        finally {
            afterPrototypeCreation(beanName);
        });
        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}

The creation of singleton beans and beans of other scores can refer to the createBean method of Spring bean creation process source code analysis.

Let's take a look at the process of creating a prototype bean:


protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    RootBeanDefinition mbdToUse = mbd;
    // 解析 class 
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // 处理 lookup-method 和 replace-method 属性,在 “Spring 中 bean 注册的源码解析“ 从已经解析过
    mbdToUse.prepareMethodOverrides();
    // 在该方法里面会执行前置处理器和后置处理器
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    // 如果应用前置处理和后置处理器改变了bean,就直接返回,AOP功能就在此实现
    if (bean != null) {
        return bean;
    }
    // 正真创建bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

// 应用前置处理器和后置处理器
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    Class<?> targetType = determineTargetType(beanName, mbd);
    if (targetType != null) {
        // 前置处理器
        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        if (bean != null) {
            // 后置处理器 
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
    }
    // 省略其他代码
    return bean;
}

// 前置处理器
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}
// 后置处理器
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

5. Type conversion

After the above steps, you will get a bean instance, no matter if the bean is singleton, prototype, or other score, in short, we have got the bean instance here. After getting the instance, we need to proceed Type conversion, that is, if the bean is a String, but the requiredType is Integer, then type conversion is required.


if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
    return getTypeConverter().convertIfNecessary(bean, requiredType);
}

// 获取类型转换器
public TypeConverter getTypeConverter() {
    TypeConverter customConverter = getCustomTypeConverter();
    if (customConverter != null) {
        return customConverter;
    }
    else {
        SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        typeConverter.setConversionService(getConversionService());
        registerCustomEditors(typeConverter);
        return typeConverter;
    }
}

// 类型的转换
public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field){
    return doConvert(value, requiredType, null, field);
}

private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field){
    if (field != null) {
        return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
    }
    else {
        return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
    }
}

// 正真类型的转换
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
    Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
    // 自定义转换器
    PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
    ConversionFailedException conversionAttemptEx = null;
    ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
    if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) 
    {
        TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
        if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
            return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
        }
     }
   }
   // 省略其他代码
    if (requiredType != null) {
    if (convertedValue != null) {
        // 类型为 class
        if (Object.class == requiredType) {
            return (T) convertedValue;
        }
        // 类型为数组
        else if (requiredType.isArray()) {
            if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
            }
            return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
        }
        // 类型为集合
        else if (convertedValue instanceof Collection) {
            convertedValue = convertToTypedCollection((Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
            standardConversion = true;
        }
        // 类型为 map
        else if (convertedValue instanceof Map) {
            convertedValue = convertToTypedMap( (Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
            standardConversion = true;
        }
        if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
            convertedValue = Array.get(convertedValue, 0);
            standardConversion = true;
        }
        // String
        if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
            return (T) convertedValue.toString();
        }
        // String
        else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
            if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                Constructor<T> strCtor = requiredType.getConstructor(String.class);
                return BeanUtils.instantiateClass(strCtor, convertedValue);
            }
            String trimmedValue = ((String) convertedValue).trim();
            if (requiredType.isEnum() && "".equals(trimmedValue)) {
                return null;
            }
            convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
            standardConversion = true;
        }
        // number
        else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
            convertedValue = NumberUtils.convertNumberToTargetClass(
                    (Number) convertedValue, (Class<Number>) requiredType);
            standardConversion = true;
        }
    }
    else {
        if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
            convertedValue = javaUtilOptionalEmpty;
        }
    }
    // 省略其他代码
    return (T) convertedValue;
}

At this point, a correct bean can be obtained through getBean.

The above is the logic of the getBean method, mainly you need to know that you can also create a bean through FactoryBean, and the beanName can also start with &.

Guess you like

Origin blog.51cto.com/15077536/2608557