1. 程式人生 > >Mybatis原始碼分析(3)—— 從Mybatis的視角去看Bean的初始化流程

Mybatis原始碼分析(3)—— 從Mybatis的視角去看Bean的初始化流程

不涉及Spring完整的啟動流程,僅僅從Mybatis的視角去分析幾個關鍵的方法,找到Mybatis是如何通過這幾個擴充套件點植入進去的,反過來看Spring是如何設計,埋下這些伏筆,實現其可擴充套件性。

springContext-mybatis.xml的配置:

<!-- simplest possible SqlSessionFactory configuration -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property
name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/mybatis-config.xml"></property> </bean> <!-- Scan for mappers and let them be autowired; notice there is no UserDaoImplementation needed. The required SqlSessionFactory will be autowired. -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.fcs.**.dao,fcs.common.**.dao" /> </bean>

一般情況下,要植入進去,必須通過介面實現,這也是Spring的擴充套件點。SqlSessionFactoryBean和MapperScannerConfigurer分別實現了這些介面:

public class SqlSessionFactoryBean implements
FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
} public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { } public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }

從AbstractApplicationContext的invokeBeanFactoryPostProcessors方法開始分析:

Map<String, BeanDefinitionRegistryPostProcessor> beanMap = beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans = new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());

OrderComparator.sort(registryPostProcessorBeans);
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
    postProcessor.postProcessBeanDefinitionRegistry(registry);
}

第一步:獲取指定型別(BeanDefinitionRegistryPostProcessor)的beanMap

DefaultListableBeanFactory#getBeansOfType:

public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
        throws BeansException {

    String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    Map<String, T> result = new LinkedHashMap<String, T>(beanNames.length);
    for (String beanName : beanNames) {
        try {
            result.put(beanName, getBean(beanName, type));
        }
        catch (BeanCreationException ex) {
            Throwable rootCause = ex.getMostSpecificCause();
            if (rootCause instanceof BeanCurrentlyInCreationException) {
                BeanCreationException bce = (BeanCreationException) rootCause;
                if (isCurrentlyInCreation(bce.getBeanName())) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Ignoring match to currently created bean '" + beanName + "': " +
                                ex.getMessage());
                    }
                    onSuppressedException(ex);
                    // Ignore: indicates a circular reference when autowiring constructors.
                    // We want to find matches other than the currently created bean itself.
                    continue;
                }
            }
            throw ex;
        }
    }
    return result;
}
  • String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);

獲取匹配型別的beanNames

  • result.put(beanName, getBean(beanName, type));

根據名稱和型別獲取bean,放到result集合中

接下來會走bean的建立流程,在AbstractAutowireCapableBeanFactory的doCreateBean方法中:

// Initialize the bean instance.
Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
}

這裡會呼叫MapperScannerConfigurer的afterPropertiesSet方法:

public void afterPropertiesSet() throws Exception {
    notNull(this.basePackage, "Property 'basePackage' is required");
}

第二步:執行postProcessor的postProcessBeanDefinitionRegistry方法

postProcessor.postProcessBeanDefinitionRegistry(registry);

這樣就會呼叫MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.registerFilters();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

這裡會開啟掃描mapper.xml,ClassPathMapperScanner繼承自Spring的ClassPathBeanDefinitionScanner,重寫了doScan方法:

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
      logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
    } else {
      for (BeanDefinitionHolder holder : beanDefinitions) {
        GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();

        if (logger.isDebugEnabled()) {
          logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() 
              + "' and '" + definition.getBeanClassName() + "' mapperInterface");
        }

        // the mapper interface is the original class of the bean
        // but, the actual class of the bean is MapperFactoryBean
        definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
        definition.setBeanClass(MapperFactoryBean.class);

        definition.getPropertyValues().add("addToConfig", this.addToConfig);

        // ......
      }
    }

    return beanDefinitions;
 }
  • Set beanDefinitions = super.doScan(basePackages);

呼叫父類的doScan方法構造每個Mapper的BeanDefinitionHolder,同service一樣。

definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
definition.setBeanClass(MapperFactoryBean.class);

definition.getPropertyValues().add("addToConfig", this.addToConfig);

往definition裡設定相關屬性,方便後面構造mapper代理類。

第三步:獲取指定型別的postProcessorNames(BeanFactoryPostProcessor)並處理

String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
    if (processedBeans.contains(ppName)) {
        // skip - already processed in first phase above
    }
    else if (isTypeMatch(ppName, PriorityOrdered.class)) {
        priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }
    else if (isTypeMatch(ppName, Ordered.class)) {
        orderedPostProcessorNames.add(ppName);
    }
    else {
        nonOrderedPostProcessorNames.add(ppName);
    }
}

// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
OrderComparator.sort(priorityOrderedPostProcessors);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

processedBeans集合包含之前兩個beanName:

0 = "org.mybatis.spring.mapper.MapperScannerConfigurer#0"
1 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"

postProcessorNames陣列包含三個beanName

