java反射invoke调用方法报空指针异常

最近做项目用到定时任务,在设计的时候,考虑到每条job对应一个jobClass和jobMethod,会需要用到反射技术。

通过反射技术获取指定的方法,然后去执行。但是!!!在执行invoke方法的时候,一直报空指针异常,百度了一下午才找到解决方案。现在把解决方法分享给大家。

先看下代码:

首先是一个测试类:

    @Test
	public void test() {
		String classBeanName = "com.bandweaver.tunnel.service.mam.measobj.MeasObjModuleCenter";
		String targetMethod = "saveSOSchedule";
		try {
			Class<?> clazz = Class.forName(classBeanName);
			Method method = clazz.getDeclaredMethod(targetMethod);
			LogUtil.info("Get method : " + method);
			method.setAccessible(true);
            method.invoke(clazz.newInstance());
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

我的目的是要执行下面这个方法,代码不需要细看,你只需要知道我这个方法里需要用到@autowired注解去获取我需要的bean,这就是为什么报空指针的原因了。

/**SO 
     *    
     * @author shaosen
     * @throws Exception 
     * @Date 2018年9月10日
     */
    public void saveSOSchedule(){
   	   //从缓存中获取数据,然后定时向对象表中更新数据,并同时保存到value表中
       List<MeasObjSO> measObjSOs = getMeasObjSOs();
       LogUtil.info("*******************************************************************");
       LogUtil.info("*******************************************************************");
       LogUtil.info("*******************************************************************");
       LogUtil.info("measObjSOs.size: " + measObjSOs.size() );
       for (MeasObjSO measObjSO : measObjSOs) {
       	
       	//step1:保存数据到value表中
    	if(measValueSOMapper == null ) { measValueSOMapper = SpringContextHolder.getBean("measValueSOMapper");}
       	List<MeasValueSO> list = measValueSOMapper.getByObjectId(measObjSO.getId());
       	LogUtil.info("Get list : " + list);
       	if(list != null && list.size() >0 ) {
       		MeasValueSO measValueSO = list.get(0);
       		if(measValueSO.getTime() != null && measValueSO.getTime().getTime()>=measObjSO.getRefreshTime().getTime()) {
       			LogUtil.info("SO监测对象[" + measObjSO.getId() + "]缓存数据暂无更新 ");
           		continue;
       		}
       	}
       	MeasValueSO measValueSO = new MeasValueSO();
       	measValueSO.setObjectId(measObjSO.getId());
       	measValueSO.setTime(measObjSO.getRefreshTime());
       	measValueSO.setCV(measObjSO.getCV());
       	LogUtil.info("Start to save : " + measValueSO);
       	measValueSOMapper.addMeasValueSO(measValueSO);
       	LogUtil.info("Success !");
       	
       	//step2:更新对象表
       	if(measObjSOMapper == null ) { measObjSOMapper = SpringContextHolder.getBean("measObjSOMapper");}
       	MeasObjSO fromDb = measObjSOMapper.getMeasObjSO(measObjSO.getId());
       	if(fromDb.getRefreshTime() != null && fromDb.getRefreshTime().getTime() >= measObjSO.getRefreshTime().getTime()) {
       		LogUtil.info("SO监测对象[" + measObjSO.getId() + "]缓存数据暂无更新 ");
       		continue;
       	}
       	fromDb.setRefreshTime(measObjSO.getRefreshTime());
       	fromDb.setCV(measObjSO.getCV());
       	LogUtil.info("Start to update : " + fromDb);
       	measObjSOMapper.update(fromDb);
       	LogUtil.info("Success !");
   	}
   }

原因:method.invoke(clazz.newInstance());事实上class.newInstance()生成的实例中,是获取不到@autowired组件的

解决方案:method.invoke(ApplicationContextUtils.getBean("measObjModuleCenter"))

把代码修改成如下:

@Test
	public void test() {
		String classBeanName = "com.bandweaver.tunnel.service.mam.measobj.MeasObjModuleCenter";
		String targetMethod = "saveSOSchedule";
		try {
			Class<?> clazz = Class.forName(classBeanName);
			Method method = clazz.getDeclaredMethod(targetMethod);
			LogUtil.info("Get method : " + method);
			method.setAccessible(true);
			method.invoke(SpringContextHolder.getBean("measObjModuleCenter"));
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

顺手把SpringContextHolder工具类也粘贴了吧

package com.bandweaver.tunnel.common.platform.util;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.bandweaver.tunnel.common.platform.log.LogUtil;

public class SpringContextHolder implements ApplicationContextAware {

	private static ApplicationContext applicationContext = null;


	/**
	 * 取得存储在静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		LogUtil.debug("从SpringContextHolder中取出Bean:" + name);
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		LogUtil.debug("清除SpringContextHolder中的ApplicationContext:"
				+ applicationContext);
		applicationContext = null;
	}

	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
//		LogUtil.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);

		if (SpringContextHolder.applicationContext != null) {
			LogUtil.info("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
		}

		SpringContextHolder.applicationContext = applicationContext; // NOSONAR
	}

	/**
	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
	 */
	public void destroy() throws Exception {
		SpringContextHolder.clearHolder();
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
		if(applicationContext == null) {
			throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/csdn_ss1991/article/details/82595176