MyBatis源码解析初步---一个常用的MyBatis的select执行过程的跟踪

1. 前言

1.1. 范围

本文讲述MyBatis的源码,主要是针对在SpringBoot环境下使用MyBatis的讲解:

  • SpringBoot版本: 2.1.9.RELEASE
  • MyBatis版本: 3.4.6
  • mybatis-spring版本: 1.3.2

1.2. 参考数据库表

FieldTypeComment
idbigint(20) NOT NULL主键
skuvarchar(50) NULLsku
price_paydecimal(20,6) NOT NULL支付价格

2. 一个常用的MyBatis的select执行过程的跟踪

2.1 业务代码展示

DAO层的核心代码如下:

   @Repository
   @Mapper
   public interface PriceChgDao {
       PriceChg selectByPrimaryKey(Long id);
   }

核心业务代码如下:

   @Service
   public class PriceServiceImpl implements PriceService {
   
       @Autowired
       private PriceChgDao priceChgDao;
   
       @Override
       @UseDataSource("price")
       public APIResponse<PriceChg> getPriceChg(Long id) {
           PriceChg priceChg = this.priceChgDao.selectByPrimaryKey(id);
           return APIResponse.successResp(priceChg);
       }
   }

2.2 一次数据查询过程跟踪

先跟踪一个MyBatis的数据查询过程。
  在上面的业务代码里调用DAO的地方打断点,step into进去,刚进去就是进入了spring封装的jdk动态AOP代理类,org.springframework.aop.framework.JdkDynamicAopProxy.java,看下面的截图,可以看到用的是spring-aop:5.1.10.RELEASE,我们Step Over相关代码,看210行:
wwimgurljdcpkug2020cn_200428000_JdkDynamicAopProxy_invoke.png
  能看到proxy对象的值是:org.apache.ibatis.binding.MapperProxy@8a4dc8。

2.2.1 org.apache.ibatis.binding.MapperProxy

于是,找到org.apache.ibatis.binding.MapperProxy类,并在invoke函数中打一个断点:
wwimgurljdcpkug2020cn_200428000_MapperProxy_invoke.png
  可以看到,mapperInterface的值是:“interface com.jd.dis.dao.PriceChgDao”,
  methodCache的定义如下:

   public class MapperProxy<T> implements InvocationHandler, Serializable {
       private final Map<Method, MapperMethod> methodCache;
   }

methodCache是一个Map接口,这里的实现类是java.util.concurrent.ConcurrentHashMap,当前大小是0,不难理解,它代表了DAO接口中的java方法,由cachedMapperMethod方法的实现可知,DAO接口中的java方法是懒加载的,第一次使用时Mapper中的方法才加载到JVM内存中。
  DAO接口中的java方法是由一个通用的类代理完成的,它是:org.apache.ibatis.binding.MapperMethod

   public class MapperProxy<T> implements InvocationHandler, Serializable {
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           try {
             // 判断接口方法是否有实现类 
             if (Object.class.equals(method.getDeclaringClass())) {
               // 如果有,调用实现类的方法
               return method.invoke(this, args);
             } else if (isDefaultMethod(method)) { // 判断接口是否有默认实现方法
               // 如果有,调用接口的默认实现方法
               return invokeDefaultMethod(proxy, method, args);
             }
           } catch (Throwable t) {
             throw ExceptionUtil.unwrapThrowable(t);
           }
           final MapperMethod mapperMethod = cachedMapperMethod(method);
           // 调用MapperMethod的execute方法
           return mapperMethod.execute(sqlSession, args);
         }
       
         private MapperMethod cachedMapperMethod(Method method) {
           MapperMethod mapperMethod = methodCache.get(method);
           if (mapperMethod == null) {
             mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
             methodCache.put(method, mapperMethod);
           }
           return mapperMethod;
         }
   }

继续断点的执行,会进入到MapperProxy类的invoke方法,然后会执行MapperMethod的execute方法来完成sql的执行。
  由此可以认为,一个MapperProxy对象是一个这样的东东:MyBatis的DAO接口类与相关的Mapper.xml文件里内容的合体,一次Mapper中接口方法的执行,由MapperProxy动态代理生成的MapperMethod来完成。
  在org.apache.ibatis.binding.MapperProxy的构造函数中打一个断点,然后重启程序,可以看到程序启动时能进入到构造方法里,可见MapperProxy是在使用了MyBatis的程序启动时进行初始化的,会给每个DAO初始化:
wwimgurljdcpkug2020cn_200428000_MapperProxy_Constructor.png

2.2.3 org.apache.ibatis.binding.MapperMethod

