web-dev-qa-db-fra.com

Printemps: utilisation du modèle de générateur pour créer un bean

J'utilise ektorp pour me connecter à CouchDB.

La façon de construire une instance ektorp HttpClient est d'utiliser le modèle de générateur:

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

Je suis relativement nouveau au printemps. Veuillez me conseiller sur la façon de configurer un HttpClient dans mon contexte pour le créer via le Builder.

Une façon de le faire est avec @Configuration. Y a-t-il d'autres options?

39
artemb

Vous pouvez essayer d'implémenter l'interface 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;
}}

Et ajoutez à la configuration la définition de bean suivante:

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

Ensuite, vous pouvez injecter ce bean dans un autre bean, il sera résolu comme instance StdHttpClient.

49
wax

Une fois, je suis tombé sur le même problème, lorsque je développais FlexyPool (un utilitaire de surveillance et de dimensionnement automatique du pool de connexions) , j'ai donc écrit n article avec à la fois un Java et un exemple basé sur xml.

Fondamentalement, à partir du générateur suivant:

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

L'utilisation de la configuration basée sur Java est simple:

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

Mais vous pouvez également utiliser une configuration basée sur 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"/>
7
Vlad Mihalcea

Veuillez consulter la documentation Spring FactoryBean et FactoryMethod.

2
Script Runner

Bien que non explicite pour votre cas; il est possible d'étendre un générateur s'il expose des propriétés via les méthodes standard de modèle de bean set. c'est-à-dire si nous prenons le org.Apache.httpcomponents:httpclientHttpClientBuilder à titre d'exemple, nous pourrions avoir les éléments suivants:

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

}

Désormais, toute méthode exposée par HttpClientBuilder est accessible à votre bean d'usine. Une configuration telle que la suivante est désormais possible:

<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>
1
Brett Ryan

Alors que FactoryBean est plus propre, il existe une méthode plus rapide et sale, utilisant SpEL .

Voici comment je viens de configurer le pilote Neo4j :

<bean id = "neoDriver" class = "org.neo4j.driver.v1.GraphDatabase" 
        factory-method="driver">
    <constructor-arg value = "bolt://127.0.0.1:7687" />
    <constructor-arg>
        <bean class = "org.neo4j.driver.v1.AuthTokens" factory-method = "basic">
            <constructor-arg value = "neo4j" />
            <constructor-arg value = "***" />
        </bean>
    </constructor-arg>
    <constructor-arg type="org.neo4j.driver.v1.Config" 
        value = "#{T(org.neo4j.driver.v1.Config).build ()
            .withConnectionAcquisitionTimeout ( 10, T(Java.util.concurrent.TimeUnit).SECONDS )
            .withConnectionTimeout ( 10, T(Java.util.concurrent.TimeUnit).SECONDS )
            .toConfig ()
        }"
    />
</bean>

Comme vous pouvez le voir dans le 3e paramètre de la méthode d'usine, vous pouvez invoquer un générateur et ses méthodes en tant qu'expression SpEL, avec la nuance que les classes doivent être spécifiées via leur FQN. Mais cela vous évite d'écrire un FactoryBean passe-partout complet.

0
zakmck