当前位置:   article > 正文

mybatis集成spring的底层实现原理_mabtis property 'basepackage' is required

mabtis property 'basepackage' is required

一.问题

  1. mybatis 怎么创建mapper的BeanDefinition

  1. 为什么要将BeanDefinition的beanClass设置为MapperFactoryBean

  1. mybatis什么时候创建的代理对象

  1. mybatis怎么创建代理对象

  1. 代理对象是怎么实现功能增强(具体怎么调用的)

二.入口

源码分析

  1. @MapperScan

重点看@Import(MapperScannerRegistrar.class),将MapperScannerRegistrar.class引进来

  1. @Slf4j
  2. @org.springframework.boot.autoconfigure.SpringBootApplication
  3. @MapperScan(basePackages = {"com.springboot.study.mapper"})
  4. public class SpringBootApplication {
  5.     public static void main(String[] args) {
  6. SpringApplication.run(SpringBootApplication.class, args);
  7. }
  8. }
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Target(ElementType.TYPE)
  11. @Documented
  12. @Import(MapperScannerRegistrar.class)
  13. @Repeatable(MapperScans.class)
  14. public @interface MapperScan {
  15.   String[] value() default {};
  16. String[] basePackages() default {};
  17. Class<?>[] basePackageClasses() default {};
  18. Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
  19. Class<? extends Annotation> annotationClass() default Annotation.class;
  20. Class<?> markerInterface() default Class.class;
  21. String sqlSessionTemplateRef() default "";
  22. String sqlSessionFactoryRef() default "";
  23. Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
  24. String lazyInitialization() default "";
  25. String defaultScope() default AbstractBeanDefinition.SCOPE_DEFAULT;
  1. MapperScannerRegistrar

registerBeanDefinitions()扫描@MapperScan注解上面的属性并且构建MapperScannerConfigurer BeanDefinition

  1. public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
  2. @Override
  3. @Deprecated
  4. public void setResourceLoader(ResourceLoader resourceLoader) {
  5. // NOP
  6. }
  7. @Override
  8. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  9. AnnotationAttributes mapperScanAttrs = AnnotationAttributes
  10. .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
  11. if (mapperScanAttrs != null) {
  12. registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
  13. generateBaseBeanName(importingClassMetadata, 0));
  14. }
  15. }
  16. void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
  17. BeanDefinitionRegistry registry, String beanName) {
  18. BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
  19. builder.addPropertyValue("processPropertyPlaceHolders", true);
  20. Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
  21. if (!Annotation.class.equals(annotationClass)) {
  22. builder.addPropertyValue("annotationClass", annotationClass);
  23. }
  24. Class<?> markerInterface = annoAttrs.getClass("markerInterface");
  25. if (!Class.class.equals(markerInterface)) {
  26. builder.addPropertyValue("markerInterface", markerInterface);
  27. }
  28. Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
  29. if (!BeanNameGenerator.class.equals(generatorClass)) {
  30. builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
  31. }
  32. Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
  33. if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
  34. builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
  35. }
  36. String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
  37. if (StringUtils.hasText(sqlSessionTemplateRef)) {
  38. builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
  39. }
  40. String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
  41. if (StringUtils.hasText(sqlSessionFactoryRef)) {
  42. builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
  43. }
  44. List<String> basePackages = new ArrayList<>();
  45. basePackages.addAll(
  46. Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
  47. basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
  48. .collect(Collectors.toList()));
  49. basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
  50. .collect(Collectors.toList()));
  51. if (basePackages.isEmpty()) {
  52. basePackages.add(getDefaultBasePackage(annoMeta));
  53. }
  54. String lazyInitialization = annoAttrs.getString("lazyInitialization");
  55. if (StringUtils.hasText(lazyInitialization)) {
  56. builder.addPropertyValue("lazyInitialization", lazyInitialization);
  57. }
  58. String defaultScope = annoAttrs.getString("defaultScope");
  59. if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
  60. builder.addPropertyValue("defaultScope", defaultScope);
  61. }
  62. builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
  63. registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
  64. }
  65. private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
  66. return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
  67. }
  68. private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {
  69. return ClassUtils.getPackageName(importingClassMetadata.getClassName());
  70. }
  71. static class RepeatingRegistrar extends MapperScannerRegistrar {
  72. @Override
  73. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  74. AnnotationAttributes mapperScansAttrs = AnnotationAttributes
  75. .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
  76. if (mapperScansAttrs != null) {
  77. AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
  78. for (int i = 0; i < annotations.length; i++) {
  79. registerBeanDefinitions(importingClassMetadata, annotations[i], registry,
  80. generateBaseBeanName(importingClassMetadata, i));
  81. }
  82. }
  83. }
  84. }
  85. }
  1. MapperScannerConfigurer

