SpringBoot 集成jax-ws無法使用@Autowired 解決方案

繼承SpringBeanAutowiringSupport后依然無法使用@Autowired
o.s.w.c.s.SpringBeanAutowiringSupport : Current WebApplicationContext is not available for processing of PortalApplication: Make sure this class gets constructed in a Spring web application. Proceeding without injection.

原因分析

jax-ws 中bean的生命周期管理是不受spring 控制的。所以需要顯式繼承 SpringBeanAutowiringSupport
來看下實(shí)現(xiàn)源碼兴溜,非常巧妙

/**
     * This constructor performs injection on this instance,
     * based on the current web application context.
     * <p>Intended for use as a base class.
     * @see #processInjectionBasedOnCurrentContext
     */
    public SpringBeanAutowiringSupport() {
        processInjectionBasedOnCurrentContext(this);
    }


    /**
     * Process {@code @Autowired} injection for the given target object,
     * based on the current web application context.
     * <p>Intended for use as a delegate.
     * @param target the target object to process
     * @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext()
     */
    public static void processInjectionBasedOnCurrentContext(Object target) {
        Assert.notNull(target, "Target object must not be null");
        WebApplicationContext cc = ContextLoader.getCurrentWebApplicationContext();
        if (cc != null) {
            AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
            bpp.setBeanFactory(cc.getAutowireCapableBeanFactory());
            bpp.processInjection(target);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Current WebApplicationContext is not available for processing of " +
                        ClassUtils.getShortName(target.getClass()) + ": " +
                        "Make sure this class gets constructed in a Spring web application. Proceeding without injection.");
            }
        }
    }

從網(wǎng)上搜索到的也基本上都解釋了這個方法套腹,但是趋箩,在spring boot中是不起作用的泰偿。
因?yàn)?spring bootServlet Context Initialization 略微不一樣

SpringBootServletInitializer.startup() 使用了自定義的ContextLoaderListener,
并沒有把創(chuàng)建的rootAppContext傳給ContextLoader俩垃。
所以JAX-WS endpoint 類初始化的時(shí)候沈撞, SpringBeanAutowiringSupport從ContextLoader.getCurrentWebApplicationContext()取值總是null,@Autowired當(dāng)然就不能用了慷荔。

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // Logger initialization is deferred in case a ordered
        // LogServletContextInitializer is being used
        this.logger = LogFactory.getLog(getClass());
        WebApplicationContext rootAppContext = createRootApplicationContext(
                servletContext);
        if (rootAppContext != null) {
            servletContext.addListener(new ContextLoaderListener(rootAppContext) {
                @Override
                public void contextInitialized(ServletContextEvent event) {
                    // no-op because the application context is already initialized
                }
            });
        }
        else {
            this.logger.debug("No ContextLoaderListener registered, as "
                    + "createRootApplicationContext() did not "
                    + "return an application context");
        }
    }
}

好了,找到了問題所在缠俺,就好解決了,思路如下显晶。

  1. 初始化時(shí)把WebApplicationContext存下來
  2. 參考SpringBeanAutowiringSupport 把WebApplicationContext 拿出來,并使用
WebApplicationContextLocator.java

@Configuration
public class WebApplicationContextLocator  implements ServletContextInitializer {

    private static WebApplicationContext webApplicationContext;

    public static WebApplicationContext getCurrentWebApplicationContext() {
        return webApplicationContext;
    }

    /**
     * 在啟動時(shí)將servletContext 獲取出來壹士,后面再讀取二次使用磷雇。
     * @param servletContext
     * @throws ServletException
     */
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
    }
}
SpringBootBeanAutowiringSupport.java
public abstract class SpringBootBeanAutowiringSupport {

    private static final Log logger = LogFactory.getLog(SpringBootBeanAutowiringSupport.class);


    /**
     * This constructor performs injection on this instance,
     * based on the current web application context.
     * <p>Intended for use as a base class.
     * @see #processInjectionBasedOnCurrentContext
     */
    public SpringBootBeanAutowiringSupport() {
        System.out.println("SpringBootBeanAutowiringSupport.SpringBootBeanAutowiringSupport");
        processInjectionBasedOnCurrentContext(this);
    }


    /**
     * Process {@code @Autowired} injection for the given target object,
     * based on the current web application context.
     * <p>Intended for use as a delegate.
     * @param target the target object to process
     * @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext()
     */
    public static void processInjectionBasedOnCurrentContext(Object target) {
        Assert.notNull(target, "Target object must not be null");
        WebApplicationContext cc = WebApplicationContextLocator.getCurrentWebApplicationContext();
        if (cc != null) {
            AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
            bpp.setBeanFactory(cc.getAutowireCapableBeanFactory());
            bpp.processInjection(target);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Current WebApplicationContext is not available for processing of " +
                        ClassUtils.getShortName(target.getClass()) + ": " +
                        "Make sure this class gets constructed in a Spring web application. Proceeding without injection.");
            }
        }
    }
}

結(jié)論

jax-ws 或類似的應(yīng)用,直接 使用我們改造后的AutowiringSupport即可
extends SpringBootBeanAutowiringSupport

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躏救,一起剝皮案震驚了整個濱河市唯笙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盒使,老刑警劉巖睁本,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異忠怖,居然都是意外死亡呢堰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門凡泣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枉疼,“玉大人,你說我怎么就攤上這事鞋拟÷钗” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵贺纲,是天一觀的道長航闺。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么潦刃? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任侮措,我火速辦了婚禮,結(jié)果婚禮上乖杠,老公的妹妹穿的比我還像新娘分扎。我一直安慰自己,他們只是感情好胧洒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布畏吓。 她就那樣靜靜地躺著,像睡著了一般卫漫。 火紅的嫁衣襯著肌膚如雪菲饼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天列赎,我揣著相機(jī)與錄音巴粪,去河邊找鬼。 笑死粥谬,一個胖子當(dāng)著我的面吹牛肛根,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漏策,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼派哲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掺喻?” 一聲冷哼從身側(cè)響起芭届,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎感耙,沒想到半個月后褂乍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡即硼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年逃片,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只酥。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡褥实,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出裂允,到底是詐尸還是另有隱情损离,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布绝编,位于F島的核電站僻澎,受9級特大地震影響貌踏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窟勃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一祖乳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拳恋,春花似錦、人聲如沸砸捏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垦藏。三九已至梆暖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掂骏,已是汗流浹背轰驳。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弟灼,地道東北人级解。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像田绑,于是被迫代替她去往敵國和親勤哗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容