zoukankan      html  css  js  c++  java
  • 从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,初始化过程又会是怎么样的 怎么触发 有无规律可循
  • 相关阅读:
    CF280C Game on Tree 概率与期望
    bzoj 3420: Poi2013 Triumphal arch 树形dp+二分
    bzoj 2111: [ZJOI2010]Perm 排列计数 Lucas
    bzoj 3709: [PA2014]Bohater 贪心
    bzoj 1396/2865: 识别子串 后缀自动机+线段树
    【教程】如何搭建一个自己的网站
    C#单例设计模式
    C#双缓冲代码
    Hibernate的查询功能
    hibernate事务规范写法
  • 原文地址:https://www.cnblogs.com/lucare/p/8679127.html
Copyright © 2011-2022 走看看