MyBatis最终执行sql是交线MapperMethod来完成的,代码如下:

   public class MapperMethod {
         public Object execute(SqlSession sqlSession, Object[] args) {
           Object result;
           switch (command.getType()) {
             case INSERT: {
             Object param = method.convertArgsToSqlCommandParam(args);
               result = rowCountResult(sqlSession.insert(command.getName(), param));
               break;
             }
             case UPDATE: {
               Object param = method.convertArgsToSqlCommandParam(args);
               result = rowCountResult(sqlSession.update(command.getName(), param));
               break;
             }
             case DELETE: {
               Object param = method.convertArgsToSqlCommandParam(args);
               result = rowCountResult(sqlSession.delete(command.getName(), param));
               break;
             }
             case SELECT:
               if (method.returnsVoid() && method.hasResultHandler()) {
                 executeWithResultHandler(sqlSession, args);
                 result = null;
               } else if (method.returnsMany()) {
                 result = executeForMany(sqlSession, args);
               } else if (method.returnsMap()) {
                 result = executeForMap(sqlSession, args);
               } else if (method.returnsCursor()) {
                 result = executeForCursor(sqlSession, args);
               } else {
                 Object param = method.convertArgsToSqlCommandParam(args);
                 result = sqlSession.selectOne(command.getName(), param);
               }
               break;
             case FLUSH:
               result = sqlSession.flushStatements();
               break;
             default:
               throw new BindingException("Unknown execution method for: " + command.getName());
           }
           if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
             throw new BindingException("Mapper method '" + command.getName() 
                 + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
           }
           return result;
         }
   }

这里没有使用某种策略模式,直接用了switch语句来处理不同的sql的执行或者MyBatis封装的flush操作,业务不算不复杂,可以接受,代码不难理解;
  select的情况稍微复杂点,根据查询返回的不同类型做了进一步的区分;
  MapperMethod类内部自定了三个公有的内部类,分别是:

  • public static class ParamMap extends HashMap<String, V>:对HashMap的get方法进行重写,使用了自定义异常;
  • public static class SqlCommand:封装了SQL标签的类型,insert、update、delete、select、flush;
  • public static class MethodSignature:方法签名,封装了接口当中方法的 参数类型 返回值类型 等信息;

2.3 扩展分析

2.3.1 org.springframework.beans.factory.FactoryBean

先看看基本的代码:

   public interface FactoryBean<T> {
       // 返回的对象实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中
       @Nullable
       T getObject() throws Exception;
       
       // 返回FactoryBean创建的bean类型
       @Nullable
       Class<?> getObjectType();
       
       // 返回由FactoryBean创建的bean实例的作用域是singleton还是prototype
       default boolean isSingleton() {
           return true;
       }
   }

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在配置文件中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案;
  通过FactoryBean的工厂类接口实现该接口定制实例化bean的逻辑;
  当实现了这个接口的Bean在配置为被Spring接管时,存入IOC容器中的实例类型将会是实例化泛型的那个类型,从IOC容器中获取时也是实例化泛型的那个类型。

2.3.2 org.mybatis.spring.mapper.MapperFactoryBean

2.3.2.1 MapperProxy的初始化的调用链

MapperProxy的初始化,最开始有spring容器发起,经过若干步骤后到了MyBatis这一块,由MapperFactoryBean来完成,调用链如下:

  newInstance:52, MapperProxyFactory (org.apache.ibatis.binding)  
  getMapper:50, MapperRegistry (org.apache.ibatis.binding)  
  getMapper:745, Configuration (org.apache.ibatis.session)  
  getMapper:318, SqlSessionTemplate (org.mybatis.spring)  
  getObject:95, MapperFactoryBean (org.mybatis.spring.mapper)  
  doGetObjectFromFactoryBean:171, FactoryBeanRegistrySupport (org.springframework.beans.factory.support)  
  getObjectFromFactoryBean:101, FactoryBeanRegistrySupport (org.springframework.beans.factory.support)  
  getObjectForBeanInstance:1645, AbstractBeanFactory (org.springframework.beans.factory.support)  
  getObjectForBeanInstance:1175, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)  
  doGetBean:327, AbstractBeanFactory (org.springframework.beans.factory.support)  
  getBean:199, AbstractBeanFactory (org.springframework.beans.factory.support)  

在org.mybatis.spring.mapper.MapperFactoryBean的第95行打上断点,然后分别向前追溯6个函数调用,向后跟踪个4函数调用;

   public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
         @Override
         public T getObject() throws Exception {
           return getSqlSession().getMapper(this.mapperInterface);
         }
   }

