MyBatis源码解析(一)----创建代理流程

186 阅读2分钟

MyBatis创建代理流程

1. 通过注解扫描 basePackages

@MapperScan("com.demo.*")
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

2. @MapperScan注解@Import(MapperScannerRegistrar.class)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
	...
}

3. 动态注册MapperScannerConfigurer的beanDefinition

MapperScannerRegistrar 实现了ImportBeanDefinitionRegistrar 接口,ImportBeanDefinitionRegistrar是spring对外提供动态注册beanDefinition的接口,在refresh#invokeBeanFactoryPostProcessors(beanFactory); 会调用所有实现了ImportBeanDefinitionRegistrar 接口的bean。

spring在初始化的时候,会回调registerBeanDefinitions方法,将MapperScannerConfigurer的bean definition注入spring容器。

void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
		
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    	builder.addPropertyValue("processPropertyPlaceHolders", true);
    	...
    	...
    	...
    	builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
    	
    	registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}

4.执行MapperScannerConfigurer的postProcessBeanDefinitionRegistry

MapperScannerConfigurer 实现了BeanDefinitionRegistryPostProcessor 接口,在refresh#invokeBeanFactoryPostProcessors(beanFactory); 会回调postProcessBeanDefinitionRegistry 方法。

说明:postProcessBeanDefinitionRegistry方法可以修改在BeanDefinitionRegistry接口实现类中注册的任意BeanDefinition,也可以增加和删除BeanDefinition。原因是这个方法执行前所有常规的BeanDefinition已经被加载到BeanDefinitionRegistry接口实现类中,但还没有bean被实例化。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
  if (StringUtils.hasText(lazyInitialization)) {
    scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
  }
  scanner.registerFilters();
  scanner.scan(
      StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

在这里会将@MapperScan("com.demo.*") 包进行扫描

5. 将基础包下的类扫描加载为BeanDefinition,将mapper接口BeanClass设置为MapperFactoryBean

@Override
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 {
    processBeanDefinitions(beanDefinitions);
  }

  return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
	GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      //在这里将BeanClass设置为MapperFactoryBean
      definition.setBeanClass(this.mapperFactoryBeanClass);
		...
		...
		...
}

6. MapperFactoryBean 生成Mapper的代理类MapperProxy

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
		...
		@Override
  		public T getObject() throws Exception {
    		return getSqlSession().getMapper(this.mapperInterface);
  		}
		...

}
public class DefaultSqlSession implements SqlSession {
		...
		@Override
  		public <T> T getMapper(Class<T> type) {
    			return configuration.<T>getMapper(type, this);
  		}
		...

}
public class Configuration {
		...
		public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    		return mapperRegistry.getMapper(type, sqlSession);
  		}
		...

}
public class 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 {
      				return mapperProxyFactory.newInstance(sqlSession);
    			} catch (Exception e) {
      				throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    			}
  		  }
		...

}
public class MapperProxyFactory<T> {
		...
		  	protected T newInstance(MapperProxy<T> mapperProxy) {
    				return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  			}

  			public T newInstance(SqlSession sqlSession) {
    				final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    				return newInstance(mapperProxy);
  			}

}

7. 生成Proxy的class示例

public final class $Proxy1 extends Proxy implements Producer3 {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy1(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void sell() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.demo.proxy.dynamic.Producer3").getMethod("sell");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}