首页 > 其他分享 >springboot mybatis mapper 注入原理浅析

springboot mybatis mapper 注入原理浅析

时间:2023-06-28 22:11:51浏览次数:52  
标签:mapper sqlSessionFactory sqlSessionTemplate springboot definition 浅析 mapperInter

spring+mybatis是我们常用的开发组合,一般情况,我们只需要写一个Mapper接口  加上@Mapper注解就可以使用了,

那么他的工作原理是什么呢?

标准mybatis调用应该是这样的流程

 1 //读取配置
 2   InputStream config = Resources.getResourceAsStream("mybatis-config.xml");
 3   //根据配置创建SessionFactory
 4   SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);
 5   //创建session
 6   SqlSession ss = ssf.openSession();
 7   //获取Mapper执行具体操作
 8   CommonMapper mapper=ss.getMapper(CommonMapper.class);
 9   Skt skt= mapper.getSktById("123");
10   //关闭session
11   ss.close();

 那么我们的Mapper代理对象肯定是封装了这些内容的,且看源码:

1#注册bean 从MapperScan开始
1 @Retention(RetentionPolicy.RUNTIME)
2 @Target({ElementType.TYPE})
3 @Documented
4 @Import({MapperScannerRegistrar.class}) //这里是入口
5 @Repeatable(MapperScans.class)
6 public @interface MapperScan {
7 }

2#MapperScannerRegistrar.registerBeanDefinitions 里面调用了  MapperScannerConfigurer

 1 void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
 2         BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
 3 //下面是添加各种注解上带的参数 
 4         builder.addPropertyValue("processPropertyPlaceHolders", true);
 5         Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
 6         if (!Annotation.class.equals(annotationClass)) {
 7             builder.addPropertyValue("annotationClass", annotationClass);
 8         }
 9 
10         Class<?> markerInterface = annoAttrs.getClass("markerInterface");
11         if (!Class.class.equals(markerInterface)) {
12             builder.addPropertyValue("markerInterface", markerInterface);
13         }
14 
15         Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
16         if (!BeanNameGenerator.class.equals(generatorClass)) {
17             builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
18         }
19 
20         Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
21         if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
22             builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
23         }
24 
25         String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
26         if (StringUtils.hasText(sqlSessionTemplateRef)) {
27             builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
28         }
29 
30         String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
31         if (StringUtils.hasText(sqlSessionFactoryRef)) {
32             builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
33         }
34 
35         List<String> basePackages = new ArrayList();
36         basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
37         basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
38         basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
39         if (basePackages.isEmpty()) {
40             basePackages.add(getDefaultBasePackage(annoMeta));
41         }
42 
43         String lazyInitialization = annoAttrs.getString("lazyInitialization");
44         if (StringUtils.hasText(lazyInitialization)) {
45             builder.addPropertyValue("lazyInitialization", lazyInitialization);
46         }
47 
48         String defaultScope = annoAttrs.getString("defaultScope");
49         if (!"".equals(defaultScope)) {
50             builder.addPropertyValue("defaultScope", defaultScope);
51         }
52 
53         builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
54         registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
55     }

3# MapperScannerConfigurer.postProcessBeanDefinitionRegistry 调用mapper扫描器

 1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
 2         if (this.processPropertyPlaceHolders) {
 3             this.processPropertyPlaceHolders();
 4         }
 5         //创建此种扫描器,更具packge路径扫描bean
 6         ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 7         scanner.setAddToConfig(this.addToConfig);
 8         scanner.setAnnotationClass(this.annotationClass);
 9         scanner.setMarkerInterface(this.markerInterface);
10         scanner.setSqlSessionFactory(this.sqlSessionFactory);
11         scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
12         scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
13         scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
14         scanner.setResourceLoader(this.applicationContext);
15         scanner.setBeanNameGenerator(this.nameGenerator);
16         scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
17         if (StringUtils.hasText(this.lazyInitialization)) {
18             scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
19         }
20 
21         if (StringUtils.hasText(this.defaultScope)) {
22             scanner.setDefaultScope(this.defaultScope);
23         }
24 
25         scanner.registerFilters();
26         scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
27     }

