Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: Using builder pattern to create a bean

I use ektorp to connect to CouchDB.

The way to build an ektorp HttpClient instance is to use builder pattern:

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

I am relatively new to Spring. Please advice me on how I can configure an HttpClient in my context to create it via the Builder.

One way to do this is with @Configuration. Are any other options?

like image 575
artemb Avatar asked Jul 13 '10 11:07

artemb


People also ask

What is builder pattern in Spring?

The builder pattern allows you to enforce a step-by-step process to construct a complex object as a finished product. In this pattern, the step-by-step construction process remains same but the finished products can have different representations.

What is the use of builder pattern to create?

Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.” It is used to construct a complex object step by step and the final step will return the object.

How do I create a custom bean in Spring boot?

In the Application , we create a bean, call its method and set up the Spring Boot application. The CommandLineRunner interface indicates that a bean should run when it is contained within a SpringApplication . It can be used to create command line applications in Spring Boot.


2 Answers

You may try to implement FactoryBean interface:

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

And add to config following bean definition:

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

Then you can inject this bean to another beans, it will be resolved as StdHttpClient instance.

like image 114
wax Avatar answered Oct 11 '22 08:10

wax


I once stumbled on the same issue when I was developing FlexyPool, so this is what I did.

Basically, starting from the following Builder:

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

Using the Java-based configuration is straight-forward:

@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();     } } 

But you can also use XML-based configuration as well:

<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"/> 
like image 28
Vlad Mihalcea Avatar answered Oct 11 '22 08:10

Vlad Mihalcea