2010-07-13 204 views
35

我使用ektorp來連接到CouchDB。Spring:使用構建器模式創建一個bean

建立一個EKTORP HttpClient實例的方法是使用生成器模式:

HttpClient httpClient = new StdHttpClient.Builder() 
           .host("mychouchdbhost") 
           .port(4455) 
           .build(); 

我是比較新的春天。請諮詢我如何在我的上下文中配置HttpClient以通過Builder創建它。

一種方法是使用@Configuration。有其他選擇嗎?

回答

42

您可以嘗試實現FactoryBean接口:

public class HttpFactoryBean implements FactoryBean<HttpClient>{ 

private String host; 
private int port; 


public HttpClient getObject() throws Exception { 
    return new StdHttpClient.Builder() 
          .host(host) 
          .port(port) 
          .build(); 
} 

public Class<? extends HttpClient> getObjectType() { 
    return StdHttpClient.class; 
} 

public boolean isSingleton() { 
    return true; 
} 

public void setHost(String host) { 
    this.host = host; 
} 

public void setPort(int port) { 
    this.port = port; 
}} 

,並加入到配置下面bean定義:

<beans ..."> 
    <bean name="myHttpClient" class="HttpFactoryBean"> 
     <property name="port" value="8080"/> 
     <property name="host" value="localhost"/> 
    </bean> 
</beans> 

然後你可以注入這個bean到另一個豆,它會被解析爲StdHttpClient實例。

3

請檢查Spring FactoryBean和FactoryMethod文檔。

1

雖然不明確爲您的情況;如果通過標準bean模式set方法公開屬性,則可以擴展構建器。即如果我們把org.apache.httpcomponents:httpclientHttpClientBuilder作爲一個例子,我們可以有以下幾種:

public class HttpClientFactoryBean 
     extends HttpClientBuilder 
     implements InitializingBean, 
        FactoryBean<HttpClient> { 

    private HttpClient value; 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     this.value = build(); 
    } 

    @Override 
    public HttpClient getObject() throws Exception { 
     return value; 
    } 

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

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

} 

現在,通過HttpClientBuilder暴露任何方法對你的工廠bean訪問。比如下面的配置,現在可以:

<beans id="httpClient" class="com.drunkendev.factory.HttpClientFactoryBean"> 
    <beans name="defaultCredentialsProvider" ref="credentialsProvider"/> 
    <beans name="targetAuthenticationStrategy"> 
    <util:constant static-field="org.apache.http.impl.client.TargetAuthenticationStrategy.INSTANCE"/> 
    </beans> 
</beans> 
5

我曾經在同一個問題上,迷迷糊糊的時候我正在開發flexy-pool (a reactive connection pool sizing utility),所以我寫了an article既基於Java和基於XML的例子。

基本上,從以下製造商開始:

public final class Configuration<T extends DataSource> extends ConfigurationProperties<T, Metrics, PoolAdapter<T>> { 

    public static final long DEFAULT_METRIC_LOG_REPORTER_PERIOD = 5; 

    public static class Builder<T extends DataSource> { 
     private final String uniqueName; 
     private final T targetDataSource; 
     private final PoolAdapterBuilder<T> poolAdapterBuilder; 
     private final MetricsBuilder metricsBuilder; 
     private boolean jmxEnabled = true; 
     private long metricLogReporterPeriod = DEFAULT_METRIC_LOG_REPORTER_PERIOD; 

     public Builder(String uniqueName, T targetDataSource, MetricsBuilder metricsBuilder, PoolAdapterBuilder<T> poolAdapterBuilder) { 
      this.uniqueName = uniqueName; 
      this.targetDataSource = targetDataSource; 
      this.metricsBuilder = metricsBuilder; 
      this.poolAdapterBuilder = poolAdapterBuilder; 
     } 

     public Builder setJmxEnabled(boolean enableJmx) { 
      this.jmxEnabled = enableJmx; 
      return this; 
     } 

     public Builder setMetricLogReporterPeriod(long metricLogReporterPeriod) { 
      this.metricLogReporterPeriod = metricLogReporterPeriod; 
      return this; 
     } 

     public Configuration<T> build() { 
      Configuration<T> configuration = new Configuration<T>(uniqueName, targetDataSource); 
      configuration.setJmxEnabled(jmxEnabled); 
      configuration.setMetricLogReporterPeriod(metricLogReporterPeriod); 
      configuration.metrics = metricsBuilder.build(configuration); 
      configuration.poolAdapter = poolAdapterBuilder.build(configuration); 
      return configuration; 
     } 
    } 

    private final T targetDataSource; 
    private Metrics metrics; 
    private PoolAdapter poolAdapter; 

    private Configuration(String uniqueName, T targetDataSource) { 
     super(uniqueName); 
     this.targetDataSource = targetDataSource; 
    } 

    public T getTargetDataSource() { 
     return targetDataSource; 
    } 

    public Metrics getMetrics() { 
     return metrics; 
    } 

    public PoolAdapter<T> getPoolAdapter() { 
     return poolAdapter; 
    } 
} 

使用基於Java的配置是直接的:

@org.springframework.context.annotation.Configuration 
public class FlexyDataSourceConfiguration { 

    @Bean 
    public Configuration configuration() { 
     return new Configuration.Builder(
       UUID.randomUUID().toString(), 
       poolingDataSource, 
       CodahaleMetrics.BUILDER, 
       BitronixPoolAdapter.BUILDER 
     ).build(); 
    } 
} 

但你也可以使用基於XML的配置,以及:

<bean id="configurationBuilder" class="com.vladmihalcea.flexypool.config.Configuration$Builder"> 
    <constructor-arg value="uniqueId"/> 
    <constructor-arg ref="poolingDataSource"/> 
    <constructor-arg value="#{ T(com.vladmihalcea.flexypool.metric.codahale.CodahaleMetrics).BUILDER }"/> 
    <constructor-arg value="#{ T(com.vladmihalcea.flexypool.adaptor.BitronixPoolAdapter).BUILDER }"/> 
</bean> 

<bean id="configuration" factory-bean="configurationBuilder" factory-method="build"/> 
+0

通讀您的文章。我喜歡這種方式,並發現它獨特。你能幫我理解最後兩個構造函數arg的構造嗎?我無法找到在那裏使用BUILDER構造的任何幫助。 – rajneesh2k10 2015-03-22 18:41:47

+1

這是一個生成器,讓其他建造者解決一些依賴關係。 – 2015-03-22 18:50:35

+0

哦......所以如果沒有弄錯的話,「BUILDER」就是「CodahaleMetrics」和「BitronixPoolAdapter」的財產。 – rajneesh2k10 2015-03-22 18:54:27