MapperFactoryBean继承SqlSessionDaoSupport,实现Spring中的FactoryBean,SqlSessionDaoSupport用于提供SqlSession。
  getSqlSession()会得到SqlSessionTemplate,再调用SqlSessionTemplate的getMapper方法:

   public class SqlSessionTemplate implements SqlSession, DisposableBean {
         @Override
         public <T> T getMapper(Class<T> type) {
           return getConfiguration().getMapper(type, this);
         }
   }

getConfiguration()会得到Configuration,再调用Configuration的getMapper方法:

   public class Configuration {
         public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
           return mapperRegistry.getMapper(type, sqlSession);
         }
   }

MapperRegistry基于HashMap实现了一个org.apache.ibatis.binding.MapperProxyFactory对象的内存缓存,再调用Configuration的getMapper方法:

   public class MapperRegistry {
       /**
          * @since 3.2.2
          */
       public void addMappers(String packageName, Class<?> superType) {
           ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
           resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
           Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
           for (Class<?> mapperClass : mapperSet) {
             addMapper(mapperClass);
           }
       }
       public <T> void addMapper(Class<T> type) {
           if (type.isInterface()) {
             if (hasMapper(type)) {
               throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
             }
             boolean loadCompleted = false;
             try {
               knownMappers.put(type, new MapperProxyFactory<T>(type));
               // It's important that the type is added before the parser is run
               // otherwise the binding may automatically be attempted by the
               // mapper parser. If the type is already known, it won't try.
               MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
               parser.parse();
               loadCompleted = true;
             } finally {
               if (!loadCompleted) {
                 knownMappers.remove(type);
               }
             }
           }
         }
       @SuppressWarnings("unchecked")
       public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
           final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
           if (mapperProxyFactory == null) {
             throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
           }
           try {
             return mapperProxyFactory.newInstance(sqlSession);
           } catch (Exception e) {
             throw new BindingException("Error getting mapper instance. Cause: " + e, e);
           }
       }
   }

从缓存中取出MapperProxyFactory对象后,再调用MapperProxyFactory对象的newInstance方法:

   public class MapperProxyFactory<T> {
         public T newInstance(SqlSession sqlSession) {
           final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
           return newInstance(mapperProxy);
         }
   }

直接调用MapperProxy的构造方法,新建MapperProxy对象并返回;

2.3.2.2 MapperRegistry的knownMappers对象初始化的调用链

可以看到,调用MapperRegistry的getMapper方法,它是直接从knownMappers获取指定接口类的MapperProxy对象,可以认为它们在此之前已经加载到内存中了。
  knownMappers的定义如下:

   public class MapperRegistry {
         private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
   }

究竟是在什么时候加载的内存中的呢,经过查找,也是一个很复杂的过程,追溯MapperRegistry类的addMapper的调用过程,在org.mybatis.spring.SqlSessionFactoryBean类的afterPropertiesSet方法入口(第375行)打上断点,然后分别向前追溯7个函数调用,向后跟踪个4函数调用;

   public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
         @Override
         public void afterPropertiesSet() throws Exception {
           notNull(dataSource, "Property 'dataSource' is required");
           notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
           state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
                     "Property 'configuration' and 'configLocation' can not specified with together");
       
           this.sqlSessionFactory = buildSqlSessionFactory();
         }
   }

进行跟踪:调用链如下:

  addMapper:741, Configuration (org.apache.ibatis.session)  
  bindMapperForNamespace:413, XMLMapperBuilder (org.apache.ibatis.builder.xml)  
  parse:94, XMLMapperBuilder (org.apache.ibatis.builder.xml)  
  buildSqlSessionFactory:521, SqlSessionFactoryBean (org.mybatis.spring)  
  afterPropertiesSet:380, SqlSessionFactoryBean (org.mybatis.spring)  
  getObject:547, SqlSessionFactoryBean (org.mybatis.spring)  
  sqlSessionFactory:153, MybatisAutoConfiguration (org.mybatis.spring.boot.autoconfigure)  
  CGLIB$sqlSessionFactory$2:-1, MybatisAutoConfiguration$$EnhancerBySpringCGLIB$$ba3c5065 (org.mybatis.spring.boot.autoconfigure)  
  invoke:-1, MybatisAutoConfiguration$$EnhancerBySpringCGLIB$$ba3c5065$$FastClassBySpringCGLIB$$faede857 (org.mybatis.spring.boot.autoconfigure)  
  invokeSuper:228, MethodProxy (org.springframework.cglib.proxy)  
  intercept:361, ConfigurationClassEnhancer$BeanMethodInterceptor (org.springframework.context.annotation)  
  sqlSessionFactory:-1, MybatisAutoConfiguration$$EnhancerBySpringCGLIB$$ba3c5065 (org.mybatis.spring.boot.autoconfigure)  

