In my previous article, Spring and Amazon Web Services, I provided a brief introduction to Spring Cloud AWS module and what you as a developer can expect from it at this point in time. One thing that is not obvious from the official documentation is how to use this module when your Internet connection is restricted by a proxy server. In this post I will outline how to approach passing of proxy configuration for both Java-based and XML-based configuration. This aspect of configuration will probably be addressed in the future releases however it might help you now in case you work with this module and need your application to work with a company proxy.



Spring Cloud AWS proxy configuration

Java configuration

Let’s start with ever more popular way of configuring Spring applications – Java configuration. Things are relatively simple in this case since you can provide required proxy configuration manually in code yourself. Consider the following configuration class declaring two beans – S3 client and proxy configuration (if these settings are not resolved from property files / properties default no-proxy connection will be used).

S3 client configuration sample from ApplicationConfiguration class @Configuration @EnableContextInstanceData public final class ApplicationConfiguration { @Value("${proxy.host}") private String proxyHost; @Value("${proxy.port}") private int proxyPort; @Value("${proxy.username}") private String proxyUsername; @Value("${proxy.password}") private String proxyPassword; @Bean public AmazonS3Client amazonS3Client() { return new AmazonS3Client(clientConfiguration()); } @Bean public ClientConfiguration clientConfiguration() { final ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setProxyHost(proxyHost); clientConfiguration.setProxyPort(proxyPort); clientConfiguration.setProxyUsername(proxyUsername); clientConfiguration.setProxyPassword(proxyPassword); return clientConfiguration; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Configuration @EnableContextInstanceData public final class ApplicationConfiguration { @Value ( "${proxy.host}" ) private String proxyHost ; @Value ( "${proxy.port}" ) private int proxyPort ; @Value ( "${proxy.username}" ) private String proxyUsername ; @Value ( "${proxy.password}" ) private String proxyPassword ; @Bean public AmazonS3Client amazonS3Client ( ) { return new AmazonS3Client ( clientConfiguration ( ) ) ; } @Bean public ClientConfiguration clientConfiguration ( ) { final ClientConfiguration clientConfiguration = new ClientConfiguration ( ) ; clientConfiguration . setProxyHost ( proxyHost ) ; clientConfiguration . setProxyPort ( proxyPort ) ; clientConfiguration . setProxyUsername ( proxyUsername ) ; clientConfiguration . setProxyPassword ( proxyPassword ) ; return clientConfiguration ; } }

Given the implications of code like this consider marking this class with profile used to run the application on developers machine e.g. @Profile("local") .

XML configuration

When it comes to proxy configuration using XML configuration certain degree of Spring configuration knowledge is required. In order to make this simple configuration work, we need to create the instance of AmazonS3Client with proxy settings stored in client configuration bean. Following XML file shows the entire configuration so lets break it down into several sections.

beans.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/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 http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd"> <context:component-scan base-package="com.jakubstas.s3downloader"/> <!-- Bunch of simple configuration switches allowing access to instance metadata, integration of S3 into ResourceLoader and region auto detection. Some of these are not essential for the example however it is always nice to have the information they provide at hand when needed. --> <aws-context:context-instance-data/> <aws-context:context-resource-loader/> <aws-context:context-region auto-detect="true"/> <!-- Configuration of Amazons credentials provider chain to allow execution on developers machine as well as in the Beanstalk environment. --> <aws-context:context-credentials> <aws-context:instance-profile-credentials/> <aws-context:simple-credentials access-key="#{systemProperties['AWS_ACCESS_KEY_ID']}" key="#{systemProperties['AWS_SECRET_KEY']}"/> </aws-context:context-credentials> <!-- Bean with client configuration with passed proxy settings (if these settings are not resolved from property files / properties default no-proxy connection will be used) --> <!-- The client instance created by hand with proxy configuration --> <bean id="amazonS3" class="com.amazonaws.services.s3.AmazonS3Client" autowire-candidate="true" autowire="constructor"/> <!-- Proxy configuration for any AWS related client code - currently used for S3 (but might as well be used for DynamoDB access, ...) --> <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration"> <property name="proxyHost" value="${proxy.host}"/> <property name="proxyPort" value="${proxy.port}"/> <property name="proxyUsername" value="${proxy.username}"/> <property name="proxyPassword" value="${proxy.password}"/> </bean> </beans> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <? xml version = "1.0" encoding = "UTF-8" ?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns : context = "http://www.springframework.org/schema/context" xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns : aws-context = "http://www.springframework.org/schema/cloud/aws/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 http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd" > <context:component-scan base-package = "com.jakubstas.s3downloader" /> <!-- Bunch of simple configuration switches allowing access to instance metadata, integration of S3 into ResourceLoader and region auto detection. Some of these are not essential for the example however it is always nice to have the information they provide at hand when needed. --> <aws-context:context-instance-data/> <aws-context:context-resource-loader/> <aws-context:context-region auto-detect = "true" /> <!-- Configuration of Amazons credentials provider chain to allow execution on developers machine as well as in the Beanstalk environment. --> <aws-context:context-credentials> <aws-context:instance-profile-credentials/> <aws-context:simple-credentials access-key = "#{systemProperties['AWS_ACCESS_KEY_ID']}" key = "#{systemProperties['AWS_SECRET_KEY']}" /> </aws-context:context-credentials> <!-- Bean with client configuration with passed proxy settings (if these settings are not resolved from property files / properties default no-proxy connection will be used) --> <!-- The client instance created by hand with proxy configuration --> <bean id = "amazonS3" class = "com.amazonaws.services.s3.AmazonS3Client" autowire-candidate = "true" autowire = "constructor" /> <!-- Proxy configuration for any AWS related client code - currently used for S3 (but might as well be used for DynamoDB access, ...) --> <bean id = "clientConfiguration" class = "com.amazonaws.ClientConfiguration" > <property name = "proxyHost" value = "${proxy.host}" /> <property name = "proxyPort" value = "${proxy.port}" /> <property name = "proxyUsername" value = "${proxy.username}" /> <property name = "proxyPassword" value = "${proxy.password}" /> </bean> </beans>

Given the implications of code like this consider marking these beans with profile used to run the application on developers machine e.g. profile="local" .

Going beyond S3

The example so far was pretty much restricted to S3. However this configuration can be used whenever applicable due to the way Amazon SDK was designed. Let’s take a look at the example of DynomoDB client. There are several clients for various Amazon AWS services that can make use of the approach discussed above.

DynamoDB client configuration sample from ApplicationConfiguration class @Configuration @EnableContextInstanceData public final class ApplicationConfiguration { @Value("${proxy.host}") private String proxyHost; @Value("${proxy.port}") private int proxyPort; @Value("${proxy.username}") private String proxyUsername; @Value("${proxy.password}") private String proxyPassword; @Bean public AmazonS3 amazonS3Client() { return new AmazonS3Client(clientConfiguration()); } @Bean public AmazonDynamoDBClient amazonDynamoDBClient() { return new AmazonDynamoDBClient(clientConfiguration()); } @Bean public ClientConfiguration clientConfiguration() { final ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setProxyHost(proxyHost); clientConfiguration.setProxyPort(proxyPort); clientConfiguration.setProxyUsername(proxyUsername); clientConfiguration.setProxyPassword(proxyPassword); return clientConfiguration; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 @Configuration @EnableContextInstanceData public final class ApplicationConfiguration { @Value ( "${proxy.host}" ) private String proxyHost ; @Value ( "${proxy.port}" ) private int proxyPort ; @Value ( "${proxy.username}" ) private String proxyUsername ; @Value ( "${proxy.password}" ) private String proxyPassword ; @Bean public AmazonS3 amazonS3Client ( ) { return new AmazonS3Client ( clientConfiguration ( ) ) ; } @Bean public AmazonDynamoDBClient amazonDynamoDBClient ( ) { return new AmazonDynamoDBClient ( clientConfiguration ( ) ) ; } @Bean public ClientConfiguration clientConfiguration ( ) { final ClientConfiguration clientConfiguration = new ClientConfiguration ( ) ; clientConfiguration . setProxyHost ( proxyHost ) ; clientConfiguration . setProxyPort ( proxyPort ) ; clientConfiguration . setProxyUsername ( proxyUsername ) ; clientConfiguration . setProxyPassword ( proxyPassword ) ; return clientConfiguration ; } }

Conclusion

Passing the application configuration to your beans is pretty standard task that should not cause a lot of trouble to an experienced Spring developer. However given the varying level of experience and hurdles of day to day life of a developer this might cause trouble. This is why I would encourage anyone to try these examples on their own, since situation modeled here uses one of the fundamental approaches to Spring configuration design. Keep practicing and keep that corporate proxy at bay. 🙂