精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Spring5 中更優雅的第三方 Bean 注入

開發 開發工具
不知道各位小伙伴們有沒有用過 OkHttp,這是一個專門做網絡請求的工具,在微服務的 HTTP 調用組件中,我們可以配置底層使用 OkHttp 這個工具。

小伙伴們知道,當我們使用 Spring 容器的時候,如果遇到一些特殊的 Bean,一般來說可以通過如下三種方式進行配置:

  • 靜態工廠方法
  • 實例工廠方法
  • FactoryBean

不過從 Spring5 開始,在 AbstractBeandefinition 類中多了一個屬性,對于特殊的 Bean 我們有了更多的選擇:

/**
 * Specify a callback for creating an instance of the bean,
 * as an alternative to a declaratively specified factory method.
 * <p>If such a callback is set, it will override any other constructor
 * or factory method metadata. However, bean property population and
 * potential annotation-driven injection will still apply as usual.
 * @since 5.0
 * @see #setConstructorArgumentValues(ConstructorArgumentValues)
 * @see #setPropertyValues(MutablePropertyValues)
 */
public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {
 this.instanceSupplier = instanceSupplier;
}

/**
 * Return a callback for creating an instance of the bean, if any.
 * @since 5.0
 */
@Nullable
public Supplier<?> getInstanceSupplier() {
 return this.instanceSupplier;
}

接下來松哥就來和大家簡單聊一聊這個話題。

1. 傳統解決方案

1.1 問題

不知道各位小伙伴們有沒有用過 OkHttp,這是一個專門做網絡請求的工具,在微服務的 HTTP 調用組件中,我們可以配置底層使用 OkHttp 這個工具。

一般來說,如果我們想直接使用 OkHttp,代碼如下:

OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(5, TimeUnit.SECONDS)
        .readTimeout(5, TimeUnit.SECONDS)
        .build();
Request getReq = new Request.Builder().get().url("http://www.javaboy.org").build();
Call call = client.newCall(getReq);
call.enqueue(new Callback() {
    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        System.out.println("e.getMessage() = " + e.getMessage());
    }
    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        System.out.println("response.body().string() = " + response.body().string());
    }
});

先通過建造者模式創建出來一個 OkHttpClient 對象,然后還是建造者模式創建出來 Request 對象,接下來去發送請求就可以了。那么對于這樣的代碼,我們可以將 OkHttpClient 對象交由 Spring 容器統一管理,那么該如何將 OkHttpClient 注冊到 Spring 容器中呢?

1.2 靜態工廠方法

首先可以采用靜態工廠方法,也就是工廠方法是一個靜態方法,如下:

public class OkHttpStaticFactory {
    private static OkHttpClient okHttpClient;
    static {
        okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .build();
    }
    
    public static OkHttpClient getOkHttpClient() {
        return okHttpClient;
    }
}

然后在 Spring 配置文件中進行注入:

<bean class="org.javaboy.bean.OkHttpStaticFactory" factory-method="getOkHttpClient" id="httpClient"/>

靜態工廠的特點是靜態方法可以直接調用,并必須要獲取到工廠類的實例,所以上面配置的時候只需要指定 factory-method 就可以了。

這就可以了,將來我們去 Spring 容器中查找一個名為 httpClient 的對象,拿到手的就是 OkHttpClient 了。

1.3 實例工廠方法

實例工廠方法意思就是說工廠方法是一個實例方法。如下:

public class OkHttpInstanceFactory {
    private volatile static OkHttpClient okHttpClient;

    public OkHttpClient getInstance() {
        if (okHttpClient == null) {
            synchronized (OkHttpInstanceFactory.class) {
                if (okHttpClient == null) {
                    okHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(5, TimeUnit.SECONDS)
                            .readTimeout(5, TimeUnit.SECONDS)
                            .build();
                }
            }
        }
        return okHttpClient;
    }
}

這是一個簡單的單例模式。但是這里的工廠方法是一個實例方法,實例方法的調用必須得先獲取到對象然后才能調用實例方法,因此配置方式如下:

<bean class="org.javaboy.bean.OkHttpInstanceFactory" id="httpInstanceFactory"/>
<bean factory-bean="httpInstanceFactory" factory-method="getInstance" id="httpClient"/>

好啦,接下來我們就可以去 Spring 容器中獲取一個名為 httpClient 的對象了,拿到手的就是 OkHttpClient 實例。

1.4 FactoryBean

