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


 

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