2020-08-22_MapperScan源码分析1
MapperScan源码分析1
1 MapperScan****源码概述
Mapperscan(内置MapperFactoryBean)注解导入了MapperScannerRegistrar,MapperScannerRegistrar实现 ImportBeanDefinitionRegistrar。
通过实现registerBeanDefinitions方法,获取需要扫描的包遍历得到BeanDefinition列表,并交给Spring ioc容器管理
1.1 MapperScan注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
图 1 MapperScannerRegistrar
1.2启动入口
从注解配置应用上下文开始。
ApplicationContext annotationConfigWebApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
((DefaultListableBeanFactory) this).singletonObjects
((DefaultListableBeanFactory) ((DefaultListableBeanFactory) this)).earlySingletonObjects
((DefaultListableBeanFactory) ((DefaultListableBeanFactory) ((DefaultListableBeanFactory) ((DefaultListableBeanFactory) this)))).beanDefinitionMap
((DefaultListableBeanFactory) ((DefaultListableBeanFactory) ((DefaultListableBeanFactory) ((DefaultListableBeanFactory) ((DefaultListableBeanFactory) this))))).beanDefinitionNames
1.2.1 AnnotationConfigApplicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
1.2.2 refresh_****invokeBeanFactoryPostProcessors
完成beanDefinitionMap,beanDefinitionNames的属性设置。
org.springframework.context.support.AbstractApplicationContext
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor)
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
image.png
图 2 configClasses
最终扫描到的BeanDefinitons都放在了BeanDefinitionRegistry:DefaultListableBeanFactory的BeanDefinitonMap中。
((DefaultListableBeanFactory)registry).beanDefinitionNames
((DefaultListableBeanFactory)registry).beanDefinitionMap
image.png图 3 beanDefinitionMap_put
1.2.3执行****MapperScannerRegistrar
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry));
}
1.2.3.1 registerBeanDefinitions
// class org.springframework.core.type.StandardAnnotationMetadata
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 1.获取注解信息
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
// 2.ClassPath扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// 3.获取需要扫描的包
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 4.过滤
scanner.registerFilters();
// 5.扫描并注册为beanDefinition
scanner.doScan(StringUtils.toStringArray(basePackages));
}
image.png
图 4 AnnotationAttributes对象注解信息
image.png图 5 获取com.kikop.mybatislinkspringend.mycompoentstudy.mapper
image.png图 6 得到根目录下的所有.class
image.png图 7 得到指定目录下.class
image.png图 8 BeanFactory
1.2.4 refresh_finishBeanFactoryInitialization
完成
((DefaultListableBeanFactory) ((DefaultListableBeanFactory)beanFactory)).dependenciesForBeanMap的注入。
org.springframework.context.support.AbstractApplicationContext
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor)
// Instantiate all remaining (non-lazy-init) singletons.
// 完成dependenciesForBeanMap的注入
finishBeanFactoryInitialization(beanFactory);
image.png
图 9 beanFactory
同时在finishBeanFactoryInitialization,遍历BeanName,进行preInstantiateSingletons的创建
// 最终会调用 MapperFactoryBean中的checkDaoConfig,将
configuration.addMapper(this.mapperInterface); 加入Configuration:
knownMappers.put(type, new MapperProxyFactory<T>(type));
org.springframework.beans.factory.support.DefaultListableBeanFactory
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
1.2.4.1 invokeInitMethods
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
>invokeInitMethods(beanName, wrappedBean, mbd);
>>((InitializingBean) bean).afterPropertiesSet();
>>>MapperFactoryBean::this.checkDaoConfig();
image.png
图 10 MapperFactoryBean类图
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
//这里和mybatis整合, 完成mapper class的注入 ,将其添加到knowMappers中。
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
1.2.4.2 knownMappers
1.4 Bean的获取
1.4.1 首次
默认
Beandefinition的元信息,AccountDao 是如何根据bean生成org.apache.ibatis.binding.MapperProxy@4c1f22f3,取到的对象放入factoryBeanObjectCache中缓存。
MapperFactoryBean
> @Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
org.mybatis.spring.SqlSessionTemplate
>@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
org.apache.ibatis.session.Configuration
>public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
org.apache.ibatis.binding.MapperRegistry
> 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 {
// 创建MapperProxy代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
org.apache.ibatis.binding.MapperProxyFactory
>public T newInstance(SqlSession sqlSession) {
// 创建InvocationHandler
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
// 类加载器
// 接口
// 自定义的InvocationHandler
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
1.4.2 非首次
org.springframework.beans.factory.support.AbstractBeanFactory:getObjectForBeanInstance
> Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
image.png
图 11 factoryBeanObjectCache
1.5数据获取
MapperProxy
>MapperMethod
>>SqlSessionTemplate::selectList
>>>SqlSessionInterceptor::invoke
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
//确保缓存一致性
sqlSession.commit(true);
}
return result;
1.5.1 SqlSessionTemplate****代理构造
org\mybatis\spring\SqlSessionTemplate.java
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
@Override
public <E> List<E> selectList(String statement, Object parameter) {
// return this.sqlSessionProxy.<E> 实际返回 JdkProxy
return this.sqlSessionProxy.<E> selectList(statement, parameter);
}
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
2 mybatis-spring中间件常用的类
2.1 SqlSessionFactoryBean
image.png图 12 SqlSessionFactoryBean类图
2.2 DefaultListableBeanFactory
这个类是Spring IOC容器的核心。
image.png图 13 DefaultListableBeanFactory
3 JDK代理类
public final class $ProxyUserMapper extends Proxy implements AccountDao {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;