ApplicationContext擴展-20191001

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


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章