0 = "propertyConfigurer"
1 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
2 = "org.mybatis.spring.mapper.MapperScannerConfigurer#0"

之前的兩個已經建立過了,現在處理剩下的”propertyConfigurer” 一個了。

根據類關係圖,自定義的propertyConfigurer剛好也實現了PriorityOrdered介面:

image

所以將會呼叫其postProcessBeanFactory方法:

private void invokeBeanFactoryPostProcessors(
        Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
    }
}

propertyConfigurer可以是我們自定義的XxPropertyPlaceholderConfigurer,繼承自PropertyPlaceholderConfigurer就行了。這裡也是一個切入點(關於dataSource的配置等)。

AbstractApplicationContext的registerBeanPostProcessors方法:

第四步:處理BeanPostProcessor相關

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

這裡找到7個類:

org.springframework.context.annotation.internalAutowiredAnnotationProcessor

org.springframework.context.annotation.internalRequiredAnnotationProcessor

org.springframework.context.annotation.internalCommonAnnotationProcessor

org.springframework.aop.config.internalAutoProxyCreator

&shiroFilter

lifecycleBeanPostProcessor

org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor

同處理BeanFactoryPostProcessor一樣,也是分為PriorityOrdered、Ordered和其他型別的順序分別獲取bean,然後呼叫其registerBeanPostProcessors方法註冊:

private void registerBeanPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

    for (BeanPostProcessor postProcessor : postProcessors) {
        beanFactory.addBeanPostProcessor(postProcessor);
    }
}

lifecycleBeanPostProcessor在shiroFilter之前初始化。

這裡重點看postProcessorNames中name為&shiroFilter。

在AbstractAutowireCapableBeanFactory的applyPropertyValues方法中找到了securityMannger屬性,然後又在安全管理器中帶出了realm屬性,接著又找到adminUserService屬性。

第五步:由一個Mapper的初始化引起所有Mapper的建立

這個的重點在於sqlSessionFactory這個屬性,中間是根據這個特殊的type去匹配所有的beandefine,adminUserService中有個@autowire註解的adminUserMapper:

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;
}

看了下AbstractAutowireCapableBeanFactory中的autowireByType方法:

protected void autowireByType(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // Don't try autowiring by type for type Object: never makes sense,
            // even if it technically is a unsatisfied, non-simple property.
            if (!Object.class.equals(pd.getPropertyType())) {
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // Do not allow eager init for type matching in case of a prioritized post-processor.
                boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
                                propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                autowiredBeanNames.clear();
            }
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}
  • String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);

此方法獲取了兩個屬性:

0 = "sqlSessionFactory"
1 = "sqlSessionTemplate"

MapperFactoryBean繼承了SqlSessionDaoSupport類:

public abstract class SqlSessionDaoSupport extends DaoSupport {

  private SqlSession sqlSession;

  private boolean externalSqlSession;

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
  }

  // ......

}

遍歷這兩個屬性名稱,對於sqlSessionFactory:

MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());

MethodParameter跟SqlSessionDaoSupport中的set方法有關,eager判斷也為true,接著:

Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);

public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
        return new DependencyObjectFactory(descriptor, beanName);
    }
    else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {
        return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
    }
    else {
        return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
    }
}

在doResolveDependency方法中:

Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

DefaultListableBeanFactory的findAutowireCandidates方法:

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());

在這個方法中傳入的還是adminUserMapper,要求的型別是SqlSessionFactory,還有個引數是DependencyDescriptor。

BeanFactoryUtils的beanNamesForTypeIncludingAncestors方法中:

String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);

然後在DefaultListableBeanFactory中getBeanNamesForType:

public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
    if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
        return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    }

    //......
}

doGetBeanNamesForType方法中遍歷所有beanDefinitionName並判斷是否匹配:

boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&
    (includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);

isTypeMatch方法中就會針對不同的beanName,與type為SqlSessionFactory做匹配:

if (FactoryBean.class.isAssignableFrom(beanType)) {
    if (!BeanFactoryUtils.isFactoryDereference(name)) {
        // If it's a FactoryBean, we want to look at what it creates, not the factory class.
        beanType = getTypeForFactoryBean(beanName, mbd);
        if (beanType == null) {
            return false;
        }
    }
}

beanType由於是MapperFactoryBean,就會獲取相關bean。

getTypeForFactoryBean方法到這裡也該終結了:

 FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);

這樣就開始建立一個個mapper了。

試想一下,就是有沒有這樣一種可能,當Spring在建立bean的過程中依賴了其他bean,它就會去處理其依賴(建立依賴物件),然後它根據某種情況判斷,將所有用到該屬性的bean一起都建立了,這樣就引起了所有Mapper物件的建立,合乎邏輯。

留下幾個問題:

  • 其他的屬性都是通過配置找到的 mapper是通過註解 如何處理這些差異
  • 如何牽一髮而動全身 引起200多個mapper的初始化
  • 如果沒有使用shiro,初始化過程又會是怎麼樣的 怎麼觸發 有無規律可循