7.4 常用的工具类 - MetaObject
在编写插件之前我们需要去学习一个 MyBatis 的工具类 - MetaObject,它可以有效读取或者修改一些重要对象的属性。在 MyBatis 中,四大对象给我们提供的 public 设置参数的方法很少,我们难以通过其自身得到相关的属性信息,但是有了 MetaObject 这个工具类我们就可以通过其他的技术手段来读取或者修改这些重要对象的属性。在 MyBatis 插件中它是一个十分常用的工具类。
它有 3 个方法常常被我们用到。
MetaObject forObject(Object object、ObjectFactory objectFactory、ObjectWrapper Factory objectWrapperFactory)方法用于包装对象。这个方法我们已经不再使用了,而是用 MyBatis 为我们提供的 SystemMetaObject.forObject(Object obj)。
Object getValue(String name)方法用于获取对象属性值,支持 OGNL。
void setValue(String name、Object value)方法用于修改对象属性值,支持 OGNL。
在 MyBatis 对象中大量使用了这个类进行包装,包括四大对象,使得我们可以通过它来给四大对象的某些属性赋值从而满足我们的需要。
例如,拦截 StatementHandler 对象,我们需要先获取它要执行的 SQL 修改它的一些值。这时候我们可以使用 MetaObject,它为我们提供了如代码清单 7-8 所示的方法。
代码清单 7-8:在插件下修改运行参数
StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = SystemMetaObject.forObject (statementHandler); //进行绑定 // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过循环可以分离出最原始的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = SystemMetaObject.forObject(object); } //BoundSql 对象是处理 SQL 语句用的 String sql = (String)metaStatementHandler.getValue ("delegate. boundSql. sql"); //判断 SQL 是否是 select 语句,如果不是 select 语句,那么就出错了 //如果是,则修改它,最多返回 1000 行,这里用的是 MySQL 数据库,其他数据库要改写成其他 if (sql != null && sql.toLowerCase().trim().indexOf("select") == 0) { //通过 SQL 重写来实现,这里我们起了一个奇怪的别名,避免与表名重复 sql = "select * from (" + sql + ") $_$limit_$table_ limit 1000"; metaStatementHandler.setValue("delegate.boundSql.sql", sql); }
从第 6 章可以知道我们拦截的 StatementHandler 实际是 RoutingStatementHandler 对象,它的 delegate 属性才是真实服务的 StatementHandler,真实的 StatementHandler 有一个属性 BoundSql,它下面又有一个属性 sql。所以才有了路径 delegate.boundSql.sql。我们就可以通过这个路径去获取或者修改对应运行时的 SQL。通过这样的改写,就可以限制所有查询的 SQL 都只能至多返回 1000 行记录。
由此可见,我们必须掌握好 6.2.2 节关于映射器解析的内容,才能准确的在插件中使用这个类,来获取或改变 MyBatis 内部对象的一些重要的属性值,这对编写插件是非常重要的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论