Skip to content

ericdallo/spring-s3-properties-loader

Repository files navigation

Build Status

Spring S3 Property Loader

S3 Property Loader has the aim of allowing loading of Spring property files from S3 bucket, in order to guarantee stateless machine configuration.

Spring PropertyConfigurer uses PropertiesFactoryBean to load property files from AWS S3 bucket.

Install

Gradle:

repositories {  
   jcenter()  
}
compile "com.spring.loader:s3-loader:3.0.0"

Maven:

<dependency>
  <groupId>com.spring.loader</groupId>
  <artifactId>s3-loader</artifactId>
  <version>3.0.0</version>
  <type>pom</type>
</dependency>

How to use

  • Adding this annotation to any spring managed bean
@S3PropertiesLocation("my-bucket/my-folder/my-properties.yaml")
  • Using a specific profile to only load properties if the app is running with that profile
@S3PropertiesLocation(value = "my-bucket/my-folder/my-properties.properties", profiles = "production")
  • Load from a System env variable
@S3PropertiesLocation(value = "${AWS_S3_LOCATION}", profiles = "developer")
// or
@S3PropertiesLocation(value = "${AWS_S3_BUCKET}/application/my.properties", profiles = "developer")

Binding properties to a POJO

You can bind the externally loaded properties to a POJO as well.

For e.g., if you have a YAML file as

zuul:
  routes:
    query1:
      path: /api/apps/test1/query/**
      stripPrefix: false
      url: "https://test.url.com/query1"
    query2:
      path: /api/apps/test2/query/**
      stripPrefix: false
      url: "https://test.url.com/query2"
    index1:
      path: /api/apps/*/index/**
      stripPrefix: false
      url: "https://test.url.com/index"

Then you can bind the properties to a POJO using ConfigurationProperties:

@Component
@ConfigurationProperties("zuul")
public class RouteConfig {
    private Map<String, Map<String, String>> routes = new HashMap<>();

    public void setRoutes(Map<String, Map<String, String>> routes) {
        this.routes = routes;
    }

    public Map<String, Map<String, String>> getRoutes() {
        return routes;
    }
}

// or

@Component
@ConfigurationProperties("zuul")
public class RouteConfig {
    private Map<String, Route> routes;

    public void setRoutes(Map<String, Route> routes) {
        this.routes = routes;
    }

    public Map<String, Route> getRoutes() {
        return routes;
    }

    public static class Route {
        private String path;
        private boolean stripPrefix;
        String url;

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public boolean isStripPrefix() {
            return stripPrefix;
        }

        public void setStripPrefix(boolean stripPrefix) {
            this.stripPrefix = stripPrefix;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        @Override
        public String toString() {
            try {
                return new ObjectMapper().writeValueAsString(this);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return this.toString();
        }
    }

    @Override
    public String toString() {
        try {
            return new ObjectMapper().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return this.toString();
    }
}

Refreshing properties in runtime

You can force your application to load properties from S3 again without restart. S3 Properties Loader uses a Spring Cloud feature that allows the spring beans annotated with @RefreshScope to reload properties. To work, it is only necessary to inject the S3PropertiesContext bean and call refresh() method. After this, S3 Properties Loader will get properties again from s3 bucket defined previously and refresh your beans annotated with @RefreshScope.

tip: You can create a endpoint that calls this class and refresh your application via endpoint or create a @Scheduled class which updates from time to time.

Example:

@RestController
public SomeController {

   @Autowired
   private S3PropertiesContext s3PropertiesContext;
    
   @PostMapping("/refresh-properties")
   public void refresh() {
       s3PropertiesContext.refresh();
   }
}

Requisites

Official spring aws sdk lib.

Problems and Issues

Found some bug? Have some enhancement ? Open a Issue here