当前位置: 首页 > news >正文

广州网站建设一般多少钱比较好的做淘客网站

广州网站建设一般多少钱,比较好的做淘客网站,工程网站开发,中国建设银行网站网上银行反射是 Java 世界中非常强大、非常灵活的一种机制。在面向对象的 Java 语言中#xff0c;我们只能按照 public、private 等关键字的规范去访问一个 Java 对象的属性和方法#xff0c;但反射机制可以让我们在运行时拿到任何 Java 对象的属性或方法。 有人说反射打破了类的封装…反射是 Java 世界中非常强大、非常灵活的一种机制。在面向对象的 Java 语言中我们只能按照 public、private 等关键字的规范去访问一个 Java 对象的属性和方法但反射机制可以让我们在运行时拿到任何 Java 对象的属性或方法。 有人说反射打破了类的封装性破坏了我们的面向对象思维我倒不这么认为。我觉得正是由于 Java 的反射机制解决了很多面向对象无法解决的问题才受到众多 Java 开源框架的青睐也出现了有很多惊艳的反射实践当然这也包括 MyBatis 中的反射工具箱。 凡事都有两面性越是灵活、越是强大的工具用起来的门槛就越高反射亦如此。这也是写业务代码时很少用到反射的原因。反过来说如果必须要用反射解决业务问题的时候就需要停下来思考我们的系统设计是不是有问题了。 为了降低反射使用门槛MyBatis 内部封装了一个反射工具箱其中包含了 MyBatis 自身常用的反射操作MyBatis 其他模块只需要调用反射工具箱暴露的简洁 API 即可实现想要的反射功能。 反射工具箱的具体代码实现位于 org.apache.ibatis.reflection 包中下面我就带你一起深入分析该模块的核心实现。 Reflector Reflector 是 MyBatis 反射模块的基础。要使用反射模块操作一个 Class都会先将该 Class 封装成一个 Reflector 对象在 Reflector 中缓存 Class 的元数据信息这可以提高反射执行的效率。 1. 核心初始化流程 既然是涉及反射操作Reflector 必然要管理类的属性和方法这些信息都记录在它的核心字段中具体情况如下所示。 typeClass? 类型该 Reflector 对象封装的 Class 类型。 readablePropertyNames、writablePropertyNamesString[] 类型可读、可写属性的名称集合。 getMethods、setMethodsMapString, Invoker 类型可读、可写属性对应的 getter 方法和 setter 方法集合key 是属性的名称value 是一个 Invoker 对象。Invoker 是对 Method 对象的封装。 getTypes、setTypesMapString, Class? 类型属性对应的 getter 方法返回值以及 setter 方法的参数值类型key 是属性名称value 是方法的返回值类型或参数类型。 defaultConstructorConstructor? 类型默认构造方法。 caseInsensitivePropertyMapMapString, String 类型所有属性名称的集合记录到这个集合中的属性名称都是大写的。 在我们构造一个 Reflector 对象的时候传入一个 Class 对象通过解析这个 Class 对象即可填充上述核心字段整个核心流程大致可描述为如下。 用 type 字段记录传入的 Class 对象。 通过反射拿到 Class 类的全部构造方法并进行遍历过滤得到唯一的无参构造方法来初始化 defaultConstructor 字段。这部分逻辑在 addDefaultConstructor() 方法中实现。 读取 Class 类中的 getter方法填充上面介绍的 getMethods 集合和 getTypes 集合。这部分逻辑在 addGetMethods() 方法中实现。 读取 Class 类中的 setter 方法填充上面介绍的 setMethods 集合和 setTypes 集合。这部分逻辑在 addSetMethods() 方法中实现。 读取 Class 中没有 getter/setter 方法的字段生成对应的 Invoker 对象填充 getMethods 集合、getTypes 集合以及 setMethods 集合、setTypes 集合。这部分逻辑在 addFields() 方法中实现。 根据前面三步构造的 getMethods/setMethods 集合的 keySet初始化 readablePropertyNames、writablePropertyNames 集合。 遍历构造的 readablePropertyNames、writablePropertyNames 集合将其中的属性名称全部转化成大写并记录到 caseInsensitivePropertyMap 集合中。 2. 核心方法解析 了解了初始化的核心流程之后我们再继续深入分析其中涉及的方法这些方法也是 Reflector 的核心方法。 首先来看 addGetMethods() 方法和 addSetMethods() 方法它们分别用来解析传入 Class 类中的 getter方法和 setter() 方法两者的逻辑十分相似。这里我们就以 addGetMethods() 方法为例深入分析其主要包括如下三个核心步骤。 第一步获取方法信息。 这里会调用 getClassMethods() 方法获取当前 Class 类的所有方法的唯一签名注意一下这里同时包含继承自父类以及接口的方法以及每个方法对应的 Method 对象。 在递归扫描父类以及父接口的过程中会使用 MapString, Method 集合记录遍历到的方法实现去重的效果其中 Key 是对应的方法签名Value 为方法对应的 Method 对象。生成的方法签名的格式如下 返回值类型#方法名称:参数类型列表例如addGetMethods(Class) 方法的唯一签名是 java.lang.String#addGetMethods:java.lang.Class可见这里生成的方法签名是包含返回值的可以作为该方法全局唯一的标识。 第二步按照 Java 的规范从上一步返回的 Method 数组中查找 getter 方法将其记录到 conflictingGetters 集合中。这里的 conflictingGetters 集合HashMapString, List()类型中的 Key 为属性名称Value 是该属性对应的 getter 方法集合。 为什么一个属性会查找到多个 getter 方法呢这主要是由于类间继承导致的在子类中我们可以覆盖父类的方法覆盖不仅可以修改方法的具体实现还可以修改方法的返回值getter 方法也不例外这就导致在第一步中产生了两个签名不同的方法。 第三步解决方法签名冲突。 这里会调用 resolveGetterConflicts() 方法对这种 getter 方法的冲突进行处理处理冲突的核心逻辑其实就是比较 getter 方法的返回值优先选择返回值为子类的 getter 方法例如 // 该方法定义在SuperClazz类中 public List getA(); // 该方法定义在SubClazz类中SubClazz继承了SuperClazz类 public ArrayList getA();可以看到SubClazz.getA() 方法的返回值 ArrayList 是其父类 SuperClazz 中 getA() 方法返回值 List 的子类所以这里选择 SubClazz 中定义的 getA() 方法作为 A 这个属性的 getter 方法。 在 resolveGetterConflicts() 方法处理完上述 getter 方法冲突之后会为每个 getter 方法创建对应的 MethodInvoker 对象然后统一保存到 getMethods 集合中。同时还会在 getTypes 集合中维护属性名称与对应 getter 方法返回值类型的映射。 到这里了addGetMethods() 的核心逻辑就分析清楚了。 我们接下来回到 Reflector 的构造方法中在通过 addGetMethods() 和 addSetMethods() 方法完成 Class 类中 getter/setter 方法的处理之后会继续调用 addFields() 方法处理没有 getter/setter 方法的字段。 这里我们以处理没有 getter 方法的字段为例addFields() 方法会为这些字段生成对应的 GetFieldInvoker 对象并记录到 getMethods 集合中同时也会将属性名称和属性类型记录到 getTypes 集合中。处理没有 setter 方法的字段也是相同的逻辑。 3. Invoker 在 Reflector 对象的初始化过程中所有属性的 getter/setter 方法都会被封装成 MethodInvoker 对象没有 getter/setter 的字段也会生成对应的 Get/SetFieldInvoker 对象。下面我们就来看看这个 Invoker 接口的定义 public interface Invoker {// 调用底层封装的Method方法或是读写指定的字段Object invoke(Object target, Object[] args);Class? getType(); // 返回属性的类型 }Invoker 接口的继承关系如下图所示 Invoker 接口继承关系图 其中MethodInvoker 是通过反射方式执行底层封装的 Method 方法例如getter/setter 方法完成属性读写效果的Get/SetFieldInvoker 是通过反射方式读写底层封装的 Field 字段进而实现属性读写效果的。 4. ReflectorFactory 通过上面的分析我们知道Reflector 初始化过程会有一系列的反射操作为了提升 Reflector 的初始化速度MyBatis 提供了 ReflectorFactory 这个工厂接口对 Reflector 对象进行缓存其中最核心的方法是用来获取 Reflector 对象的 findForClass() 方法。 DefaultReflectorFactory 是 ReflectorFactory 接口的默认实现它默认会在内存中维护一个 ConcurrentHashMapClass?, Reflector 集合reflectorMap 字段缓存其创建的所有 Reflector 对象。 在其 findForClass() 方法实现中首先会根据传入的 Class 类查询 reflectorMap 缓存如果查找到对应的 Reflector 对象则直接返回否则创建相应的 Reflector 对象并记录到 reflectorMap 中缓存等待下次使用。 默认对象工厂 ObjectFactory 是 MyBatis 中的反射工厂其中提供了两个 create() 方法的重载我们可以通过两个 create() 方法创建指定类型的对象。 DefaultObjectFactory 是 ObjectFactory 接口的默认实现其 create() 方法底层是通过调用 instantiateClass() 方法创建对象的。instantiateClass() 方法会通过反射的方式根据传入的参数列表选择合适的构造函数实例化对象。 除了使用 DefaultObjectFactory 这个默认实现之外我们还可以在 mybatis-config.xml 配置文件中配置自定义 ObjectFactory 接口扩展实现 类在 MyBatis 提供的测试类中就包含了自定义的 ObjectFactory 实现可以参考我们的源码完成自定义的功能扩展。 属性解析工具 在前面《02 | 订单系统持久层示例分析20 分钟带你快速上手 MyBatis》介绍的订单系统示例中我们在 orderMap 这个 ResultMap 映射中如果要配置 Order 与 OrderItem 的一对多关系可以使用 collection 标签进行配置如果 OrderItem 个数明确可以直接使用数组下标索引方式即 ordersItems[0]填充 orderItems 集合。 这里的 “.” 导航以及数组下标的解析也都是在反射工具箱中完成的。下面我们就来介绍 reflection.property 包下的三个属性解析相关的工具类在后面的 MetaClass、MetaObject 等工具类中也都需要属性解析能力。 PropertyTokenizer 工具类负责解析由“.”和“[]”构成的表达式。PropertyTokenizer 继承了 Iterator 接口可以迭代处理嵌套多层表达式。 PropertyCopier 是一个属性拷贝的工具类提供了与 Spring 中 BeanUtils.copyProperties() 类似的功能实现相同类型的两个对象之间的属性值拷贝其核心方法是 copyBeanProperties() 方法。 PropertyNamer 工具类提供的功能是转换方法名到属性名以及检测一个方法名是否为 getter 或 setter 方法。 MetaClass MetaClass 提供了获取类中属性描述信息的功能底层依赖前面介绍的 Reflector在 MetaClass 的构造方法中会将传入的 Class 封装成一个 Reflector 对象并记录到 reflector 字段中MetaClass 的后续属性查找都会使用到该 Reflector 对象。 MetaClass 中的 findProperty() 方法是实现属性查找的核心方法它主要处理了“.”导航的属性查找该方法会用前文介绍的 PropertyTokenizer 解析传入的 name 表达式该表达式可能通过“.”导航多层例如order.deliveryAddress.customer.name。 MetaClass 会逐层处理这个表达式首先通过 Order 类型对应的 Reflector 查找 deliveryAddress 属性查找成功之后根据 deliveryAddress 属性的类型即 Address 类型创建对应的 MetaClass 对象以及底层的 Reflector 对象再继续查找其中的 customer 属性如此递归处理直至最后查找到 Customer 中的 name 属性。这部分递归查找逻辑位于 MetaClass.buildProperty() 方法中。 在上述 MetaClass 查找属性的过程中还会调用 hasGetter() 和 hasSetter() 方法负责判断属性表达式中指定的属性是否有对应的 getter/setter 方法。这两个方法也是先通过 PropertyTokenizer 解析传入的 name 表达式然后进行递归查询在递归查询中会依赖 Reflector.hasGetter() 方法查找前文介绍的 getMethods 集合或 setMethods 集合查找属性对应的 getter/setter 方法。 MetaClass 中的其他方法实现也都大多是依赖 PropertyTokenizer 解析表达式然后递归查找查找过程会依赖 Reflector 的相关方法。 ObjectWrapper MetaClass 中封装的是 Class 元信息ObjectWrapper 封装的则是对象元信息。在 ObjectWrapper 中抽象了一个对象的属性信息并提供了查询对象属性信息的相关方法以及更新属性值的相关方法。 ObjectWrapper 的实现类如下图所示 ObjectWrapper 继承关系图 BaseWrapper 是 ObjectWrapper 接口的抽象实现其中只有一个 MetaObject 类型的字段。BaseWrapper 为子类实现了 resolveCollection()、getCollectionValue() 和 setCollectionValue() 三个针对集合对象的处理方法。其中resolveCollection() 方法会将指定属性作为集合对象返回底层依赖 MetaObject.getValue()方法实现后面还会详细介绍。getCollectionValue() 方法和 setCollectionValue() 方法会解析属性表达式的下标信息然后获取/设置集合中的对应元素这里解析属性表达式依然是依赖前面介绍的 PropertyTokenizer 工具类。 BeanWrapper 继承了 BaseWrapper 抽象类底层除了封装了一个 JavaBean 对象之外还封装了该 JavaBean 类型对应的 MetaClass 对象以及从 BaseWrapper 继承下来的 MetaObject 对象。 在 get() 方法和 set() 方法实现中BeanWrapper 会根据传入的属性表达式获取/设置相应的属性值。以 get() 方法为例首先会判断表达式中是否含有数组下标如果含有下标会通过 resolveCollection() 和 getCollectionValue() 方法从集合中获取相应元素如果不包含下标则通过 MetaClass 查找属性名称在 Reflector.getMethods 集合中相应的 GetFieldInvoker然后调用 Invoker.invoke() 方法读取属性值。 BeanWrapper 中其他方法的实现也大都与 get() 方法和 set() 方法类似依赖 MetaClass、MetaObject 完成相关对象中属性信息读写这里就不再一一介绍你若感兴趣的话可以参考源码进行学习。 CollectionWrapper 是 ObjectWrapper 接口针对 Collection 集合的一个实现其中封装了CollectionObject 集合对象只有 isCollection()、add()、addAll() 方法以及从 BaseWrapper 继承下来的方法是可用的其他方法都会抛出 UnsupportedOperationException 异常。 MapWrapper 是针对 Map 类型的一个实现这个实现就比较简单了所以我就留给你自己去分析了分析过程中可以参考下面将要介绍的 MetaObject。 MetaObject 通过对 ObjectWrapper 的介绍我们了解到ObjectWrapper 实现了读写对象属性值、检测getter/setter 等基础功能在分析 BeanWrapper 等实现类时我们可以看到其底层会依赖 MetaObject。在 MetaObject 中维护了一个 originalObject 字段指向被封装的 JavaBean 对象还维护了该 JavaBean 对象对应的 ObjectWrapper 对象objectWrapper 字段。 MetaObject 和 ObjectWrapper 中关于类级别的方法例如hasGetter() 方法、hasSetter() 方法、findProperty() 方法等都是直接调用 MetaClass 或 ObjectWrapper 的对应方法实现的。其他关于对象级别的方法都是与 ObjectWrapper 配合实现例如 MetaObject.getValue()/setValue() 方法等。 这里以 getValue() 方法为例该方法首先根据 PropertyTokenizer 解析指定的属性表达式如果该表达式是包含“.”导航的多级属性查询则获取子表达式并为其对应的属性对象创建关联的 MetaObject 对象继续递归调用 getValue() 方法直至递归处理结束递归出口会调用 ObjectWrapper.get() 方法获取最终的属性值。 在 MetaObject 中setValue() 方法的核心逻辑与 getValue() 方法基本类似也是递归查找。但是其中有一个不同之处需要你注意如果需要设置的最终属性值不为空时在递归查找 setter() 方法的过程中会调用 ObjectWrapper.instantiatePropertyValue() 方法初始化递归过程中碰到的任意空对象但如果碰到为空的集合元素则无法通过该方法初始化。ObjectWrapper.instantiatePropertyValue() 方法实际上是依赖 ObjectFactory 接口的 create()方法默认实现是 DefaultObjectFactory 创建相应类型的对象。 了解了 MetaObject 和 BeanWrapper 配合使用的方式以及递归查找属性表达式指定的属性值的逻辑之后MetaObject 剩余方法的实现就比较好分析了这里我也就不再赘述了。 总结 这一讲我们重点介绍了 MyBatis 中的反射工具箱。首先我们介绍了反射工具箱中最核心、最底层的 Reflector 类的核心实现接下来介绍了反射工具箱在 Reflector 基础之上提供的各种工具类其中包括 ObjectFactory 工厂类、ObjectWrapper 包装类以及记录元数据的 MetaClass、MetaObject 等。
http://www.dnsts.com.cn/news/126462.html

