填坑之路(SpringBoot Jersey)

Why?

技術(shù)變革的車輪不斷向前,伴隨著k8s、docker等新技術(shù)的落地,陳舊的技術(shù)棧,千瘡百孔的工程,已經(jīng)逐步成為技術(shù)負(fù)債的黑洞。秉承著“前人挖坑后人罵,后人填坑苦哈哈”的精神,我來吧,苦哈哈。

What?

  • Jersey2.x 多Servlet-Mapping

Spring 3 映射Mappings,基于web.xml 映射Servlet,如以下代碼示例,目的是為了實(shí)現(xiàn)接口的默認(rèn)前綴并控制接口版本,以映射不同的鑒權(quán)版本、攔截器等

    <servlet>
        <servlet-name>Jersey2</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey2</servlet-name>
        <url-pattern>/rest/v1</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Jersey2</servlet-name>
        <url-pattern>/rest/v2</url-pattern>
    </servlet-mapping>
  <servlet-mapping>
        <servlet-name>Jersey2</servlet-name>
        <url-pattern>/rest/v3</url-pattern>
    </servlet-mapping>

基于springboot想實(shí)現(xiàn)接口的默認(rèn)前綴,存在以下幾種方式

  • 每一個接口添加前綴 或多個接口實(shí)現(xiàn)(當(dāng)我沒說)
  • @ApplicationPath
    然而無法實(shí)現(xiàn)多個path共存的想法,因此貌似走到了怪圈里。。走了好久好久好久。。

直到發(fā)現(xiàn)了以下的文檔:
Springboot 中Jersey 的multiple Application實(shí)現(xiàn)
核心思想:即對Servlet掃描規(guī)則進(jìn)行了拓展,完美的解決了以上問題。

  • SpringBoot Jar包運(yùn)行,提示FileNotFound

原本的配置是這個樣子的,基于IDE調(diào)試的過程中一直很順利,直到基于jar部署的時候,涼涼了

public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        //掃描Jersey實(shí)例所在包
        packages("com.xx.xx");
        // 注冊JacksonFeature
        register(JacksonFeature.class);
    }
}

貌似又走到了怪圈里。。走了好久好久好久。。

直到發(fā)現(xiàn)了以下的文檔:
jersey在 spring boot 添加 packages 掃描路徑支持
核心思想:springboot打包成jar之后,jersey packages掃描不到相關(guān)類,故使用Spring的掃描機(jī)制進(jìn)行處理

此處發(fā)現(xiàn)可以優(yōu)化的點(diǎn),之前是進(jìn)行包下的所有類掃描并注冊,之后啟動后會提示一些警告,故可以在之中判斷class是有@Path的引用,再進(jìn)行注冊

  • 多Application實(shí)例,注冊不成功

原以為逃離了怪圈。。好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)。。基于Jar部署后,啟動成功了,然而調(diào)用接口后,404??!
又又又涼涼涼了。。

貌似又又走到了怪圈里。。走了好久好久。。

之后毅然決然的查看了Application的相關(guān)源碼,發(fā)現(xiàn)了事情的真相。

public class Application {
    
    public Set<Class<?>> getClasses() {
        return Collections.emptySet();
    }
    ...省略
}

getClasses() 方法即為基于以上實(shí)例掃描到的Jersey實(shí)例,通過debug發(fā)現(xiàn)以下為空,瞬間懂了,將上文掃描到的classes,返回即可。

希望這回真的逃離了怪圈。。好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)。。

  • @ Produces 不指定類型或者干脆沒有這個注解

基于以上的一通兒操作,我以為我今天一定可以霸屏"填坑走多遠(yuǎn)排行版"第一把交椅,然而又又又又TM的出現(xiàn)了,已經(jīng)一個正常的請求,后臺提示 text/html 沒有解析器。

?。?!這是一個應(yīng)該響應(yīng)成JSON的請求!!!

貌似又又又又又又走到了怪圈里。。有點(diǎn)走走走走走走不動了。。

冷靜了許久。。想到了兩個解決方案:

  • 全局搜索,然后一個一個補(bǔ)全,之后打死哪些不寫全代碼的人
  • 配置默認(rèn)的響應(yīng)MediaType

最終在Jersey包下找到了以下類ContainerResponseFilter,大體的源碼如下

package javax.ws.rs.container;
import java.io.IOException;
public interface ContainerResponseFilter {

    /**
     * Filter method called after a response has been provided for a request
     * (either by a {@link ContainerRequestFilter request filter} or by a
     * matched resource method.
     * <p>
     * Filters in the filter chain are ordered according to their {@code javax.annotation.Priority}
     * class-level annotation value.
     * </p>
     *
     * @param requestContext  request context.
     * @param responseContext response context.
     * @throws IOException if an I/O exception occurs.
     */
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
            throws IOException;
}

關(guān)鍵的一段英文在下面

Filter method called after a response has been provided for a request

?。?!在請求的響應(yīng)返回時觸發(fā) ?。?!

果斷實(shí)現(xiàn)接口,對于代碼做容錯,大體邏輯如下:

沒有@Produces 響應(yīng)默認(rèn)為MediaType.APPLICATION_JSON
有@Produces 但是沒有值,則一樣變成MediaType.APPLICATION_JSON

To be continued ?

少挖坑,多種樹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容