Skip to content

Commit

Permalink
Update Spring FactoryBean to properly support isSingleton property
Browse files Browse the repository at this point in the history
Motivation
----------
The current MemcachedClientFactoryBean is marked as a singleton to Spring but
does not respect the flag. It is creating a new instance with every call to
getObject(). According to the Spring Javadoc a FactoryBean marked with
isSingleton true should always return the same reference. By doing this it
will also expose an ability to safely shutdown a client instance.

Modifications
-------------
The class was updated to implement the Spring InitializingBean and
DesposableBean interfaces. These interfaces provide the two key lifecycle
methods to create and shutdown the client object. The afterPropertiesSet is
called after the FactoryBean is constructed and all of the properties have
been set. This will create the client object and store it in a field so the
same reference can be returned. The destroy method is called when closing the
Spring context. It will call the client's shutdown method. I have also added a
new property that allows a caller to specify the number of seconds to wait
before shutting down the client. This is a well established Spring pattern
that is used in many of their own FactoryBean implementations.

Result
------
A more accurate Factory bean that respects the Spring lifecycle and provides
a safe shutdown mechanism.

Change-Id: I9ae2d71ae7d3fe899bce8ec8200e215aa987400d
Reviewed-on: http://review.couchbase.org/44144
Reviewed-by: Michael Nitschinger <michael.nitschinger@couchbase.com>
Tested-by: Michael Nitschinger <michael.nitschinger@couchbase.com>
  • Loading branch information
mattbertolini authored and Michael Nitschinger committed Dec 10, 2014
1 parent 8af3ebb commit 95833c9
Showing 1 changed file with 31 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package net.spy.memcached.spring;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.ConnectionFactoryBuilder;
Expand All @@ -37,7 +38,9 @@
import net.spy.memcached.ops.OperationQueueFactory;
import net.spy.memcached.transcoders.Transcoder;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

/**
* A Spring {@link FactoryBean} creating {@link MemcachedClient} instances.
Expand All @@ -62,15 +65,17 @@
*/

@SuppressWarnings("rawtypes")
public class MemcachedClientFactoryBean implements FactoryBean {
public class MemcachedClientFactoryBean implements FactoryBean,
InitializingBean, DisposableBean {
private final ConnectionFactoryBuilder connectionFactoryBuilder =
new ConnectionFactoryBuilder();
private String servers;
private long shutdownTimeoutSeconds = 0;
private MemcachedClient client;

@Override
public Object getObject() throws Exception {
return new MemcachedClient(connectionFactoryBuilder.build(),
AddrUtil.getAddresses(servers));
return client;
}

@Override
Expand All @@ -83,6 +88,21 @@ public boolean isSingleton() {
return true;
}

@Override
public void afterPropertiesSet() throws Exception {
client = new MemcachedClient(connectionFactoryBuilder.build(),
AddrUtil.getAddresses(servers));
}

@Override
public void destroy() throws Exception {
if(shutdownTimeoutSeconds > 0) {
client.shutdown(shutdownTimeoutSeconds, TimeUnit.SECONDS);
} else {
client.shutdown();
}
}

public void setServers(final String newServers) {
this.servers = newServers;
}
Expand Down Expand Up @@ -162,4 +182,12 @@ public void setUseNagleAlgorithm(final boolean to) {
public void setWriteOpQueueFactory(final OperationQueueFactory q) {
connectionFactoryBuilder.setWriteOpQueueFactory(q);
}

/**
* The number of seconds to wait for connections to finish before shutting
* down the client.
*/
public void setShutdownTimeoutSeconds(long shutdownTimeoutSeconds) {
this.shutdownTimeoutSeconds = shutdownTimeoutSeconds;
}
}

0 comments on commit 95833c9

Please sign in to comment.