相关文章:

  • 搭建科技网站价格视频拍摄教程
  • 淄博网站制作首选专家凡科快图电脑版
  • 建站免费平台阿里云外贸建站
  • 集团网站定制文件夹里内容做网站的分类
  • 东莞企业网站推广宁波江北网站建设
  • 上海做家教去哪个网站网站广告psd
  • 汽车门户网站建设宝塔 wordpress
  • 做网站需要会语言吗东莞路桥投资发展有限公司
  • logopond设计网站做网站维护学什么编程语言
  • 手机网站案列十大外贸平台
  • 海南网站搭建2022年新项目加盟代理
  • 手机网站用什么软件开发做商城网站哪家好
  • 淘宝天猫优惠券网站建设费用wordpress评测
  • 网站首页图怎么做上海自助建网站
  • 邢台营销型网站建设昌平上门做网站那
  • 网上营销网站企业网站建设销售前景
  • 南昌市建设监督网站站长如何写app程序
  • 龙华城市建设局网站将网站保存怎么做
  • 网站建设人员求职信中国房地产网站
  • 无锡网站建设 微信免费发布信息平台网
  • 铁路项目建设 网站龙斗seo博客
  • 做3d地形比较好的网站科技公司网站设
  • 做网站的学什么代码个人网站网页设计模板
  • 网站设计和网页设计微信平板版官网下载
  • 怎么做律所的官方网站国外域名注册哪家比较好
  • 公司网站的服务器宁波网络营销推广咨询报价
  • 没有公司可以注册网站吗wordpress异步加载插件
  • 为什么有网网站打不开怎么回事国发网站建设
  • 网站建设的优点wordpress加dz
  • 网站怎么做成手机版常见的网络营销平台有哪些