當然,也可以通過 FactoryBean 來解決上述問題,FactoryBean 松哥在之前的文章中剛剛和大家介紹過,我們來看下:

public class OkHttpClientFactoryBean implements FactoryBean<OkHttpClient> {
    @Override
    public OkHttpClient getObject() throws Exception {
        return new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .build();
    }

    @Override
    public Class<?> getObjectType() {
        return OkHttpClient.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

最后在 Spring 中配置即可:

<bean class="org.javaboy.bean.OkHttpClientFactoryBean" id="httpClient"/>

這個就不做過多解釋了,不熟悉的小伙伴可以翻看前面的文章。

上面這三種方案都是傳統方案。

特別是前兩種,其實我們用的比較少,前兩種有一個缺陷,就是我們配置的的 factory-method 都是通過反射來調用的,通過反射調用的話,多多少少性能受點影響。

這種 factory-method 在 Spring 中處理的源碼執行時序圖如下:

圖片圖片

所以最終反射是在 SimpleInstantiationStrategy#instantiate 方法中執行的,就是大家非常熟悉的反射代碼了:

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
  @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
  ReflectionUtils.makeAccessible(factoryMethod);
  Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
  try {
   currentlyInvokedFactoryMethod.set(factoryMethod);
   Object result = factoryMethod.invoke(factoryBean, args);
   if (result == null) {
    result = new NullBean();
   }
   return result;
  }
  finally {
   if (priorInvokedFactoryMethod != null) {
    currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
   }
   else {
    currentlyInvokedFactoryMethod.remove();
   }
  }
}

好了,這是傳統的解決方案。

2. Spring5 解決方案

Spring5 中開始提供了 Supplier,可以通過接口回調獲取到一個 Bean 的實例,這種方式顯然性能更好一些。

如下:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(Book.class);
definition.setInstanceSupplier((Supplier<Book>) () -> {
    Book book = new Book();
    book.setName("深入淺出 Spring Security");
    book.setAuthor("江南一點雨");
    return book;
});
ctx.registerBeanDefinition("b1", definition);
ctx.refresh();
Book b = ctx.getBean("b1", Book.class);
System.out.println("b = " + b);

關鍵就是通過調用 BeanDefinition 的 setInstanceSupplier 方法去設置回調。當然,上面這段代碼還可以通過 Lambda 進一步簡化:

public class BookSupplier {
    public Book getBook() {
        Book book = new Book();
        book.setName("深入淺出 Spring Security");
        book.setAuthor("江南一點雨");
        return book;
    }
}

然后調用這個方法即可:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(Book.class);
BookSupplier bookSupplier = new BookSupplier();
definition.setInstanceSupplier(bookSupplier::getBook);
ctx.registerBeanDefinition("b1", definition);
ctx.refresh();
Book b = ctx.getBean("b1", Book.class);
System.out.println("b = " + b);

這是不是更有一點 Lambda 的感覺了~

在 Spring 源碼中,處理獲取 Bean 實例的時候,有如下一個分支,就是處理 Supplier 這種情況的:

AbstractAutowireCapableBeanFactory#createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
 // Make sure bean class is actually resolved at this point.
 Class<?> beanClass = resolveBeanClass(mbd, beanName);
 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
 }
 Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
 if (instanceSupplier != null) {
  return obtainFromSupplier(instanceSupplier, beanName);
 }
 if (mbd.getFactoryMethodName() != null) {
  return instantiateUsingFactoryMethod(beanName, mbd, args);
 }
 //...
 return instantiateBean(beanName, mbd);
}

@Nullable
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
 String outerBean = this.currentlyCreatedBean.get();
 this.currentlyCreatedBean.set(beanName);
 try {
  if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
   return instanceSupplier.get(RegisteredBean.of((ConfigurableListableBeanFactory) this, beanName));
  }
  if (supplier instanceof ThrowingSupplier<?> throwableSupplier) {
   return throwableSupplier.getWithException();
  }
  return supplier.get();
 }
}

上面 obtainFromSupplier 這個方法,最終會調用到第二個方法。第二個方法中的 supplier.get(); 其實最終就調用到我們自己寫的 getBook 方法了。

責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2022-05-23 13:50:20

開發封裝

2017-05-16 13:24:02

LinuxCentOS第三方倉庫

2015-11-05 16:44:37

第三方登陸android源碼

2011-10-08 14:37:59

漏洞

2017-12-11 15:53:56

2019-07-30 11:35:54

AndroidRetrofit

