2019/10/1
问题
使用java 反射做多渠道逻辑操作
直接使用反射操作,得到bean,该bean依赖的其他bean是为空的,无法注入
如果从application里面拿该bean,那么该bean依赖的其他bean也会被spring注入并管理
如下
Class<?> notifyClass = Class.forName(ReturnThirdPartEnum.getClassPath(policyDetailByPolicyNo.getSaleSource()));
NotifyThirdPartService notifyThirdPartService= (NotifyThirdPartService)notifyClass.newInstance();
解决办法
容器初始化时,添加监听
添加自定义监听扩展
web.xml初始化时增加自定义Listen,如下添加的是InitListener.calss
<listener>
<listener-class>xxx.xxx.InitListener.class</listener-class>
</listener>
InitListener.calss implements ServletContextListener接口后, 监听的InitListener.calss 代码如下,其中添加的get/set方法可以由程序员自己决定什么时间把初始化的ApplicationContext容器赋值
定义
private static ApplicationContext springContext;
获取上下文
public void contextInitialized(ServletContextEvent arg0) {
log.info("InitListener init begin");
springContext = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext());
//加载zk配置
ZkBus.getInstance();
//加载多线程池
ExecutorFactory.getInstance();
//白名单过滤AuthFilter
ApiWhiteListCache.getInstance();
// 初始化调用方appid/appkey/secretkey到本地cache中
AppInfoCache.getInstance();
log.info("InitListener init end");
}
//从applicationcontext 获取bean
public static <T> T getService(String classFullName) {
try {
String shortClassName = ClassUtils.getShortName(classFullName);
String beanName = Introspector.decapitalize(shortClassName);
Class<T> requiredType = (Class<T>) Class.forName(classFullName);
return springContext.getBean(beanName, requiredType);
} catch (Throwable e) {
log.warn("getService exception, classFullName={}", classFullName, e);
}
return null;
}
public static ApplicationContext getSpringContext() {
return springContext;
}
public static void setSpringContext(ApplicationContext s) {
springContext = s;
}
此时我选择在测试类中初始化完applicationContext后,把它set到InitListence.class。有一个前提,需要该测试类需要继承ApplicationContextAware,只有继承了ApplicationContextAware才能使用InitListence.class的get/set方法,操作applicationContext
//Test类实现ApplicationContextAware
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/ht_service_cliservice.xml", "classpath:/META-INF/spring/spring-mybatis.xml",
"classpath:/mybatis-config.xml" })
public class VisitResourceTest implements ApplicationContextAware {
private final static Logger log = LogUtils.getLogger();
private Gson gson = new Gson();
@Test
public void notifyThirdPart()throws Exception {
String url = "";
Response resp = NetUtil.getInstance().post(url, gson.toJson(notifyThirdPartReq), MediaType.APPLICATION_JSON);
log.info("resp={}", new Gson().toJson(resp));
}
//把容器注入到InitListener
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
InitListener.setSpringContext(applicationContext);
}
}
当需要从applicationContext获取bean时如下
//使用
XXX xxx = InitListener.getService(String classPath);
response = notifyThirdPartService.notifyThirdPart(notifyThirdPartReq);