1. 前言
1.1. 范围
本文讲述MyBatis的源码,主要是针对在SpringBoot环境下使用MyBatis的讲解:
- SpringBoot版本: 2.1.9.RELEASE
- MyBatis版本: 3.4.6
- mybatis-spring版本: 1.3.2
1.2. 参考数据库表
Field | Type | Comment |
---|---|---|
id | bigint(20) NOT NULL | 主键 |
sku | varchar(50) NULL | sku |
price_pay | decimal(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行:
能看到proxy对象的值是:org.apache.ibatis.binding.MapperProxy@8a4dc8。
2.2.1 org.apache.ibatis.binding.MapperProxy
于是,找到org.apache.ibatis.binding.MapperProxy类,并在invoke函数中打一个断点:
可以看到,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初始化:
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);
}
上图展示了与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入口 :
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方法发起的调用链:
红框的部分意味着一个Bean的加载过程的开始,每个Bean加载过程的调用链是一样的,经过图中所显示的14次的函数调用,完成一个非抽象非懒加载的单例Bean的加载过程。