我们首先观察一下实现了一些什么接口才知道它想要执行的时机和操作的具体功能

1.InitializingBean.afterPropertiesSet():在属性赋值之后加了一个判断basePackage是否为空的操作

2.ApplicationContextAware只是拿到了ApplicationContext给当前对象里的属性赋值而已

3.重点是BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry:自定义了一个扫描器去扫描接口注册成BeanDefinition

留意一下(ClassPathMapperScanner)scanner.registerFilters();这里将

然后调用spring的扫描scanner.scan()

  1. public class MapperScannerConfigurer
  2. implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
  3. private String basePackage;
  4. private boolean addToConfig = true;
  5. private String lazyInitialization;
  6. private SqlSessionFactory sqlSessionFactory;
  7. private SqlSessionTemplate sqlSessionTemplate;
  8. private String sqlSessionFactoryBeanName;
  9. private String sqlSessionTemplateBeanName;
  10. private Class<? extends Annotation> annotationClass;
  11. private Class<?> markerInterface;
  12. private Class<? extends MapperFactoryBean> mapperFactoryBeanClass;
  13. private ApplicationContext applicationContext;
  14. private String beanName;
  15. private boolean processPropertyPlaceHolders;
  16. private BeanNameGenerator nameGenerator;
  17. private String defaultScope;
  18.   @Override
  19. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  20. if (this.processPropertyPlaceHolders) {
  21. processPropertyPlaceHolders();
  22. }
  23. ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  24. scanner.setAddToConfig(this.addToConfig);
  25. scanner.setAnnotationClass(this.annotationClass);
  26. scanner.setMarkerInterface(this.markerInterface);
  27. scanner.setSqlSessionFactory(this.sqlSessionFactory);
  28. scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  29. scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  30. scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  31. scanner.setResourceLoader(this.applicationContext);
  32. scanner.setBeanNameGenerator(this.nameGenerator);
  33. scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
  34. if (StringUtils.hasText(lazyInitialization)) {
  35. scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
  36. }
  37. if (StringUtils.hasText(defaultScope)) {
  38. scanner.setDefaultScope(defaultScope);
  39. }
  40. scanner.registerFilters();
  41. scanner.scan(
  42. StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  43. }
  44.    
  45.   @Override
  46.   public void afterPropertiesSet() throws Exception {
  47.     notNull(this.basePackage, "Property 'basePackage' is required");
  48.   }
  49. }
  1. ClassPathMapperScanner

1.继承了spring的ClassPathBeanDefinitionScanner扫描器

2.registerFilters()

这里将ClassPathMapperScanner作为TypeFilter添加进includeFilters里面了,目的让扫描出来的Mapper接口能通过ClassPathBeanDefinitionScanner.isCandidateComponent。

3.definition.setBeanClass(this.mapperFactoryBeanClass);

将MapperInterface BeanDefinition的beanClass设置成MapperFactoryBean.class

4.definition.setLazyInit(lazyInitialization);

