springboot mybatis mapper 注入原理淺析

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 }

搞完收工!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章