从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接口:
所以将会调用其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,初始化过程又会是怎么样的 怎么触发 有无规律可循