2014-07-23 08:55:42

iOSFMDB

2014-07-25 09:33:22

2019-09-03 18:31:19

第三方支付電商支付行業

2016-10-21 14:09:10

2009-12-31 14:38:34

Silverlight

2021-03-17 09:26:48

代碼注入密鑰簽名

2017-11-01 06:40:33

2025-04-01 05:00:00

OAuth2服務器身份驗證

2019-09-02 14:59:41

蘋果維修設備

2014-07-22 10:56:45

Android Stu第三方類庫

2009-01-14 12:45:05

MSNIM蘋果

2013-08-12 16:04:19

第三方移動應用

2021-09-26 10:43:08

注冊Istio集成

2010-05-25 11:09:31

SVN工具
點贊
收藏

51CTO技術棧公眾號

四虎影视2018在线播放alocalhost| 久久这里只有精品国产| 超薄肉色丝袜脚交一区二区| 国产精品久久三| 91成人免费看| 五月婷婷中文字幕| 色综合久久网| 精品不卡在线视频| 无人在线观看的免费高清视频| eeuss影院www在线播放| 国产精品正在播放| 日本人成精品视频在线| 91狠狠综合久久久| 欧美色图五月天| 欧美日韩国产大片| 麻豆tv在线播放| 麻豆传媒视频在线| 91色porny| 97超碰人人看人人| 成人免费一级片| 亚洲国产美女 | 国内外成人免费在线视频| 韩国成人免费视频| 中文字幕在线一区二区三区| 精品综合在线| 99国产精品久久久久久久成人| 性8sex亚洲区入口| 色综合天天综合网国产成人网| xxx在线播放| 精品日产乱码久久久久久仙踪林| 欧美精品 日韩| 国产免费视频传媒| 国产精选在线| 一个色妞综合视频在线观看| 一区二区三区国产福利| 久久久久久久影视| www.成人网.com| 91久久极品少妇xxxxⅹ软件 | 国精产品99永久一区一区| 一区二区国产欧美| 日韩av网站在线观看| 韩国福利视频一区| 久久精品免费在线| 国内一区二区三区| 久久福利网址导航| 黄色片子在线观看| 日本一区二区免费高清| 亚洲午夜国产成人av电影男同| 国产 中文 字幕 日韩 在线| 精品一区二区男人吃奶| 欧美xxxx老人做受| 亚洲区 欧美区| 午夜日韩影院| 日韩欧美亚洲国产另类| 亚洲一二区在线观看| 深夜日韩欧美| 欧美精品xxxxbbbb| 国产传媒免费观看| 自拍偷拍亚洲| 91精品午夜视频| 手机看片一级片| 四虎精品永久免费| 91精品免费在线观看| 黄色a级三级三级三级| 国产麻豆精品| 欧美成人一区二区三区片免费 | 日本精品入口免费视频| 日韩电影在线免费观看| 国产精品美女久久久久久免费| 国产一级片一区二区| 美女视频黄 久久| 91久久久亚洲精品| www.成人在线观看| www.欧美色图| 欧美亚洲另类久久综合| av色图一区| 亚洲免费观看高清完整版在线观看 | 成人网在线视频| 99久久精品国产一区二区成人| 国产精品一区在线观看乱码| 99在线首页视频| 少妇高潮一区二区三区99小说| 成人性生交大合| 蜜桃传媒视频第一区入口在线看| 九色国产在线观看| 国产精品久99| 免费一级特黄毛片| 人人鲁人人莫人人爱精品| 欧美日韩一区二区欧美激情| 日本wwwxx| 久久不见久久见国语| 日韩在线精品一区| 国产亚洲小视频| 久久精品女人| 91精品一区二区| 五月婷婷六月丁香综合| 国产精品久久看| 亚洲精品久久久久久久蜜桃臀| 在线毛片观看| 欧美一区二区播放| 青青草视频成人| 91超碰国产精品| 欧美综合激情网| av男人天堂av| 国产视频亚洲色图| 91亚洲精品国产| 亚洲www啪成人一区二区| 日韩精品一区二区三区在线| 国产精品扒开腿做爽爽| 欧美精品不卡| 国产精品日韩欧美综合| 免费激情视频网站| 国产精品高潮呻吟久久| 欧美亚洲一二三区| 精品国产鲁一鲁****| 亚洲老板91色精品久久| 欧美人与禽zozzo禽性配| 日韩av午夜在线观看| 国产精选一区二区| 国产1区在线| 在线视频你懂得一区二区三区| 亚洲成人激情小说| 99热国内精品| 国产成人涩涩涩视频在线观看 | 亚洲精品国产品国语在线| 久久国产波多野结衣| 日韩精彩视频在线观看| 国产欧美韩日| 亚洲按摩av| 欧美美女一区二区在线观看| 久久精品国产亚洲av久| 日韩视频二区| 国产精品免费观看高清| av在线看片| 在线播放中文一区| 欧美人妻一区二区三区| 亚洲综合三区| 精品无人区一区二区三区竹菊| 暧暧视频在线免费观看| 欧美一区二区三区系列电影| 老司机精品免费视频| 日韩国产精品91| 欧美日韩亚洲综合一区二区三区激情在线 | 国产成人av毛片| 欧美久久久精品| 99久久精品无免国产免费 | 日韩乱码在线观看| 成人中文字幕合集| 日本福利视频网站| 亚洲一二三区视频| 欧美日韩成人网| 亚洲精品国产精品国| 尤物av一区二区| 中文写幕一区二区三区免费观成熟| 亚洲草久电影| 亚洲精品免费网站| 最新黄网在线观看| 精品国产一区二区三区久久影院| 久久久99精品| 成人av片在线观看| 色综合久久久久无码专区| 美日韩黄色大片| 欧美在线播放视频| 国产小视频福利在线| 在线观看免费成人| 亚洲一二三四五六区| 国内成人免费视频| 成人国产在线看| 岛国av一区| 欧美一区二区三区免费视| 狠狠v欧美ⅴ日韩v亚洲v大胸| 色天使色偷偷av一区二区| av网站免费在线看| 美女精品自拍一二三四| 少妇熟女一区二区| 国产日韩三级| 国产精品久久久久久久电影| 欧美精品videos另类| 日韩欧美一区二区免费| 国产精品6666| 国产视频在线观看一区二区三区| 亚洲高清免费在线观看| 欧美成人首页| 国产一区在线观| 99久久精品一区二区成人| 久久深夜福利免费观看| 天天操天天舔天天干| 91久久精品一区二区二区| 欧美另类videoxo高潮| 国产精品77777竹菊影视小说| 欧美深夜福利视频| 日韩不卡一区| 国产精品v欧美精品∨日韩| 成人亚洲欧美| 欧美插天视频在线播放| 蜜芽tv福利在线视频| 在线亚洲+欧美+日本专区| 欧美日韩精品亚洲精品| 国产亚洲精品aa| 麻豆传媒在线看| 天堂久久一区二区三区| 亚洲天堂第一区| 国产麻豆一区二区三区精品视频| 亚洲xxxx3d| 欧洲一级精品| 97国产suv精品一区二区62| 成人网视频在线观看| 欧美mv日韩mv| 在线免费观看一级片| 精品国产91久久久久久老师| 男人的午夜天堂| 久久久久久久久久久黄色| 亚洲AV无码久久精品国产一区| 免费视频一区| 黄色成人在线免费观看| 日韩在线观看一区| 久久久久久久久久久一区| 成人豆花视频| 国产精品久久久久免费a∨大胸 | 国产成人精品av| 97在线视频免费观看完整版| 久久精品国产2020观看福利| 欧美婷婷久久五月精品三区| 精品日韩99亚洲| 国产精品久久欧美久久一区| 日韩欧美成人精品| 日本污视频在线观看| 亚洲欧洲综合另类在线| 老熟妇一区二区| 99久久精品国产精品久久 | 2020国产精品| 亚洲精品激情视频| 国产精一品亚洲二区在线视频| 在线观看的毛片| 久久久久久久尹人综合网亚洲| 黄色一级片在线看| 欧美日韩中文| 男同互操gay射视频在线看| 不卡在线一区| 日本不卡久久| 精品国产乱码| 日韩av不卡在线播放| 一本色道久久综合狠狠躁的番外| 久久精品欧美| 欧美色图婷婷| 欧美福利一区二区三区| 久草精品视频| 精品一区二区三区国产| 国产精品视频a| 日韩精品亚洲专区| 日韩中文字幕组| 天堂蜜桃91精品| 一区二区成人网| 天天综合中文字幕| 粉嫩av一区二区| 鬼打鬼之黄金道士1992林正英| 久久久久久久久久久久电影| 亚洲aⅴ日韩av电影在线观看 | 欧美成人午夜精品免费| 久久香蕉国产线看观看99| 久久精品综合视频| 久久久蜜桃精品| av电影在线不卡| 国产精品天美传媒| 男人晚上看的视频| 亚洲女人的天堂| 2021亚洲天堂| 亚洲国产精品久久久久秋霞影院 | 91精品国产乱码久久久久久久| 中文字幕av导航| 午夜性色一区二区三区免费视频| 成年人深夜视频| 亚洲激情专区| 久久国产乱子伦免费精品| 日韩激情av在线| 亚洲精品20p| 国产91丝袜在线观看| 亚洲天堂成人av| 中文在线免费一区三区高中清不卡| 久久久久久久久久97| 亚洲综合久久久| 手机在线看片1024| 欧美绝品在线观看成人午夜影视| 99视频在线观看免费| 亚洲韩国日本中文字幕| 国产51人人成人人人人爽色哟哟| 久久久久999| 国产在线美女| 国产日韩在线一区| 大香伊人久久精品一区二区| 日韩高清三级| 欧美日本免费| 久久精品免费网站| 国产电影精品久久禁18| 精品人妻无码一区二区三区| 自拍视频在线观看一区二区| 草久久免费视频| 欧美精品在线视频| 四虎电影院在线观看| 日韩中文有码在线视频| av在线中出| 国产日韩欧美成人| 欧美三级午夜理伦三级在线观看| 一区不卡视频| 中文久久精品| 手机在线观看日韩av| 国产亚洲综合色| 日本熟妇色xxxxx日本免费看| 欧美视频在线观看一区二区| 神马久久久久久久久久| 久久久www成人免费精品张筱雨 | 日韩欧美在线看| 国产成人精品免费看视频| 亚洲香蕉av在线一区二区三区| 国内高清免费在线视频| 成人精品一区二区三区| 小说区图片区色综合区| 欧美国产视频一区| 毛片不卡一区二区| 国产免费看av| 亚洲第一福利视频在线| 国产喷水吹潮视频www| 国产一区二区三区视频在线观看 | 色综合欧美在线| 亚洲精品97久久中文字幕无码| 久久九九国产精品怡红院| 久久91导航| 美女视频久久| 亚洲影音先锋| 中文字幕日韩三级片| 亚洲国产欧美日韩另类综合| www.污视频| 久久成人精品电影| 国产免费av国片精品草莓男男| 亚洲欧美日韩精品久久久| 久久一二三四| 好吊视频在线观看| 一本久久精品一区二区| 毛片在线播放网站| 国产成人精品亚洲精品| 久久超碰99| 国产精品无码一本二本三本色| www国产成人| 欧美成人一区二区三区四区| 亚洲国产黄色片| 涩涩视频在线播放| 精选一区二区三区四区五区| 国产欧美日韩综合一区在线播放 | 国产精品国产三级国产有无不卡| 天干夜夜爽爽日日日日| 亚洲视频自拍偷拍| 久久福利在线| 国产免费一区二区三区四在线播放| 精品一区二区日韩| 日韩在线观看视频一区二区| 欧美一级二级三级蜜桃| 三级福利片在线观看| 国产一区二区不卡视频| 一区二区三区四区五区精品视频| bl动漫在线观看| 色婷婷精品久久二区二区蜜臂av| 91亚洲欧美| 97人摸人人澡人人人超一碰| 在线日本高清免费不卡| 中文字幕 自拍| 7777精品伊人久久久大香线蕉最新版| 性xxxfreexxxx性欧美| 精品欧美国产| 日本在线不卡视频一二三区| 黑人と日本人の交わりビデオ| 欧美午夜影院一区| 无码国产精品96久久久久| 日韩免费在线看| 欧美在线首页| 亚洲自拍偷拍精品| 在线观看一区不卡| 黄网页免费在线观看| 国产精品我不卡| 麻豆亚洲精品| 性爱在线免费视频| 91精品在线观看入口| 免费网站看v片在线a| 国产精品久久久久久久久久久久冷 | 日韩一级视频| 无码熟妇人妻av在线电影| 久久女同精品一区二区| 中文字幕一区二区在线视频 | 国产精品免费久久久| 99久久.com| 一级黄色免费视频| 色婷婷av一区二区三区大白胸| 日韩精品成人av| 狠狠色综合色区| 免费高清不卡av| 国产第一页在线播放| 在线视频日本亚洲性| 日本一区二区三区播放| 欧美成人黄色网址| 亚洲一二三区视频在线观看| av在线第一页|