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);