这个过程比较好理解,就不展开讲述了。

2.3.3 org.mybatis.spring.SqlSessionFactoryBean

先看看基本的代码:

   public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
         @Override
         public SqlSessionFactory getObject() throws Exception {
           if (this.sqlSessionFactory == null) {
             afterPropertiesSet();
           }
       
           return this.sqlSessionFactory;
         }
       
         @Override
         public void afterPropertiesSet() throws Exception {
           notNull(dataSource, "Property 'dataSource' is required");
           notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
           state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
                     "Property 'configuration' and 'configLocation' can not specified with together");
       
           this.sqlSessionFactory = buildSqlSessionFactory();
         }
       
       protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
           // ......
       }
   }

MybatisAutoConfiguration会通过创建SqlSessionFactoryBean再调用其getObject()创建SqlSessionFactory对象,并注入SqlSessionFactory对象到IOC容器中,IOC容器中的其他类型的对象就可以通过SqlSessionFactory拿到SqlSession实例,执行sql语句。

2.3.4 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

使用@Bean注解,在IOC容器里注入了两个类:SqlSessionFactory、SqlSessionTemplate,核心代码如下:

       @org.springframework.context.annotation.Configuration
       @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
       @ConditionalOnBean(DataSource.class)
       @EnableConfigurationProperties(MybatisProperties.class)
       @AutoConfigureAfter(DataSourceAutoConfiguration.class)
       public class MybatisAutoConfiguration {
         @Bean
         @ConditionalOnMissingBean
         public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
           SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
           factory.setDataSource(dataSource);
           factory.setVfs(SpringBootVFS.class);
           if (StringUtils.hasText(this.properties.getConfigLocation())) {
             factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
           }
           Configuration configuration = this.properties.getConfiguration();
           if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
             configuration = new Configuration();
           }
           if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
             for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
               customizer.customize(configuration);
             }
           }
           factory.setConfiguration(configuration);
           if (this.properties.getConfigurationProperties() != null) {
             factory.setConfigurationProperties(this.properties.getConfigurationProperties());
           }
           if (!ObjectUtils.isEmpty(this.interceptors)) {
             factory.setPlugins(this.interceptors);
           }
           if (this.databaseIdProvider != null) {
             factory.setDatabaseIdProvider(this.databaseIdProvider);
           }
           if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
             factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
           }
           if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
             factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
           }
           if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
             factory.setMapperLocations(this.properties.resolveMapperLocations());
           }
       
           return factory.getObject();
         }

         @Bean
         @ConditionalOnMissingBean
         public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
           ExecutorType executorType = this.properties.getExecutorType();
           if (executorType != null) {
             return new SqlSessionTemplate(sqlSessionFactory, executorType);
           } else {
             return new SqlSessionTemplate(sqlSessionFactory);
           }
         }
   }

先看MybatisAutoConfiguration头部有哪些注解:

  • @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }):当前classpath路径下面是否存在SqlSessionFactory.class, SqlSessionFactoryBean.class这两个类,存在则将当前配置装载到spring容器中;
  • @ConditionalOnBean(DataSource.class):在当前上下文中有DataSource实例的时候才将当前配置装载到spring容器中;
  • @AutoConfigureAfter(DataSourceAutoConfiguration.class):这个配置装载在DataSourceAutoConfiguration配置装载之后;
      再看看MybatisAutoConfiguration中的SqlSessionFactory的Bean构造基本的代码,前面是给SqlSessionFactoryBean设置一些属性方法;
      最后一个设置(factory.setMapperLocations)是扫描所配置的mapper路径下的所有mapper.xml文件信息到SqlSessionFactoryBean对象的MapperLocations属性里,此时还没有解析mapper.xml;
      最后一行是调用SqlSessionFactoryBean的返回的对象实例方法。

3. Spring AOP

这里简单讲一下mybatis-spring中涉及到的Spring AOP:

3.1 org.springframework.aop.framework.AopProxy

AopProxy接口有两个方法:

       public interface AopProxy {
          /**
           * 使用默认的类加载器生成代理对象,默认的类加载器通常是当前线程的上下文类加载器,可通过Thread#getContextClassLoader()获得
           */
          Object getProxy();

          /**
           * 使用指定的类加载器生成代理对象
           */
          Object getProxy(ClassLoader classLoader);
       }  

