Skip to content

Commit

Permalink
setup redis as cache and SNS subscriber to support CDN
Browse files Browse the repository at this point in the history
  • Loading branch information
akirasosa committed Mar 11, 2016
1 parent 0faedf7 commit 9d16232
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This repository is an example application for Spring Boot and Angular2 tutorial.
Run Spring Boot.

```
redis-server /usr/local/etc/redis.conf # use redis as cache storage
mvn spring-boot:run
```

Expand Down
18 changes: 14 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
Expand All @@ -74,14 +78,17 @@
<artifactId>querydsl-sql-spring</artifactId>
<version>${querydsl.version}</version>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
Expand Down Expand Up @@ -191,8 +198,11 @@
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
<outputDirectory>target/generated-sources/java
</outputDirectory>
<processor>
com.querydsl.apt.jpa.JPAAnnotationProcessor
</processor>
</configuration>
</execution>
</executions>
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/myapp/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@ protected SpringApplicationBuilder configure(SpringApplicationBuilder applicatio
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

1 change: 1 addition & 0 deletions src/main/java/com/myapp/config/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ public class AppConfig {
public static final String PREFIX = "app";

private String assetHost;
private String assetManifestUrl;
}
25 changes: 25 additions & 0 deletions src/main/java/com/myapp/config/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.myapp.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;

/**
* I want to use {@link org.springframework.cloud.aws.cache.config.annotation.EnableElastiCache}
* which supports cluster for prod environment. But it has a problem shown on https://github.com/spring-cloud/spring-cloud-aws/issues/93 .
* As a result, I use a single redis server through RedisCacheManager.
*/
@Configuration
@EnableCaching
public class CacheConfig {

@Bean
@Autowired
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
}
1 change: 0 additions & 1 deletion src/main/java/com/myapp/config/QueryDSLConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;


@Configuration
public class QueryDSLConfig {

Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/myapp/controller/AssetManifestSubscriber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.myapp.controller;

import com.myapp.service.AssetManifestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sns/Micropost-AssetManifest-Updated")
public class AssetManifestSubscriber {

@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = LoggerFactory.getLogger(AssetManifestSubscriber.class);

private final AssetManifestService assetManifestService;

@Autowired
public AssetManifestSubscriber(AssetManifestService assetManifestService) {
this.assetManifestService = assetManifestService;
}


@RequestMapping(method = RequestMethod.POST)
public void handleNotificationMessage(@RequestBody String body) {
logger.info(body);
assetManifestService.invalidateCache();
}

}

9 changes: 7 additions & 2 deletions src/main/java/com/myapp/controller/MainController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.myapp.controller;

import com.myapp.config.AppConfig;
import com.myapp.service.AssetManifestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -9,21 +10,25 @@
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {
class MainController {

@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = LoggerFactory.getLogger(MainController.class);

private final AppConfig appConfig;

private final AssetManifestService assetManifestService;

@Autowired
public MainController(AppConfig appConfig) {
public MainController(AppConfig appConfig, AssetManifestService assetManifestService) {
this.appConfig = appConfig;
this.assetManifestService = assetManifestService;
}

@RequestMapping({"/**"})
public String index(Model model) {
model.addAttribute("assetHost", appConfig.getAssetHost());
model.addAttribute("manifest", assetManifestService.fetchAssetManifest());
return "index";
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/myapp/dto/AssetManifest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.myapp.dto;

import java.util.HashMap;
import java.util.Optional;

public class AssetManifest extends HashMap<String, String> {
@Override
public String get(Object key) {
return Optional.ofNullable(super.get(key)).orElse(key.toString());
}
}
51 changes: 51 additions & 0 deletions src/main/java/com/myapp/service/AssetManifestService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.myapp.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.myapp.config.AppConfig;
import com.myapp.dto.AssetManifest;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.IOException;

@Service
public class AssetManifestService {

@SuppressWarnings("unused")
private static final Logger logger = LoggerFactory.getLogger(AssetManifestService.class);

private final AppConfig appConfig;

@Autowired
public AssetManifestService(AppConfig appConfig) {
this.appConfig = appConfig;
}

@Cacheable("assetManifest")
public AssetManifest fetchAssetManifest() {
final OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url(appConfig.getAssetManifestUrl())
.build();
try {
final Response response = client.newCall(request).execute();
final String jsonStr = response.body().string();
return new ObjectMapper().readValue(jsonStr, AssetManifest.class);
} catch (IOException e) {
logger.info("manifest does not exist. fallback to default assets.");
return new AssetManifest(); // fallback
}
}

@CacheEvict("assetManifest")
public void invalidateCache() {
logger.info("the cache of asset manifest was invalidated.");
}
}
10 changes: 5 additions & 5 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ management:
app:
jwt:
secret: qwerty
asset-host: localhost:3001
asset-manifest-url: http://localhost:3001/manifest.json
---
spring:
profiles: dev
Expand All @@ -30,8 +32,6 @@ logging:
config: classpath:logback-dev.xml
flyway:
enabled: false
app:
asset-host: localhost:3001
---
spring:
profiles: test
Expand Down Expand Up @@ -64,8 +64,6 @@ spring:
ddl-auto: validate
logging:
config: classpath:logback-stg.xml
app:
asset-host: localhost:3001
---
spring:
profiles: prod
Expand All @@ -81,4 +79,6 @@ spring:
logging:
config: classpath:logback-prod.xml
app:
asset-host: springboot-angular2-tutorial.github.io/angular2-app
asset-host: cdn.hana053.com
asset-manifest-url: https://s3.amazonaws.com/cdn.hana053.com/manifest.json

4 changes: 2 additions & 2 deletions src/main/resources/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
</head>
<body>
<app />
<script th:src="|//${assetHost}/polyfills.js|"></script>
<script th:src="|//${assetHost}/main.js|"></script>
<script th:src="|//${assetHost}/${manifest.get('polyfills.js')}|"></script>
<script th:src="|//${assetHost}/${manifest.get('main.js')}|"></script>
<!-- Google Analytics: change UA-74585747-1 to be your site's ID -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
Expand Down

0 comments on commit 9d16232

Please sign in to comment.