2.反射的作用反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够知道这个类的所以属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。
我们通过案例来了解,反射的作用,都说实践出真理,操作一遍理解更深刻。
案例:对集合数组进行拆分批量调用持久层对象进行批量插入,当使用的类只有一个的时候可能简单写法,不用反射会更简单,都是我可能有多个类,类的方法可能有批量删除,批量插入,批量更新等操作时我们就需要写很多重复的代码,只有我们使用反射原理来实现,写个工具类,通过传递不同的对象和方法实现上面的操作.
我们创建UserPojo实体类:
public class UserPojo {
public String name;
public String sex;
public int age;
//get/set 和 toString 省略
}
创建持久层保持类UserDao:
public class UserDao {
public static void getUserInfo(List userPojos){
System.out.println("---------批量调用分界线--------");
userPojos.forEach(userPojo -> {
//打印每个用户信息
System.out.println(userPojo.toString());
});
//将来这里肯定是调用一个对象然后通过mybatis方式批量插入数据库中
}
public static void getUserUser(List userPojos){
System.out.println("---------批量调用分界线--------");
userPojos.forEach(userPojo -> {
//打印每个用户信息
System.out.println(userPojo.getName());
});
}
}
用于反射的工具类方法
其中方法的最后一个参数是可以传递多个参数类型的通过runObject.getMethod方法获取对象的一个具体的方法,通过method.invoke方法进行反射操作,调用Class下的newInstance( )静态方法来实例化对象以便操作
public static void splitTraversalCall (List> collectionParameter, Integer step, Class>runObject, String methodName, Class>...parameterType){
int m=collectionParameter.size()/step;
for (int i = 0; i <=m; i++) {
int begin=i*step;
int end=(begin+step)
测试方法的可用性
public class UserService {
public static void main(String[] args) {
//需要批量插入的集合
List userPojoList=new ArrayList<>();
//模拟需要插入的10个用户, 我们需要
for (int i = 0; i < 10; i++) {
UserPojo user=new UserPojo();
user.setName("张"+i);
user.setAge(20+i);
user.setSex("男");
userPojoList.add(user);
}
//使用批量分割集合调用方法
ItmeiUtil.splitTraversalCall(userPojoList,4, UserDao.class,"getUserInfo",List.class);
}
}
可以看出已经批量打印出来,以后可以把持久层方法写成调用mybatis的批量插入方法
好像到这里你还会想这么麻烦为什么不直接调用对象的方法来的直接,就是因为我之前就是在每一个方法里面写最简单的遍历插入,太麻烦了按照之前说的一个类如果至少有三个批量我就要写好多这样重复的代码不美观又麻烦,所以才会想着怎么优化才写的这篇文章.
现在我们在调用同一个类不同的批量方法:getUserUser打印集合名称
现在又有一个类是商品信息的
public class GoodsInfo {
public String goodName;
public Long barCode;
public Integer amount;
//get/set 和 toString 省略
}
之后肯定有需要把商品信息保存到库中,那意味着会有持久层,也可能有批量插入商品表,如果还要使用批量插入你是不是可以想到前面的批量分割反射调用方法呢!!!
创建一个GoodInfoDao类
public class GoodInfoDao {
public static void saveGoodInfoDao(List goodInfos){
System.out.println("---------批量调用分界线--------");
goodInfos.forEach(goodInfo -> {
//将来这里肯定是调用一个对象然后通过mybatis方式批量插入数据库中
//打印每个用户信息
System.out.println(goodInfo.toString());
});
}
}
测试不同对象使用反射方法实现对应的方法
运行可以看出通过反射调用不同的方法可以重复使用
3.Spring中使用出现的问题
需要注意的是在Spring项目中不能使用前面写的工具类,着就是一个坑,遇到一个坑就要解决下个坑[手动滑稽],后面把写好的方法在spring项目使用会报错,因为我们使用这个runObject.newInstance(),由于spring会管理已经注册的对象,但是你使用newInstance相当于重新注册了一个对象,脱离了spring的管理,这样会导致反射方法里面使用spring对象会报空指针.
spring中场景还原
debug展示查看
报空指针异常
4.解决方法:
method.invoke中传入的对象必须是Spring管理的对象
我们需要创建一个工具类来获取spring的IOC容器对象
工具类的名称随意都是要实现ApplicationContextAware接口获取上下文,重写类的方法setApplicationContext记得在这个工具类里面添加Component注解当作配置类注入spring中
重写一下方法,然后在里面创建一个方法传入容器名称,用来获取bean对象
在改造一下工具类的方法:
public static void splitTraversalCallSpring (List> collectionParameter, Integer step, Class>runObject,String beanName, String methodName, Class>...parameterType){
if(collectionParameter.size()>0){
int m=collectionParameter.size()/step;
for (int i = 0; i <=m; i++) {
int begin=i*step;
int end=(begin+step)
在测试方法
可以看出对象已经不是空的了
批量更新数据当然也不会有问题了
需要注意的是我是有定义bean 的名称所以传入获取这个对象也要是这个
这样spring项目也可以使用了唯一不同的就是需要传递容器的名称获取对象,大功告成!