将MapperInterface BeanDefinition设置为懒加载,调用的时候才将Bean对象实例化

  1. public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  2.     public void registerFilters() {
  3. boolean acceptAllInterfaces = true;
  4. // if specified, use the given annotation and / or marker interface
  5. if (this.annotationClass != null) {
  6. addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
  7. acceptAllInterfaces = false;
  8. }
  9. // override AssignableTypeFilter to ignore matches on the actual marker interface
  10. if (this.markerInterface != null) {
  11. addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
  12. @Override
  13. protected boolean matchClassName(String className) {
  14. return false;
  15. }
  16. });
  17. acceptAllInterfaces = false;
  18. }
  19. if (acceptAllInterfaces) {
  20. // default include filter that accepts all classes
  21. addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
  22. }
  23. // exclude package-info.java
  24. addExcludeFilter((metadataReader, metadataReaderFactory) -> {
  25. String className = metadataReader.getClassMetadata().getClassName();
  26. return className.endsWith("package-info");
  27. });
  28. }
  29.     private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
  30.     AbstractBeanDefinition definition;
  31.     BeanDefinitionRegistry registry = getRegistry();
  32.     for (BeanDefinitionHolder holder : beanDefinitions) {
  33.     definition = (AbstractBeanDefinition) holder.getBeanDefinition();
  34.     boolean scopedProxy = false;
  35.     if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
  36.     definition = (AbstractBeanDefinition) Optional
  37.     .ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition())
  38.     .map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException(
  39.     "The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));
  40.     scopedProxy = true;
  41.     }
  42.     String beanClassName = definition.getBeanClassName();
  43.     LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
  44.     + "' mapperInterface");
  45.    
  46.     // the mapper interface is the original class of the bean
  47.     // but, the actual class of the bean is MapperFactoryBean
  48.     definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
  49.     definition.setBeanClass(this.mapperFactoryBeanClass);
  50.    
  51.     definition.getPropertyValues().add("addToConfig", this.addToConfig);
  52.    
  53.     // Attribute for MockitoPostProcessor
  54.     // https://github.com/mybatis/spring-boot-starter/issues/475
  55.     definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, beanClassName);
  56.    
  57.     boolean explicitFactoryUsed = false;
  58.     if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
  59.     definition.getPropertyValues().add("sqlSessionFactory",
  60.     new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
  61.     explicitFactoryUsed = true;
  62.     } else if (this.sqlSessionFactory != null) {
  63.     definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
  64.     explicitFactoryUsed = true;
  65.     }
  66.    
  67.     if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
  68.     if (explicitFactoryUsed) {
  69.     LOGGER.warn(
  70.     () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
  71.     }
  72.     definition.getPropertyValues().add("sqlSessionTemplate",
  73.     new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
  74.     explicitFactoryUsed = true;
  75.     } else if (this.sqlSessionTemplate != null) {
  76.     if (explicitFactoryUsed) {
  77.     LOGGER.warn(
  78.     () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
  79.     }
  80.     definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
  81.     explicitFactoryUsed = true;
  82.     }
  83.    
  84.     if (!explicitFactoryUsed) {
  85.     LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
  86.     definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
  87.     }
  88.    
  89.     definition.setLazyInit(lazyInitialization);
  90.    
  91.     if (scopedProxy) {
  92.     continue;
  93.     }
  94.    
  95.     if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {
  96.     definition.setScope(defaultScope);
  97.     }
  98.    
  99.     if (!definition.isSingleton()) {
  100.     BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
  101.     if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
  102.     registry.removeBeanDefinition(proxyHolder.getBeanName());
  103.     }
  104.     registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
  105.     }
  106.    
  107.     }
  108.     }
  109. }
  1. MapperFactoryBean

  1. 实现了FactoryBean接口,定义了一个专门处理MapperInterface Bean的工厂

2.当使用的时候(我这里用@Autowired注入作为使用例子)会调用MapperFactoryBean的getObject方法

@Autowired
private PeopleMapper peopleMapper;
  1. public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
  2.   @Override
  3. public T getObject() throws Exception {
  4.     return getSqlSession().getMapper(this.mapperInterface);
  5.   }
  6. }
  1. MybatisMapperProxyFactory

1.先走MybatisMapperRegistry.getMapper,

2.然后做一个强转MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);

3.调用mapperProxyFactory.newInstance(sqlSession);

  1. public class MybatisMapperRegistry extends MapperRegistry {
  2.     @Override
  3. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  4. // TODO 这里换成 MybatisMapperProxyFactory 而不是 MapperProxyFactory
  5. // fix https://github.com/baomidou/mybatis-plus/issues/4247
  6. MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);
  7. if (mapperProxyFactory == null) {
  8. mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.entrySet().stream()
  9. .filter(t -> t.getKey().getName().equals(type.getName())).findFirst()
  10. .orElseThrow(() -> new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry."));
  11. }
  12. try {
  13. return mapperProxyFactory.newInstance(sqlSession);
  14. } catch (Exception e) {
  15. throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  16. }
  17. }
  18. }

4.在newInstance()里面创建了一个MybatisMapperProxy对象然后调用proxy.newProxyInstance创建代理对象

  1. public class MybatisMapperProxyFactory<T> {
  2. @Getter
  3. private final Class<T> mapperInterface;
  4. @Getter
  5. private final Map<Method, MybatisMapperProxy.MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
  6. public MybatisMapperProxyFactory(Class<T> mapperInterface) {
  7. this.mapperInterface = mapperInterface;
  8. }
  9. @SuppressWarnings("unchecked")
  10. protected T newInstance(MybatisMapperProxy<T> mapperProxy) {
  11. return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
  12. }
  13. public T newInstance(SqlSession sqlSession) {
  14. final MybatisMapperProxy<T> mapperProxy = new MybatisMapperProxy<>(sqlSession, mapperInterface, methodCache);
  15. return newInstance(mapperProxy);
  16. }
  17. }
  1. MybatisMapperProxy(接口代理对象)

