美文网首页
2020-08-22_MapperScan源码分析1

2020-08-22_MapperScan源码分析1

作者: kikop | 来源:发表于2020-08-23 13:32 被阅读0次

    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;
    
    

    相关文章

      网友评论

          本文标题:2020-08-22_MapperScan源码分析1

          本文链接:https://www.haomeiwen.com/subject/mnbijktx.html