4#ClassPathMapperScanner.processBeanDefinitions  动态添加MapperFactoryBean

 1 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
 2         BeanDefinitionRegistry registry = this.getRegistry();
 3         Iterator var4 = beanDefinitions.iterator();
 4 
 5         while(var4.hasNext()) {
 6             BeanDefinitionHolder holder = (BeanDefinitionHolder)var4.next();
 7             AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition();
 8             boolean scopedProxy = false;
 9             if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
10                 definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> {
11                     return new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]");
12                 });
13                 scopedProxy = true;
14             }
15 
16             String beanClassName = definition.getBeanClassName();
17             LOGGER.debug(() -> {
18                 return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
19             });
20             
21   //这里设置构造时传出Mapper接口类型
22 definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
23            //这里设置MapperFactoryBean
24             definition.setBeanClass(this.mapperFactoryBeanClass);
25             definition.getPropertyValues().add("addToConfig", this.addToConfig);
26             definition.setAttribute("factoryBeanObjectType", beanClassName);
27             boolean explicitFactoryUsed = false;
28             if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
29                 definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
30                 explicitFactoryUsed = true;
31             } else if (this.sqlSessionFactory != null) {
32                 definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
33                 explicitFactoryUsed = true;
34             }
35 
36             if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
37                 if (explicitFactoryUsed) {
38                     LOGGER.warn(() -> {
39                         return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
40                     });
41                 }
42 
43               //添加各种参数  如果有
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); 44 explicitFactoryUsed = true; 45 } else if (this.sqlSessionTemplate != null) { 46 if (explicitFactoryUsed) { 47 LOGGER.warn(() -> { 48 return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."; 49 }); 50 } 51 52 definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); 53 explicitFactoryUsed = true; 54 } 55 56 if (!explicitFactoryUsed) { 57 LOGGER.debug(() -> { 58 return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."; 59 });
//可以设置自动注入模式哦,设置完后MapperBeanFactory里面的属性统统根据类型自动注入(如果不重复) 60 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); 61 } 62 63 definition.setLazyInit(this.lazyInitialization); 64 if (!scopedProxy) { 65 if ("singleton".equals(definition.getScope()) && this.defaultScope != null) { 66 definition.setScope(this.defaultScope); 67 } 68 69 if (!definition.isSingleton()) { 70 BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true); 71 if (registry.containsBeanDefinition(proxyHolder.getBeanName())) { 72 registry.removeBeanDefinition(proxyHolder.getBeanName()); 73 } 74 75 registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition()); 76 } 77 } 78 } 79 80 }

5# MapperFactoryBean 的实现

 1 public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { // 实现了 FactoryBean 接口(关键)
 2     private Class<T> mapperInterface;
 3     private boolean addToConfig = true;
 4 
 5     public MapperFactoryBean() {
 6     }
 7 
 8     public MapperFactoryBean(Class<T> mapperInterface) { //上一步就是指定用这个来构造bean的
 9         this.mapperInterface = mapperInterface;
10     }
11 
12     protected void checkDaoConfig() {
13         super.checkDaoConfig();
14         Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
15         Configuration configuration = this.getSqlSession().getConfiguration();
16         if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
17             try {
18                 configuration.addMapper(this.mapperInterface);
19             } catch (Exception var6) {
20                 this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
21                 throw new IllegalArgumentException(var6);
22             } finally {
23                 ErrorContext.instance().reset();
24             }
25         }
26 
27     }
28 
29     public T getObject() throws Exception {
30         return this.getSqlSession().getMapper(this.mapperInterface);  //这里有返回了Mapper  是不是似曾相识,没错  就是那个啦
31     }
32 
33     public Class<T> getObjectType() {
34         return this.mapperInterface;
35     }
36 
37     public boolean isSingleton() {
38         return true;
39     }
40 
41     public void setMapperInterface(Class<T> mapperInterface) {
42         this.mapperInterface = mapperInterface;
43     }
44 
45     public Class<T> getMapperInterface() {
46         return this.mapperInterface;
47     }
48 
49     public void setAddToConfig(boolean addToConfig) {
50         this.addToConfig = addToConfig;
51     }
52 
53     public boolean isAddToConfig() {
54         return this.addToConfig;
55     }
56 }
57 
58 public abstract class SqlSessionDaoSupport extends DaoSupport {
59     private SqlSessionTemplate sqlSessionTemplate;
60 
61     public SqlSessionDaoSupport() {
62     }
63 
64     //这里是自动注入的 beandDefine的时候可以设置哦
65     public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
66         if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
67             this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
68         }
69 
70     }
71 
72     protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
73         return new SqlSessionTemplate(sqlSessionFactory);
74     }
75 
76     public final SqlSessionFactory getSqlSessionFactory() {
77         return this.sqlSessionTemplate != null ? this.sqlSessionTemplate.getSqlSessionFactory() : null;
78     }
79 
80     public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
81         this.sqlSessionTemplate = sqlSessionTemplate;
82     }
83 
84     public SqlSession getSqlSession() {
85         return this.sqlSessionTemplate;
86     }
87 
88     public SqlSessionTemplate getSqlSessionTemplate() {
89         return this.sqlSessionTemplate;
90     }
91 
92     protected void checkDaoConfig() {
93         Assert.notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
94     }
95 }