wwimgurljdcpkug2020cn_200428000_AopProxy.png
  上图展示了与AopProxy相关的几个类之间的关系。

3.2 org.springframework.aop.framework.JdkDynamicAopProxy

       final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
           @Override
           public Object getProxy() {
               return getProxy(ClassUtils.getDefaultClassLoader());
           }
           
           @Override
           public Object getProxy(@Nullable ClassLoader classLoader) {
               //......
               //获取代理对象需要实现的所有接口
               Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
               findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
               //通过JDK生成代理对象,第一个ClassLoader代表创建类的类加载器,第二个表示需要被代理的目标对象的接口,第三个参数InvocationHandler叫做调用处理器,在这里它就是对象本身,调用的代理对象方法实际就是调用InvocationHandler接口中的invoke方法。
               return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
           }

           @Override
           @Nullable
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               Object oldProxy = null;
               boolean setProxyContext = false;
           
               TargetSource targetSource = this.advised.targetSource;
               Object target = null;
           
               try {
                   //......
                   Object retVal;
                   //......
           
                   target = targetSource.getTarget();
                   // 得到被代理对象的类名
                   Class<?> targetClass = (target != null ? target.getClass() : null);
           
                   // 根据被代理类名和方法名得到拦截链
                   List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
           
                   //如果拦截链为空,则直接反射调用被代理方法
                   if (chain.isEmpty()) { 
                       Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                       retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                   }
                   else {
                       // 若拦截链不为空,创建代理方法
                       MethodInvocation invocation = // MethodInvocation是对象完成对AOP功能实现的封装    
                               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 
                       // 执行拦截链和被代理方法
                       retVal = invocation.proceed();
                   }
           
                   // 省略“返回值处理”

                   return retVal;
               }
               finally {
                   //......
               }
           }
       }  

3.3 org.springframework.beans.factory.InitializingBean

InitializingBean接口为bean提供初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

4. Spring启动的关键过程简析

SpringBoot启动流程实例化Bean入口 :
wwimgurljdcpkug2020cn_200428000_SpringBootLaunch_InstantiateBean.png

4.1 org.springframework.beans.factory.support.DefaultListableBeanFactory

下面讲一下DefaultListableBeanFactory类的preInstantiateSingletons方法,先看源码:

       @SuppressWarnings("serial")
       public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
               implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
           @Override
           public void preInstantiateSingletons() throws BeansException {
               if (logger.isTraceEnabled()) {
                   logger.trace("Pre-instantiating singletons in " + this);
               }
       
               // 得到所有beanName
               List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
       
               // 遍历所有beanName,初始化所有非懒加载的单例Bean
               for (String beanName : beanNames) {
                   // 根据BeanName得到BeanDefinition
                   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                   // 如果不是抽象的,是单例,不是懒加载
                   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                       // 如果是FactoryBean
                       if (isFactoryBean(beanName)) {
                           Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                           if (bean instanceof FactoryBean) {
                               final FactoryBean<?> factory = (FactoryBean<?>) bean;
                               boolean isEagerInit;
                               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                                   isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                   ((SmartFactoryBean<?>) factory)::isEagerInit,
                                           getAccessControlContext());
                               }
                               else {
                                   isEagerInit = (factory instanceof SmartFactoryBean &&
                                           ((SmartFactoryBean<?>) factory).isEagerInit());
                               }
                               if (isEagerInit) {
                                   getBean(beanName);
                               }
                           }
                       }
                       // 如果不是FactoryBean
                       else {
                           getBean(beanName);
                       }
                   }
               }
       
               // 触发所有Bean的后期初始化(post-initialization)回调方法
               for (String beanName : beanNames) {
                   Object singletonInstance = getSingleton(beanName);
                   if (singletonInstance instanceof SmartInitializingSingleton) {
                       final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                       if (System.getSecurityManager() != null) {
                           AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                               smartSingleton.afterSingletonsInstantiated();
                               return null;
                           }, getAccessControlContext());
                       }
                       else {
                           smartSingleton.afterSingletonsInstantiated();
                       }
                   }
               }
           }
       }  

这个方法会初始化几乎Spring项目所需要的所有Bean,上面谈到的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration,也是在这个过程中初始化的,我们看一下由DefaultListableBeanFactory类的preInstantiateSingletons方法发起的调用链:
wwimgurljdcpkug2020cn_200428000_SpringBootLaunch_InstantiateChain.png
  红框的部分意味着一个Bean的加载过程的开始,每个Bean加载过程的调用链是一样的,经过图中所显示的14次的函数调用,完成一个非抽象非懒加载的单例Bean的加载过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值