Skip to content
Browse files

update article with proper spring config

  • Loading branch information...
1 parent e2f33a2 commit 1f7ac5c0a172bc9fe6edba3634fbe62b15071813 @jsimone jsimone committed Nov 28, 2011
View
113 ARTICLE.md
@@ -0,0 +1,113 @@
+## Using Memcache from Java
+
+Spymemcached is a popular Java Memcache client. In order to use Spymemcached in your project you have to declare the dependency in your build and initialize the client from the environment variables that Heroku provides to your application.
+
+### Add Spymemcached to your pom.xml
+
+Add the following repository and dependency to your pom.xml in order to use Spymemcached to connect to Memcache:
+
+ <repository>
+ <id>spy</id>
+ <name>Spy Repository</name>
+ <layout>default</layout>
+ <url>http://files.couchbase.com/maven2/</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+
+ ...
+
+ <dependency>
+ <groupId>spy</groupId>
+ <artifactId>spymemcached</artifactId>
+ <version>2.7.3</version>
+ </dependency>
+
+### Use Spymemcached in your application
+
+ :::java
+ AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD")));
+ ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
+ ConnectionFactory cf = factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build();
+
+ MemcachedClient memcachedClient = new MemcachedClient(cf, Collections.singletonList(new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211)));
+ memcachedClient.add("test", 0, "testData");
+
+### Using Spymemcached with Spring
+
+Use the following Java configuration class to set up a `MemcachedClient` object as a singleton Spring bean:
+
+ :::java
+ @Configuration
+ public class SpringConfig {
+ @Bean
+ public PlainCallbackHandler getPlainCallbackHandler() {
+ return new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD"));
+ }
+
+ @Bean
+ public AuthDescriptor getAuthDescriptor() {
+ return new AuthDescriptor(new String[]{"PLAIN"},
+ getPlainCallbackHandler());
+ }
+
+ @Bean
+ public ConnectionFactory getConnectionFactory() {
+ ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
+ return factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(getAuthDescriptor()).build();
+ }
+
+ @Bean
+ public InetSocketAddress getServerAddress() {
+ return new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211);
+ }
+
+ @Bean
+ public MemcachedClient getMemcachedClient() throws IOException{
+ MemcachedClient memcachedClient =
+ new MemcachedClient(
+ getConnectionFactory(),
+ Collections.singletonList(getServerAddress()));
+ return memcachedClient;
+ }
+ }
+
+or the following XML configuration file:
+
+ :::xml
+ <?xml version="1.0" encoding="UTF-8"?>
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <context:annotation-config/>
+ <context:property-placeholder/>
+
+ <bean id="plainCallbackHandler" class="net.spy.memcached.auth.PlainCallbackHandler">
+ <constructor-arg index="0" value="${MEMCACHE_USERNAME}"/>
+ <constructor-arg index="1" value="${MEMCACHE_PASSWORD}"/>
+ </bean>
+
+ <bean id="authDescriptor" class="net.spy.memcached.auth.AuthDescriptor">
+ <constructor-arg index="0">
+ <array><value>PLAIN</value></array>
+ </constructor-arg>
+ <constructor-arg index="1" ref="plainCallbackHandler"/>
+ </bean>
+
+ <bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
+ <property name="servers" value="${MEMCACHE_SERVERS}:11211"/>
+ <property name="protocol" value="BINARY"/>
+ <property name="authDescriptor" ref="authDescriptor"/>
+ </bean>
+
+ </beans>
+
+### Sample code
+
+To see a complete, working example, check out the [sample code in github](https://github.com/heroku/devcenter-memcache-java). The [readme](https://github.com/heroku/devcenter-memcache-java/blob/master/README.md) explains more about the example.
View
2 Procfile
@@ -0,0 +1,2 @@
+sample: sh target/bin/sample
+springsample: sh target/bin/spring-sample
View
126 README.md
@@ -1,88 +1,64 @@
-## Using Memcache from Java
+## Using MongoDB from Java
-Spymemcached is a popular Java Memcache client. In order to use Spymemcached in your project you have to declare the dependency in your build and initialize the client from the environment variables that Heroku provides to your application.
+This is an example of using Spymemcached to connect to the Membase Memcache service from both a generic Java application and a Spring configured application on Heroku. Read more about how to use Membache in the [add-on article](http://devcenter.heroku.com/articles/memcache).
-### Add Spymemcached to Your Pom.xml
+# Using The Sample Code
-Add the following repository and dependency to your pom.xml in order to use Spymemcached to connect to Memcache:
+Clone the repo with:
- <repository>
- <id>spy</id>
- <name>Spy Repository</name>
- <layout>default</layout>
- <url>http://files.couchbase.com/maven2/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
-
- ...
-
- <dependency>
- <groupId>spy</groupId>
- <artifactId>spymemcached</artifactId>
- <version>2.7.3</version>
- </dependency>
-
-### Use Spymemcached in Your Application
-
- :::java
- AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD")));
- ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
- ConnectionFactory cf = factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build();
-
- MemcachedClient memcachedClient = new MemcachedClient(cf, Collections.singletonList(new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211)));
- memcachedClient.add("test", 0, "testData");
+ $ git clone https://github.com/heroku/devcenter-memcache-java.git
-### Using Spymemcached with Spring
+Start Memcached locally and set environment variables the way that the Heroku add-on by Membase does:
-When using Spymemcached with Spring you can create a bean that will hold your Memcache configuration and then use Spring to initialize that bean:
+ $ export MEMCACHE_SERVERS=localhost
+ $ export MEMCACHE_USERNAME=user
+ $ export MEMCACHE_PASSWORD=password
-Memcache Configuration Bean:
+Build the sample:
- public class MemcacheConfig {
- private String servers;
- private String username;
- private String password;
+ $ mvn package
+ [INFO] Scanning for projects...
+ [INFO]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Building memcacheSample 0.0.1-SNAPSHOT
+ [INFO] ------------------------------------------------------------------------
+ ...
- //getters and setters ommitted
- }
+Run it with foreman:
+
+ $ foreman start
+ 20:32:39 sample.1 | started with pid 78505
+ 20:32:39 springsample.1 | started with pid 78506
+ 20:32:40 springsample.1 | Nov 28, 2011 8:32:40 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
+ 20:32:40 springsample.1 | INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
+ 20:32:40 springsample.1 | Nov 28, 2011 8:32:40 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
+ 20:32:40 springsample.1 | INFO: Refreshing org.springframework.context.support.GenericXmlApplicationContext@657d5d2a: startup date [Mon Nov 28 20:32:40 PST 2011]; root of context hierarchy
+ 20:32:40 springsample.1 | Nov 28, 2011 8:32:40 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
+ 20:32:40 springsample.1 | INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@296f25a7: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,plainCallbackHandler,authDescriptor,memcachedClient]; root of factory hierarchy
+ 20:32:40 sample.1 | 2011-11-28 20:32:40.520 INFO net.spy.memcached.MemcachedConnection: Added {QA sa=mc7.ec2.northscale.net/174.129.165.0:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
+ 20:32:40 sample.1 | 2011-11-28 20:32:40.530 WARN net.spy.memcached.MemcachedConnection: Could not redistribute to another node, retrying primary node for test.
+ 20:32:40 springsample.1 | 2011-11-28 20:32:40.531 INFO net.spy.memcached.MemcachedConnection: Added {QA sa=mc7.ec2.northscale.net/174.129.165.0:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
+ 20:32:40 springsample.1 | 2011-11-28 20:32:40.539 WARN net.spy.memcached.MemcachedConnection: Could not redistribute to another node, retrying primary node for testSpring.
+ 20:32:40 sample.1 | 2011-11-28 20:32:40.581 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@78a1d1f4
+ 20:32:40 springsample.1 | 2011-11-28 20:32:40.603 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@506835fb
+ 20:32:40 sample.1 | 2011-11-28 20:32:40.685 INFO net.spy.memcached.auth.AuthThread: Authenticated to mc7.ec2.northscale.net/174.129.165.0:11211
+ 20:32:40 springsample.1 | 2011-11-28 20:32:40.704 INFO net.spy.memcached.auth.AuthThread: Authenticated to mc7.ec2.northscale.net/174.129.165.0:11211
+ 20:32:40 sample.1 | testData
+ 20:32:40 springsample.1 | testDataSpring
+
+
+You can switch between the Java and XML based configuration by commenting out one of the two lines in `Main.java` in the `spring` sub-package:
-This bean can be initialized with either Java or XML based spring configuration:
+ :::java
+ public class Main {
-Java Configuration:
+ public static void main(String[] args) throws Exception{
- :::java
- @Configuration
- public class SpringConfig {
- @Bean
- public MemcacheConfig getMemcachedConfig() {
- MemcacheConfig mcConfig = new MemcacheConfig();
- mcConfig.setServers(System.getenv("MEMCACHE_SERVERS"));
- mcConfig.setUsername(System.getenv("MEMCACHE_USERNAME"));
- mcConfig.setPassword(System.getenv("MEMCACHE_PASSWORD"));
- return mcConfig;
- }
- }
-
-or XML Configuration:
-
- <bean class="com.heroku.devcenter.spring.MemcacheConfig">
- <property name="servers" value="#{systemEnvironment['MEMCACHE_SERVERS'] }"/>
- <property name="username" value="#{systemEnvironment['MEMCACHE_USERNAME'] }"/>
- <property name="password" value="#{systemEnvironment['MEMCACHE_PASSWORD'] }"/>
- </bean>
-
-Client Creation:
+ // If you want Java based configuration:
+ final ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
+
+ // If you want XML based configuration:
+ //final ApplicationContext ctx = new GenericXmlApplicationContext("applicationContext.xml");
+
+ ...
- :::java
- // For xml based config use GenericXmlApplicationContext
- ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
- MemcacheConfig config = ctx.getBean(MemcacheConfig.class);
-
- AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(config.getUsername(), config.getPassword()));
- ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
- ConnectionFactory cf = factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build();
- MemcachedClient memcachedClient = new MemcachedClient(cf, Collections.singletonList(new InetSocketAddress(config.getServers(), 11211)));
-
-You can also download the [sample code](http://github.com/heroku/devcenter-memcache-java)
View
41 pom.xml
@@ -40,5 +40,46 @@
<version>2.2.2</version>
</dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+ <!-- The maven app assembler plugin will generate a script that sets up the classpath and runs your project -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>appassembler-maven-plugin</artifactId>
+ <version>1.1.1</version>
+ <configuration>
+ <assembleDirectory>target</assembleDirectory>
+ <programs>
+ <program>
+ <mainClass>com.heroku.devcenter.Main</mainClass>
+ <name>sample</name>
+ </program>
+ <program>
+ <mainClass>com.heroku.devcenter.spring.Main</mainClass>
+ <name>spring-sample</name>
+ </program>
+ </programs>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>assemble</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
View
8 src/main/java/com/heroku/devcenter/spring/Main.java
@@ -26,14 +26,8 @@
public static void main(String[] args) throws IOException, URISyntaxException {
//ApplicationContext ctx = new GenericXmlApplicationContext("applicationContext.xml");
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
- MemcacheConfig config = ctx.getBean(MemcacheConfig.class);
+ MemcachedClient memcachedClient = ctx.getBean(MemcachedClient.class);
- AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"},
- new PlainCallbackHandler(config.getUsername(), config.getPassword()));
- ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
- ConnectionFactory cf = factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build();
-
- MemcachedClient memcachedClient = new MemcachedClient(cf, Collections.singletonList(new InetSocketAddress(config.getServers(), 11211)));
memcachedClient.add("testSpring", 0, "testDataSpring");
System.out.println(memcachedClient.get("testSpring"));
}
View
27 src/main/java/com/heroku/devcenter/spring/MemcacheConfig.java
@@ -1,27 +0,0 @@
-package com.heroku.devcenter.spring;
-
-public class MemcacheConfig {
-
- private String servers;
- private String username;
- private String password;
-
- public String getServers() {
- return servers;
- }
- public void setServers(String servers) {
- this.servers = servers;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
-}
View
51 src/main/java/com/heroku/devcenter/spring/SpringConfig.java
@@ -1,17 +1,50 @@
package com.heroku.devcenter.spring;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+
+import net.spy.memcached.ConnectionFactory;
+import net.spy.memcached.ConnectionFactoryBuilder;
+import net.spy.memcached.MemcachedClient;
+import net.spy.memcached.ConnectionFactoryBuilder.Protocol;
+import net.spy.memcached.auth.AuthDescriptor;
+import net.spy.memcached.auth.PlainCallbackHandler;
+
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
-
- @Bean
- public MemcacheConfig getMemcachedConfig() {
- MemcacheConfig mcConfig = new MemcacheConfig();
- mcConfig.setServers(System.getenv("MEMCACHE_SERVERS"));
- mcConfig.setUsername(System.getenv("MEMCACHE_USERNAME"));
- mcConfig.setPassword(System.getenv("MEMCACHE_PASSWORD"));
- return mcConfig;
- }
+
+ @Bean
+ public PlainCallbackHandler getPlainCallbackHandler() {
+ return new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD"));
+ }
+
+ @Bean
+ public AuthDescriptor getAuthDescriptor() {
+ return new AuthDescriptor(new String[]{"PLAIN"},
+ getPlainCallbackHandler());
+ }
+
+ @Bean
+ public ConnectionFactory getConnectionFactory() {
+ ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
+ return factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(getAuthDescriptor()).build();
+ }
+
+ @Bean
+ public InetSocketAddress getServerAddress() {
+ return new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211);
+ }
+
+ @Bean
+ public MemcachedClient getMemcachedClient() throws IOException{
+ MemcachedClient memcachedClient =
+ new MemcachedClient(
+ getConnectionFactory(),
+ Collections.singletonList(getServerAddress()));
+ return memcachedClient;
+ }
}
View
23 src/main/resources/applicationContext.xml
@@ -8,11 +8,24 @@
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
-
- <bean class="com.heroku.devcenter.spring.MemcacheConfig">
- <property name="servers" value="#{systemEnvironment['MEMCACHE_SERVERS'] }"/>
- <property name="username" value="#{systemEnvironment['MEMCACHE_USERNAME'] }"/>
- <property name="password" value="#{systemEnvironment['MEMCACHE_PASSWORD'] }"/>
+ <context:property-placeholder/>
+
+ <bean id="plainCallbackHandler" class="net.spy.memcached.auth.PlainCallbackHandler">
+ <constructor-arg index="0" value="${MEMCACHE_USERNAME}"/>
+ <constructor-arg index="1" value="${MEMCACHE_PASSWORD}"/>
+ </bean>
+
+ <bean id="authDescriptor" class="net.spy.memcached.auth.AuthDescriptor">
+ <constructor-arg index="0">
+ <array><value>PLAIN</value></array>
+ </constructor-arg>
+ <constructor-arg index="1" ref="plainCallbackHandler"/>
+ </bean>
+
+ <bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
+ <property name="servers" value="${MEMCACHE_SERVERS}:11211"/>
+ <property name="protocol" value="BINARY"/>
+ <property name="authDescriptor" ref="authDescriptor"/>
</bean>
</beans>

0 comments on commit 1f7ac5c

Please sign in to comment.
Something went wrong with that request. Please try again.