搞完收工!

 

标签:mapper,sqlSessionFactory,sqlSessionTemplate,springboot,definition,浅析,mapperInter
From: https://www.cnblogs.com/dint/p/17512685.html

相关文章

  • 四、SpringBoot整合Apollo
    Apollo非常支持与Spring和SpringBoot的整合。这里选择SpringBoot2.7.9,java选择jdk17。添加依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>......
  • springboot测试时不能写个main测试含有bean方法的原因
     springboot使用bean作用是不用自己new对象,new类生成对象时,可能需要输入自定义类B作为参数,而该自定义类B可能又依赖其它需要输入自定义类C作为参数,新建对象会很麻烦,springboot的bean注入容器后,该对象不用自己定义,直接从容器中取.但用注解定义了bean后,并没有注入容......
  • 基于SpringBoot整合Redisson的延迟队列
    一、需求:     1.订单下单超过30分钟以后,如果还未支付,则自动转为取消支付状态 2.订单收货超过七天以后,如果还未评价,则自动转为好评 3.等类似需求二、实现步骤:    1. 引入redisson依赖<dependency><groupId>org.rediss......
  • Springboot实现邮件发送
    本文以QQ邮箱为例,实现springboot邮件发送邮箱设置 主要获取授权码   按照步骤开启服务 获取授权码导入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>配置......
  • springboot 自定义异常 全局异常处理器
    创建自定义异常类,继承 RuntimeException类1publicclassCustomExceptionextendsRuntimeException{2publicCustomException(Stringmessage){3super(message);4}5}在指定情况下抛出该异常,代码如下: @ServicepublicclassCategoryServiceIm......
  • 浅析住宅小区电动车充电桩的电气设计与平台管理系统
    罗轩志安科瑞电气股份有限公司 上海嘉定201801摘要:根据目前对于新能源汽车发展规划及政策,以及国内外充电设施的主要类型和技术参数。论述地下车库电动汽车充电桩的供配电系统的设计及设计过程中需要注意的一些问题。关键词:充电桩;地下车库;供配电设计;负荷计算0引言新能源汽车的......
  • SpringBoot接入Chat-GPT3
    创建一个APIKeyAPIKey创建网址:https://platform.openai.com/account/api-keys先登录OpenAI账号登陆后创建一个APIKey起一个名字点击创建,生成一个APIKey,记录下这个APIKey后续会用。可以在官网看到剩余容量,账号默认会送$18刀的容量,超过需要购买。在SpringB......
  • SpringBoot自定义starter
    1、先来一个简单的案例非常简单的工程结构controllerpackagecom.ly.demo.controller;importcom.ly.demo.service.MyStarterService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;import......
  • SpringBoot项目中功能集成的方式
    原文合集地址如下,有需要的朋友可以关注本文地址合集地址SpringBoot项目中功能集成的方式接口集成基于HTTP协议的集成方式协议和通信HTTP是一种基于客户端-服务器模型的协议。确定使用的HTTP版本(如HTTP/1.1或HTTP/2)以及通信过程中使用的其他协议和规范。在协议和通信阶段,需......
  • 基于MySQL+SpringBoot+IDEA开放的绩效评估系统
    基于MySQL+SpringBoot+IDEA开放的绩效评估系统项目介绍......