Skip to content

Commit 95833c9

Browse files
mattbertoliniMichael Nitschinger
authored andcommitted
Update Spring FactoryBean to properly support isSingleton property
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>
1 parent 8af3ebb commit 95833c9

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

src/main/java/net/spy/memcached/spring/MemcachedClientFactoryBean.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package net.spy.memcached.spring;
2424

2525
import java.util.Collection;
26+
import java.util.concurrent.TimeUnit;
2627

2728
import net.spy.memcached.AddrUtil;
2829
import net.spy.memcached.ConnectionFactoryBuilder;
@@ -37,7 +38,9 @@
3738
import net.spy.memcached.ops.OperationQueueFactory;
3839
import net.spy.memcached.transcoders.Transcoder;
3940

41+
import org.springframework.beans.factory.DisposableBean;
4042
import org.springframework.beans.factory.FactoryBean;
43+
import org.springframework.beans.factory.InitializingBean;
4144

4245
/**
4346
* A Spring {@link FactoryBean} creating {@link MemcachedClient} instances.
@@ -62,15 +65,17 @@
6265
*/
6366

6467
@SuppressWarnings("rawtypes")
65-
public class MemcachedClientFactoryBean implements FactoryBean {
68+
public class MemcachedClientFactoryBean implements FactoryBean,
69+
InitializingBean, DisposableBean {
6670
private final ConnectionFactoryBuilder connectionFactoryBuilder =
6771
new ConnectionFactoryBuilder();
6872
private String servers;
73+
private long shutdownTimeoutSeconds = 0;
74+
private MemcachedClient client;
6975

7076
@Override
7177
public Object getObject() throws Exception {
72-
return new MemcachedClient(connectionFactoryBuilder.build(),
73-
AddrUtil.getAddresses(servers));
78+
return client;
7479
}
7580

7681
@Override
@@ -83,6 +88,21 @@ public boolean isSingleton() {
8388
return true;
8489
}
8590

91+
@Override
92+
public void afterPropertiesSet() throws Exception {
93+
client = new MemcachedClient(connectionFactoryBuilder.build(),
94+
AddrUtil.getAddresses(servers));
95+
}
96+
97+
@Override
98+
public void destroy() throws Exception {
99+
if(shutdownTimeoutSeconds > 0) {
100+
client.shutdown(shutdownTimeoutSeconds, TimeUnit.SECONDS);
101+
} else {
102+
client.shutdown();
103+
}
104+
}
105+
86106
public void setServers(final String newServers) {
87107
this.servers = newServers;
88108
}
@@ -162,4 +182,12 @@ public void setUseNagleAlgorithm(final boolean to) {
162182
public void setWriteOpQueueFactory(final OperationQueueFactory q) {
163183
connectionFactoryBuilder.setWriteOpQueueFactory(q);
164184
}
185+
186+
/**
187+
* The number of seconds to wait for connections to finish before shutting
188+
* down the client.
189+
*/
190+
public void setShutdownTimeoutSeconds(long shutdownTimeoutSeconds) {
191+
this.shutdownTimeoutSeconds = shutdownTimeoutSeconds;
192+
}
165193
}

0 commit comments

Comments
 (0)