关于Mybatis的研究之 bean没有set方法 也可以赋值
2018-02-01 23:20
459 查看
在学习mybatis的时候,发现了一个有趣的现象
如果resultType所指向的bean没有set方法时 在ibatis上是不能成功并且报错误 但在mybatis却是可以的
bean类:
![](https://img-blog.csdn.net/20131003154741718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXJvbmxlZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
sqlmap如下:
![](https://img-blog.csdn.net/20131003155017968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXJvbmxlZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
测试类代码如下:
[java] view
plain copy
@Test
public void testNewTable() throws IOException{
String resource = "sqlMap_config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(reader);
SqlSession session = factory.openSession();
List<User> list = session.selectList("NewTable.selectAll");
System.out.println( list.get(0) );
}
这样User类的属性居然是有值的!!!!
这着实让我很诧异 在排除了是我操作的问题的情况下,最终的造成此现象的根源在于mybatis本身。
于是我有了想看mybatis源码的冲动。。。。
2.分析问题
说实话,这是我第一次正儿八经的看框架源码。
一个字:杂啊!!!
但杂而不乱,我debug了好久才找到了根源
类SetFieldInvoke
[java] view
plain copy
public class SetFieldInvoker implements Invoker {
private Field field;
public SetFieldInvoker(Field field) {
this.field = field;
}
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
field.set(target, args[0]);
return null;
}
public Class<?> getType() {
return field.getType();
}
}
[java] view
plain copy
field.set(target, args[0]);
原来它利用的是反射原理直接操作属性而非set方法
但有一个问题出现了 User类中的属性都是private的。如果 Field 类中没有setAccessible(true)的话,是不会访问到私有属性的。
在SetFieldInvoke方法中并没有执行此方法啊,但结果确实是给私有属性赋值了。
可以说明一点是setAccessible(true)此方法 肯定是执行了。
剩下的问题是此方法在哪里执行了??
于是我搜索文本setAccessible(true)
果然在org.apache.ibatis.reflection.Reflector 中 发现了此方法在调用
[java] view
plain copy
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
if (!setMethods.containsKey(field.getName())) {
// issue 379 - removed the check for final because JDK 1.5 allows
// modification of final fields through reflection (JSR-133). (JGB)
addSetField(field);
}
if (!getMethods.containsKey(field.getName())) {
addGetField(field);
}
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
简单来说,就是在初始化的时候就将每个属性都setAccessible(true)了
说明一点就是mybaits 的result结果集的映射用的是暴力反射 直接赋值;
如果resultType所指向的bean没有set方法时 在ibatis上是不能成功并且报错误 但在mybatis却是可以的
bean类:
sqlmap如下:
测试类代码如下:
[java] view
plain copy
@Test
public void testNewTable() throws IOException{
String resource = "sqlMap_config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(reader);
SqlSession session = factory.openSession();
List<User> list = session.selectList("NewTable.selectAll");
System.out.println( list.get(0) );
}
这样User类的属性居然是有值的!!!!
这着实让我很诧异 在排除了是我操作的问题的情况下,最终的造成此现象的根源在于mybatis本身。
于是我有了想看mybatis源码的冲动。。。。
2.分析问题
说实话,这是我第一次正儿八经的看框架源码。
一个字:杂啊!!!
但杂而不乱,我debug了好久才找到了根源
类SetFieldInvoke
[java] view
plain copy
public class SetFieldInvoker implements Invoker {
private Field field;
public SetFieldInvoker(Field field) {
this.field = field;
}
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
field.set(target, args[0]);
return null;
}
public Class<?> getType() {
return field.getType();
}
}
[java] view
plain copy
field.set(target, args[0]);
原来它利用的是反射原理直接操作属性而非set方法
但有一个问题出现了 User类中的属性都是private的。如果 Field 类中没有setAccessible(true)的话,是不会访问到私有属性的。
在SetFieldInvoke方法中并没有执行此方法啊,但结果确实是给私有属性赋值了。
可以说明一点是setAccessible(true)此方法 肯定是执行了。
剩下的问题是此方法在哪里执行了??
于是我搜索文本setAccessible(true)
果然在org.apache.ibatis.reflection.Reflector 中 发现了此方法在调用
[java] view
plain copy
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
if (!setMethods.containsKey(field.getName())) {
// issue 379 - removed the check for final because JDK 1.5 allows
// modification of final fields through reflection (JSR-133). (JGB)
addSetField(field);
}
if (!getMethods.containsKey(field.getName())) {
addGetField(field);
}
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
简单来说,就是在初始化的时候就将每个属性都setAccessible(true)了
说明一点就是mybaits 的result结果集的映射用的是暴力反射 直接赋值;
相关文章推荐
- 关于Mybatis的研究之 bean没有set方法 也可以赋值
- 关于Mybatis的研究之 bean没有set方法 也可以赋值
- 关于Java中的构造方法和set方法()给属性赋值
- 反射给没有set方法的属性赋值
- 关于struts2 中action 属性没有 set 方法 依然会注入值的问题(解决)
- 关于Enum枚举类没有values()方法却可以在枚举类中使用的问题
- 反射给没有set方法的属性赋值
- 利用运行时,给UIImageView写一个分类,交换里面的setImage的方法,可以重绘图片,提高内存的利用率(要是没有重绘图片,直接使用系统提供的setImag就会造成占用大量的内存问题)
- 关于mybatis的关联查询中id错误赋值的解决方法
- 关于:安全研究人员发现新木马 可以隐蔽ICMP协议传数据
- 关于接口中语言不同,用的方法可以试着换下
- 关于mybatis的动态if语句查询报错问题和解决方法
- Android中关于setLatestEventInfo()过时以及构建Notification的解决方法
- 判断Set里的元素是否重复、==、equals、hashCode方法研究-代码演示
- 关于在一个页面去finish其他的页面,也可以调用其他页面的方法
- windows下简单的调用Setforegroundwindow并不能将窗口置最前,我找到三种方法可以实现该功能。
- 关于JSF应用程序生命周期与Creator2阶段方法的深入研究
- 【搬家】关于有 “1 个软件包没有被完全安装或卸载”问题的解决方法
- 在MYSQL里没有数组,但find_in_set()可以充当
- 反射应用实例--根据map中的值创建对应并调用set方法给域赋值