Map<Method, MapperMethodInvoker> methodCache属性:用来存mapper的方法,第一次调用会put进去
SqlSession sqlSession:访问数据库
Class<T> mapperInterface:你的mapper接口类型

实现了InvocationHandler接口,职责是处理代理类的执行方法

当调用mapper的方法,invoke->if(你的所属类型是Object类就直接执行实现方法)else(是接口类型,走cachedInvoker)

cachedInvoker:会判断你是否是default方法,true:走DefaultMethodInvoker.invoke,直接传参执行方法,false:走PlainMethodInvoker.invoke,底层是走sqlSession访问数据库获取数据返回

  1. public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
  2. private static final long serialVersionUID = -5154982058833204559L;
  3. private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
  4. | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
  5. private static final Constructor<MethodHandles.Lookup> lookupConstructor;
  6. private static final Method privateLookupInMethod;
  7. private final SqlSession sqlSession;
  8. private final Class<T> mapperInterface;
  9. private final Map<Method, MapperMethodInvoker> methodCache;
  10. public MybatisMapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
  11. this.sqlSession = sqlSession;
  12. this.mapperInterface = mapperInterface;
  13. this.methodCache = methodCache;
  14. }
  15. static {
  16. Method privateLookupIn;
  17. try {
  18. privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
  19. } catch (NoSuchMethodException e) {
  20. privateLookupIn = null;
  21. }
  22. privateLookupInMethod = privateLookupIn;
  23. Constructor<MethodHandles.Lookup> lookup = null;
  24. if (privateLookupInMethod == null) {
  25. // JDK 1.8
  26. try {
  27. lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
  28. lookup.setAccessible(true);
  29. } catch (NoSuchMethodException e) {
  30. throw new IllegalStateException(
  31. "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
  32. e);
  33. } catch (Throwable t) {
  34. lookup = null;
  35. }
  36. }
  37. lookupConstructor = lookup;
  38. }
  39. @Override
  40. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  41. try {
  42. if (Object.class.equals(method.getDeclaringClass())) {
  43. return method.invoke(this, args);
  44. } else {
  45. return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
  46. }
  47. } catch (Throwable t) {
  48. throw ExceptionUtil.unwrapThrowable(t);
  49. }
  50. }
  51. private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  52. try {
  53. return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
  54. if (m.isDefault()) {
  55. try {
  56. if (privateLookupInMethod == null) {
  57. return new DefaultMethodInvoker(getMethodHandleJava8(method));
  58. } else {
  59. return new DefaultMethodInvoker(getMethodHandleJava9(method));
  60. }
  61. } catch (IllegalAccessException | InstantiationException | InvocationTargetException
  62. | NoSuchMethodException e) {
  63. throw new RuntimeException(e);
  64. }
  65. } else {
  66. return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  67. }
  68. });
  69. } catch (RuntimeException re) {
  70. Throwable cause = re.getCause();
  71. throw cause == null ? re : cause;
  72. }
  73. }
  74. private MethodHandle getMethodHandleJava9(Method method)
  75. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  76. final Class<?> declaringClass = method.getDeclaringClass();
  77. return ((MethodHandles.Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
  78. declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
  79. declaringClass);
  80. }
  81. private MethodHandle getMethodHandleJava8(Method method)
  82. throws IllegalAccessException, InstantiationException, InvocationTargetException {
  83. final Class<?> declaringClass = method.getDeclaringClass();
  84. return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);
  85. }
  86. interface MapperMethodInvoker {
  87. Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
  88. }
  89. private static class PlainMethodInvoker implements MapperMethodInvoker {
  90. private final MybatisMapperMethod mapperMethod;
  91. public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
  92. super();
  93. this.mapperMethod = mapperMethod;
  94. }
  95. @Override
  96. public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  97. return mapperMethod.execute(sqlSession, args);
  98. }
  99. }
  100. private static class DefaultMethodInvoker implements MapperMethodInvoker {
  101. private final MethodHandle methodHandle;
  102. public DefaultMethodInvoker(MethodHandle methodHandle) {
  103. super();
  104. this.methodHandle = methodHandle;
  105. }
  106. @Override
  107. public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  108. return methodHandle.bindTo(proxy).invokeWithArguments(args);
  109. }
  110. }
  111. }

三.总结回答

  1. 通过自定义扫描器去扫描指定的backpage包下的mapperinterface

  1. 3. 4.通过自定义工厂类MapperFactoryBean实现了FactoryBean接口,在使用mapperinterface对象(调用getObject)的时候会自动创建代理类MybatisMapperProxy(由Bean容器管理)

5.通过实现InvocationHandler接口,自定义代理类执行对象方法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/892551
推荐阅读
相关标签
  

闽ICP备14008679号