第02篇:Mybatis配置文件解析
作者: 西魏陶渊明
博客: https://springlearn.cn
真正的猛士,每天干一碗毒鸡汤!
问世间钱为何物,只叫人生死相许。!😄
# 一、配置文件分析
文件分析
在上一篇的代码中,我们看到了一个非常重要文件,这里我们先来人肉分析看,然后看下代码是如何解析的,毕竟代码也是人写的。 思路决定出路,我们如果有思路,然后在看源码会更加的具有分析的能动性。
    
     - 
      
       
      
      
       
        @Test
       
      
 
     - 
      
       
      
      
           public void mapper() {
       
      
 
     - 
      
       
      
      
               // 读取配置信息(为什么路径前不用加/,因为是相对路径。maven编译后的资源文件和class文件都是在一个包下,所以不用加/就是当前包目录)
       
      
 
     - 
      
       
      
      
               InputStream mapperInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatisConfig.xml");
       
      
 
     - 
      
       
      
      
               // 生成SqlSession工厂,SqlSession从名字上看就是,跟数据库交互的会话信息,负责将sql提交到数据库进行执行
       
      
 
     - 
      
       
      
      
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(mapperInputStream, "development");
       
      
 
     - 
      
       
      
      
               // 获取Mybatis配置信息
       
      
 
     - 
      
       
      
      
               Configuration configuration = sqlSessionFactory.getConfiguration();
       
      
 
     - 
      
       
      
      
               // 参数: autoCommit,从名字上看就是是否自动提交事务
       
      
 
     - 
      
       
      
      
               SqlSession sqlSession = sqlSessionFactory.openSession(false);
       
      
 
     - 
      
       
      
      
               // 获取Mapper
       
      
 
     - 
      
       
      
      
               TUserMapper mapper = configuration.getMapperRegistry().getMapper(TUserMapper.class, sqlSession);
       
      
 
     - 
      
       
      
      
               TUser tUser = new TUser();
       
      
 
     - 
      
       
      
      
       
                tUser.setName("testUser1");
       
      
 
     - 
      
       
      
      
       
                tUser.setTokenId("testTokenId1");
       
      
 
     - 
      
       
      
      
       
                mapper.insert(tUser);
       
      
 
     - 
      
       
      
      
               // 获取插入的数据
       
      
 
     - 
      
       
      
      
       
                System.out.println(mapper.selectAll());
       
      
 
     - 
      
       
      
      
               // 数据插入后,执行查询,然后回滚数据
       
      
 
     - 
      
       
      
      
       
                sqlSession.rollback();
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
    
   
    
  # 1.1 mybatisConfig.xml
注意看高亮行
- line(4) dtd文件是xml的约束文件,用于约束 
xml标签中属性 - line(8) properties标签,指定了配置信息文件是 
application.properties - line(11-13) mybatis的配置信息
 - line(15-27) mybatis支持多环境配置
 - line(30-32) 映射文件
 
基于上面的行,我们来讲解。
    
     - 
      
       
      
      
       
        <?xml version="1.0" encoding="UTF-8" ?>
       
      
 
     - 
      
       
      
      
       
        <!DOCTYPE configuration
       
      
 
     - 
      
       
      
      
               PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       
      
 
     - 
      
       
      
      
               "http://mybatis.org/dtd/mybatis-3-config.dtd">
       
      
 
     - 
      
       
      
      
       
        <configuration>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
           <!-- 指定properties配置文件, 我这里面配置的是数据库相关 -->
       
      
 
     - 
      
       
      
      
           <properties resource="application.properties"></properties>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
           <!-- 指定Mybatis使用log4j -->
       
      
 
     - 
      
       
      
      
           <settings>
       
      
 
     - 
      
       
      
      
               <setting name="logImpl" value="LOG4J"/>
       
      
 
     - 
      
       
      
      
           </settings>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
           <environments default="development">
       
      
 
     - 
      
       
      
      
               <environment id="development">
       
      
 
     - 
      
       
      
      
                   <transactionManager type="JDBC"/>
       
      
 
     - 
      
       
      
      
                   <dataSource type="POOLED">
       
      
 
     - 
      
       
      
      
                       <!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 -->
       
      
 
     - 
      
       
      
      
                       <property name="driver" value="${datasource.driver-class-name}"/>
       
      
 
     - 
      
       
      
      
                       <property name="url" value="${datasource.url}"/>
       
      
 
     - 
      
       
      
      
                       <property name="username" value="${datasource.username}"/>
       
      
 
     - 
      
       
      
      
                       <property name="password" value="${datasource.password}"/>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
                   </dataSource>
       
      
 
     - 
      
       
      
      
               </environment>
       
      
 
     - 
      
       
      
      
           </environments>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
           <!-- 映射文件,mybatis精髓, 后面才会细讲 -->
       
      
 
     - 
      
       
      
      
           <mappers>
       
      
 
     - 
      
       
      
      
               <mapper resource="mapper/TUserMapper.xml"/>
       
      
 
     - 
      
       
      
      
           </mappers>
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
       
        </configuration>
       
      
 
    
   
    
  # 二、知识点讲解
# 2.1 xml约束文件dtd
为什么要学习dtd约束文件呢? 当你学会dtd约束文件后,你就知道这个标签有那些属性,知道标签及子标签信息。 当有一天你要写开源框架的时候,你也可以来定义你自己的配置文件规则。这部分知识了解就行。不需要死记硬背。 因为记住也基本没啥用,只要做到看到了认识,需要用了知道去哪里抄代码学习就够了。
# 2.1.1 元素 & 属性 & 属性值
| 域 | 示例 | 语法 | 例子 | 
|---|---|---|---|
| 元素 | 声明根元素标签 | <!ELEMENT 元素名称 (元素内容)> | 
     <!ELEMENT students(student)>,元素students有一个student | 
    
| 元素 | 空元素 | <!ELEMENT 元素名称 EMPTY> | 
     <br /> | 
    
| 元素 | 元素只出现一次 | <!ELEMENT 元素名称 (子元素名称)> | 
     <!ELEMENT students(student)>,元素students至少有一个student | 
    
| 元素 | 元素最少出现一次 | <!ELEMENT 元素名称 (子元素名称+)> | 
     <!ELEMENT students(student+)>,元素students最少有一个student | 
    
| 元素 | 声明出现零次或多次的元素 | <!ELEMENT 元素名称 (子元素名称*)> | 
     <!ELEMENT students(student*)>,元素students可以有多个student,也可以一个没有 | 
    
| 元素 | 声明“非.../既...”类型的内容 | <!ELEMENT note (to,from,header,(message|body))> | 
     <!ELEMENT student(name,age,(boy|girl))>,元素student有一个name和age标签,有一个boy或者girl标签 | 
    
| 元素 | 声明混合型的内容 | <!ELEMENT note (#PCDATA|to|from|header|message)*> | 
     <!ELEMENT note (#PCDATA|to|from|header|message)*>"note" 元素可包含出现零次或多次的 PCDATA、"to"、"from"、"header" 或者 "message" | 
    
| 属性 | 属性声明 | <!ATTLIST 元素名称 属性名称 属性类型 默认值> | 
     <!ATTLIST payment type CDATA "check">,payment有一个属性type,类型为字符类型,默认值check | 
    
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
值类型
| 类型 | 描述 | 
|---|---|
| CDATA | 值为字符数据 (character data) | 
| (en1 | en2 | 
| ID | 值为唯一的 id | 
| IDREF | 值为另外一个元素的 id | 
| IDREFS | 值为其他 id 的列表 | 
| NMTOKEN | 值为合法的 XML 名称 | 
| NMTOKENS | 值是一个实体 | 
| ENTITIES | 值是一个实体列表 | 
| NOTATION | 此值是符号的名称 | 
| xml: | 值是一个预定义的 XML 值 | 
默认值参数可使用下列值
| 类型 | 描述 | 
|---|---|
| 值 | 属性的默认值 | 
| #REQUIRED | 属性值是必需的 | 
| #IMPLIED | 属性不是必需的 | 
| #FIXED value | 属性值是固定的 | 
# 2.2 configuration标签分析
前面我们知道了dtd约束文件,我们就可以看下,configuration标签一共有那些子标签及属性信息了。
mybatis-3-config.dtd (opens new window)
通过分析dtd文件,我们知道有那些子标签及属性信息。内容比较长。但是不是很重要。这里只要知道就行。
后面我们看如何使用代码来解析这些标签。
# 2.3 Mybatis配置解析核心逻辑
思路决定出路
- line(6) 
sqlSessionFactory.getConfiguration() 
由此来看所有的解析都是在SqlSessionFactoryBuilder进行完成的. 具体的解析xml代码我们不研究,这里我们只要搞清楚它的调用关系,及实现的代码在哪里即可。如果这里 看懂,其实都会得到一个结论。就是mybaits的源码是比较简单的,因为他的配置是比较集中的,无论是xml方式或者是注解方式。 最终所有的配置信息都在 Configuration 类中。
    
     - 
      
       
      
      
       
        @Test
       
      
 
     - 
      
       
      
      
           public void configuration() {
       
      
 
     - 
      
       
      
      
               // 读取配置信息(为什么路径前不用加/,因为是相对路径。maven编译后的资源文件和class文件都是在一个包下,所以不用加/就是当前包目录)
       
      
 
     - 
      
       
      
      
               InputStream mapperInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatisConfig.xml");
       
      
 
     - 
      
       
      
      
               // 生成SqlSession工厂,SqlSession从名字上看就是,跟数据库交互的会话信息,负责将sql提交到数据库进行执行
       
      
 
     - 
      
       
      
      
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(mapperInputStream, "development");
       
      
 
     - 
      
       
      
      
               // 获取Mybatis配置信息,由此来看所有的解析都是在SqlSessionFactoryBuilder进行完成的.
       
      
 
     - 
      
       
      
      
               Configuration configuration = sqlSessionFactory.getConfiguration();
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
    
    
  # 2.3.1 new SqlSessionFactoryBuilder().build
这里可以看到就是核心类就是使用 XMLConfigBuilder 进行解析。下面我们就主要分析 XMLConfigBuilder
    
     - 
      
       
      
      
       
        public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
       
      
 
     - 
      
       
      
      
           try {
       
      
 
     - 
      
       
      
      
             XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
       
      
 
     - 
      
       
      
      
             return build(parser.parse());
       
      
 
     - 
      
       
      
      
       
            } catch (Exception e) {
       
      
 
     - 
      
       
      
      
             throw ExceptionFactory.wrapException("Error building SqlSession.", e);
       
      
 
     - 
      
       
      
      
       
            } finally {
       
      
 
     - 
      
       
      
      
             ErrorContext.instance().reset();
       
      
 
     - 
      
       
      
      
             try {
       
      
 
     - 
      
       
      
      
       
                inputStream.close();
       
      
 
     - 
      
       
      
      
       
              } catch (IOException e) {
       
      
 
     - 
      
       
      
      
               // Intentionally ignore. Prefer previous error.
       
      
 
     - 
      
       
      
      
       
              }
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
     - 
      
       
      
      
       
          }
       
      
 
    
   
    
  # 2.3.2 核心配置类解析(XMLConfigBuilder)
重点关注
- line(8), 我们看到核心解析类是 
XPathParser parser = new XPathParser() - line(17), 标签的解析都在 
parseConfiguration - line(17), 思考下为什么先解析 
propertiesElement(root.evalNode("properties")) 
    
     - 
      
       
      
      
       
        public class XMLConfigBuilder extends BaseBuilder {
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         private boolean parsed;
       
      
 
     - 
      
       
      
      
         private final XPathParser parser;
       
      
 
     - 
      
       
      
      
         private String environment;
       
      
 
     - 
      
       
      
      
         private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
       
      
 
     - 
      
       
      
      
         
       
      
 
     - 
      
       
      
      
       
          public Configuration parse() {
       
      
 
     - 
      
       
      
      
           if (parsed) {
       
      
 
     - 
      
       
      
      
             throw new BuilderException("Each XMLConfigBuilder can only be used once.");
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
     - 
      
       
      
      
       
            parsed = true;
       
      
 
     - 
      
       
      
      
       
            parseConfiguration(parser.evalNode("/configuration"));
       
      
 
     - 
      
       
      
      
           return configuration;
       
      
 
     - 
      
       
      
      
       
          }
       
      
 
     - 
      
       
      
      
         
       
      
 
     - 
      
       
      
      
         private void parseConfiguration(XNode root) {
       
      
 
     - 
      
       
      
      
           try {
       
      
 
     - 
      
       
      
      
             // issue #117 read properties first
       
      
 
     - 
      
       
      
      
       
              propertiesElement(root.evalNode("properties"));
       
      
 
     - 
      
       
      
      
             Properties settings = settingsAsProperties(root.evalNode("settings"));
       
      
 
     - 
      
       
      
      
       
              loadCustomVfs(settings);
       
      
 
     - 
      
       
      
      
       
              loadCustomLogImpl(settings);
       
      
 
     - 
      
       
      
      
       
              typeAliasesElement(root.evalNode("typeAliases"));
       
      
 
     - 
      
       
      
      
       
              pluginElement(root.evalNode("plugins"));
       
      
 
     - 
      
       
      
      
       
              objectFactoryElement(root.evalNode("objectFactory"));
       
      
 
     - 
      
       
      
      
       
              objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
       
      
 
     - 
      
       
      
      
       
              reflectorFactoryElement(root.evalNode("reflectorFactory"));
       
      
 
     - 
      
       
      
      
       
              settingsElement(settings);
       
      
 
     - 
      
       
      
      
             // read it after objectFactory and objectWrapperFactory issue #631
       
      
 
     - 
      
       
      
      
       
              environmentsElement(root.evalNode("environments"));
       
      
 
     - 
      
       
      
      
       
              databaseIdProviderElement(root.evalNode("databaseIdProvider"));
       
      
 
     - 
      
       
      
      
       
              typeHandlerElement(root.evalNode("typeHandlers"));
       
      
 
     - 
      
       
      
      
       
              mapperElement(root.evalNode("mappers"));
       
      
 
     - 
      
       
      
      
       
            } catch (Exception e) {
       
      
 
     - 
      
       
      
      
             throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
     - 
      
       
      
      
       
          }
       
      
 
     - 
      
       
      
      
       
        }  
       
      
 
    
   
    
  看到上面代码是不是就恍然大悟了,原来配置文件的标签都是在这里解析呀。这里的主要思路就是将xml解析成Java对象然后放到 Configuration中。具体任何实现呢? 感兴趣可以自己研究下。
# 2.3.3 Configuration属性介绍
那么这些数据最终哪里会使用呢,我们专门留一片文章, 详细分析。这里先看看Configuration内部都有那些关键的配置类把。
| 属性 | 解释 | 
|---|---|
| TypeAliasRegistry | key是一个别名,value是一个class对象 | 
| Properties variables | 配置文件中占位符的变量配置 | 
| InterceptorChain interceptorChain | 拦截链,用于拦截方法,实现插件 | 
| ObjectFactory objectFactory | 对象实例化统一的工厂方法,我们不用都反射来实例化了 | 
| ObjectWrapperFactory objectWrapperFactory | 包装对象后为其提供统一的属性操作方法。我们不用通过反射来修改对象属性值了 | 
| ReflectorFactory reflectorFactory | 反射工厂,用于生成一个反射信息对象,具有缓存的作用 | 
| Environment environment | 环境信息包含(事务管理器和数据源) | 
| TypeHandlerRegistry typeHandlerRegistry | 主要处理jdbc的返回数据,转换成Java对象 | 
| MapperRegistry mapperRegistry | Mapper生成的处理类,包含代理的逻辑 | 
# 2.3.4 Mapper.xml 解析
XMLMapperBuilder
解析Mapper对应的xml配置文件,这里面包含了sql的信息。
mapper的dtd约束文件更多,可以参考: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#
    
     - 
      
       
      
      
       
        <!-- 映射文件,mybatis精髓, 后面才会细讲 -->
       
      
 
     - 
      
       
      
      
           <mappers>
       
      
 
     - 
      
       
      
      
               <mapper resource="mapper/TUserMapper.xml"/>
       
      
 
     - 
      
       
      
      
           </mappers>
       
      
 
    
    
  这里就要介绍一个重要的类的,MapperBuilderAssistant Mapper构建辅助工具类。
| 属性 | 解释 | 
|---|---|
| MapperBuilderAssistant | Mapper构建辅助工具类(缓存配置) | 
| CacheRefResolver | 决定如何使用缓存 | 
| ParameterMapping | 当sql中使用到了#{}占位符时候,负责填充sql参数 | 
| ResultMapResolver | 返回值映射 | 
| Map<String, XNode> sqlFragments | sql片段 | 
| MappedStatement | Mapper方法的所有信息(出参,入参,及sql信息等) | 
# 2.4 Mybatis可以借鉴的知识点
# 2.4.1 占位符解析逻辑
在第一篇的时候我们说过,从配置文件解析中我们能学会,如果解析占位符。并将占位符填充真实数据。这里我们就具体说下是如何解析。 还记得前面让思考下为什么先解析 propertiesElement(root.evalNode("properties"))。
答案就是为了先读取变量信息,方便后面给依赖的信息,给填充值。
我们直接说答案: 具体谁来做了这个事情,从职责划分上来看,这个其实还是属于xml文件解析。所以是 XPathParser parser XPathParser中填充上变量信息,这样XPathParser在解析的时候会自动将 ${} 填充上真实的数据。
    
     - 
      
       
      
      
       
        // 执行后,会解析properties标签,并且将属性赋值给XPathParser
       
      
 
     - 
      
       
      
      
           propertiesElement(root.evalNode("properties"));
       
      
 
     - 
      
       
      
      
       
            parser.setVariables(defaults);
       
      
 
     - 
      
       
      
      
       
            configuration.setVariables(defaults);
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
           // XPathParser 生成节点时候,属性信息会提前处理。
       
      
 
     - 
      
       
      
      
           public XNode(XPathParser xpathParser, Node node, Properties variables) {
       
      
 
     - 
      
       
      
      
              this.xpathParser = xpathParser;
       
      
 
     - 
      
       
      
      
              this.node = node;
       
      
 
     - 
      
       
      
      
              this.name = node.getNodeName();
       
      
 
     - 
      
       
      
      
              this.variables = variables;
       
      
 
     - 
      
       
      
      
              this.attributes = parseAttributes(node);
       
      
 
     - 
      
       
      
      
              this.body = parseBody(node);
       
      
 
     - 
      
       
      
      
       
             }
       
      
 
     - 
      
       
      
      
            // 发现是占位符,就从变量中读取。
       
      
 
     - 
      
       
      
      
            // ${datasource.driver-class-name} 替换成变量值里面的数据。
       
      
 
     - 
      
       
      
      
            public static String parse(String string, Properties variables) {
       
      
 
     - 
      
       
      
      
              VariableTokenHandler handler = new VariableTokenHandler(variables);
       
      
 
     - 
      
       
      
      
              GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
       
      
 
     - 
      
       
      
      
              return parser.parse(string);
       
      
 
     - 
      
       
      
      
       
             }
       
      
 
    
   
    
  # 2.4.2 Mybatis Resources 工具
可以从配置文件中或者网络中解析配置,生成 Resources 对象
    
     - 
      
       
      
      
       
        String resource = context.getStringAttribute("resource");
       
      
 
     - 
      
       
      
      
             if (resource != null) {
       
      
 
     - 
      
       
      
      
       
                defaults.putAll(Resources.getResourceAsProperties(resource));
       
      
 
     - 
      
       
      
      
       
              } else if (url != null) {
       
      
 
     - 
      
       
      
      
       
                defaults.putAll(Resources.getUrlAsProperties(url));
       
      
 
     - 
      
       
      
      
       
              }
       
      
 
     - 
      
       
      
      
       
              parser.setVariables(defaults);
       
      
 
     - 
      
       
      
      
       
              configuration.setVariables(defaults);
       
      
 
     - 
      
       
      
      
             
       
      
 
     - 
      
       
      
      
             // 从资源中获取流
       
      
 
     - 
      
       
      
      
             InputStream inputStream = Resources.getResourceAsStream(resource)
       
      
 
     - 
      
       
      
      
             // 从url中获取流
       
      
 
     - 
      
       
      
      
             InputStream inputStream = Resources.getUrlAsStream(url)
       
      
 
    
    
  # 2.4.3 Mybatis PropertyParser 占位符解析
    
     - 
      
       
      
      
       
        @Test
       
      
 
     - 
      
       
      
      
           public void propertyParser() {
       
      
 
     - 
      
       
      
      
       
                Properties variables = new Properties();
       
      
 
     - 
      
       
      
      
       
                variables.put("datasource.driver-class-name", "com.mysql.cj.jdbc.Driver");
       
      
 
     - 
      
       
      
      
               // 变量中有就从变量中获取 参数信息: com.mysql.cj.jdbc.Driver
       
      
 
     - 
      
       
      
      
       
                System.out.println(PropertyParser.parse("参数信息: ${datasource.driver-class-name}", variables));
       
      
 
     - 
      
       
      
      
               // 变量中没有就直接返回key datasource.url
       
      
 
     - 
      
       
      
      
       
                System.out.println(PropertyParser.parse("datasource.url", variables));
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
    
    
  # 2.4.4 反射工厂 ReflectorFactory
在Mybatis中使用到的反射地方蛮多的,那么都知道反射是相对比较耗时间,那么我们来看Mybatis是如何利用反射工厂来提高反射的性能的?
缓存,对要使用的Class类,做反射并保存起来, 生成的对象是 Reflector。
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    
     - 
      
       
      
      
       
        public interface ReflectorFactory {
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         boolean isClassCacheEnabled();
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         void setClassCacheEnabled(boolean classCacheEnabled);
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         Reflector findForClass(Class<?> type);
       
      
 
     - 
      
       
      
      
       
        }
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
       
        public class Reflector {
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         private final Class<?> type;
       
      
 
     - 
      
       
      
      
         private final String[] readablePropertyNames;
       
      
 
     - 
      
       
      
      
         private final String[] writablePropertyNames;
       
      
 
     - 
      
       
      
      
         private final Map<String, Invoker> setMethods = new HashMap<>();
       
      
 
     - 
      
       
      
      
         private final Map<String, Invoker> getMethods = new HashMap<>();
       
      
 
     - 
      
       
      
      
         private final Map<String, Class<?>> setTypes = new HashMap<>();
       
      
 
     - 
      
       
      
      
         private final Map<String, Class<?>> getTypes = new HashMap<>();
       
      
 
     - 
      
       
      
      
         private Constructor<?> defaultConstructor;
       
      
 
     - 
      
       
      
      
        
       
      
 
     - 
      
       
      
      
         private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
       
      
 
     - 
      
       
      
      
       
        }
       
      
 
    
   
    
  
    
     - 
      
       
      
      
       
        @Test
       
      
 
     - 
      
       
      
      
           public void reflector() throws Exception {
       
      
 
     - 
      
       
      
      
       
                ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
       
      
 
     - 
      
       
      
      
       
                Reflector forClass = reflectorFactory.findForClass(TUser.class);
       
      
 
     - 
      
       
      
      
       
                TUser user = (TUser) forClass.getDefaultConstructor().newInstance();
       
      
 
     - 
      
       
      
      
       
                forClass.getSetInvoker("uid").invoke(user, new Object[]{1});
       
      
 
     - 
      
       
      
      
       
                forClass.getSetInvoker("name").invoke(user, new Object[]{"孙悟空"});
       
      
 
     - 
      
       
      
      
       
                forClass.getSetInvoker("tokenId").invoke(user, new Object[]{"tokenId"});
       
      
 
     - 
      
       
      
      
               // 1
       
      
 
     - 
      
       
      
      
       
                System.out.println(forClass.getGetInvoker("uid").invoke(user, new Object[]{}));
       
      
 
     - 
      
       
      
      
               // 孙悟空
       
      
 
     - 
      
       
      
      
       
                System.out.println(forClass.getGetInvoker("name").invoke(user, new Object[]{}));
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
    
    
  # 2.4.5 异常上下文设计 ErrorContext
- 在代码执行的过程中,将关键信息通过 
ErrorContext.instance().message()保存进去。利用到了线程隔离的知识。 ErrorContext.instance()是利用ThreadLocal进行线程隔离。- 异常打印后,进行 
reset重置。 
    
     - 
      
       
      
      
       
        public int update(String statement, Object parameter) {
       
      
 
     - 
      
       
      
      
           try {
       
      
 
     - 
      
       
      
      
       
              dirty = true;
       
      
 
     - 
      
       
      
      
             MappedStatement ms = configuration.getMappedStatement(statement);
       
      
 
     - 
      
       
      
      
             return executor.update(ms, wrapCollection(parameter));
       
      
 
     - 
      
       
      
      
       
            } catch (Exception e) {
       
      
 
     - 
      
       
      
      
             throw wrapException("Error updating database. Cause: " + e, e);
       
      
 
     - 
      
       
      
      
       
            } finally {
       
      
 
     - 
      
       
      
      
             // 完成之后异常上下文进行重置
       
      
 
     - 
      
       
      
      
             ErrorContext.instance().reset();
       
      
 
     - 
      
       
      
      
       
            }
       
      
 
     - 
      
       
      
      
       
          }
       
      
 
     - 
      
       
      
      
         
       
      
 
     - 
      
       
      
      
         // 将异常上线文中报错的错误都打印出来。
       
      
 
     - 
      
       
      
      
         public static RuntimeException wrapException(String message, Exception e) {
       
      
 
     - 
      
       
      
      
           return new PersistenceException(ErrorContext.instance().message(message).cause(e).toString(), e);
       
      
 
     - 
      
       
      
      
       
          }
       
      
 
    
   
    
  文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。
原文链接:springlearn.blog.csdn.net/article/details/125858037
- 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)