2020-08-22_MapperScan源码分析1

2020-08-23  本文已影响0人  kikop

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;

上一篇下一篇

猜你喜欢

热点阅读