Skip to content

Commit

Permalink
perf($Cache): support Guava cache for cacheFunction
Browse files Browse the repository at this point in the history
[skip ci]
  • Loading branch information
johnnymillergh committed Sep 29, 2021
1 parent 554406c commit 7497cdb
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 23 deletions.
74 changes: 51 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,44 @@ Here is the highlights of **Muscle and Fitness Server**:
- For Spring MVC, [spring-cloud-starter](https://github.com/johnnymillergh/muscle-and-fitness-server/tree/master/spring-cloud-starter)
- For Spring WebFlux, [reactive-spring-cloud-starter](https://github.com/johnnymillergh/muscle-and-fitness-server/tree/master/reactive-spring-cloud-starter)

4. PMD code quality check for each every CI (during Maven verify phase), with [Alibaba-p3c](https://github.com/alibaba/p3c) rulesets
4. PMD code quality check for each every CI (during Maven verify phase), with [Alibaba-p3c](https://github.com/alibaba/p3c) rulesets.

5. Secured API. [RBAC](https://en.wikipedia.org/wiki/Role-based_access_control) by API gateway and Auth Center. JWT authentication, and RBAC authorization.
5. Advocate 𝛌 Java Functional Programming, provide developers with powerful and useful functions to make Java more sweeter.

6. [MySQL Replication for High Availability](https://severalnines.com/resources/database-management-tutorials/mysql-replication-high-availability-tutorial). Multi data source. [Dynamic SQL read-write isolation](https://baomidou.com/guide/dynamic-datasource.html). [MyBatis-Plus](https://github.com/baomidou/mybatis-plus) is the integrated ORM library. [Druid](https://github.com/alibaba/druid) is the database connection pool. Dynamically enhance connection pool size by CPU count (logical processor count). Read more at [How to Find the Optimal Database Connection Pool Size](https://wiki.postgresql.org/wiki/Number_Of_Database_Connections#How_to_Find_the_Optimal_Database_Connection_Pool_Size), [Sizing the Connection Pool](https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-usagenotes-j2ee-concepts-connection-pooling.html#idm46216069663472).
6. Secured API. [RBAC](https://en.wikipedia.org/wiki/Role-based_access_control) by API gateway and Auth Center. JWT authentication, and RBAC authorization.

7. Redis 6.x support. [Master-slave replication for high availability](https://redis.io/topics/replication). Redis cluster.
7. [MySQL Replication for High Availability](https://severalnines.com/resources/database-management-tutorials/mysql-replication-high-availability-tutorial). Multi data source. [Dynamic SQL read-write isolation](https://baomidou.com/guide/dynamic-datasource.html). [MyBatis-Plus](https://github.com/baomidou/mybatis-plus) is the integrated ORM library. [Druid](https://github.com/alibaba/druid) is the database connection pool. Dynamically enhance connection pool size by CPU count (logical processor count). Read more at [How to Find the Optimal Database Connection Pool Size](https://wiki.postgresql.org/wiki/Number_Of_Database_Connections#How_to_Find_the_Optimal_Database_Connection_Pool_Size), [Sizing the Connection Pool](https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-usagenotes-j2ee-concepts-connection-pooling.html#idm46216069663472).

8. Docker, Rancher Kubernetes support. Google JIB for building Docker container images.
8. Redis 6.x support. [Master-slave replication for high availability](https://redis.io/topics/replication). Redis cluster.

9. OSS service, based on [Minio](https://min.io/) and SFTP integration. Asynchronous [Progressive Download](https://www.nginx.com/resources/glossary/progressive-download/) resources. Chunked resource upload. The media player will play back that content using sequential byte-range requests. Refers to [a request for partial content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) (HTTP 206). This type of request is typically used to retrieve a large asset in smaller segments. This technique is employed by HTTP Progressive Download to avoid long buffering times.
9. Docker, Rancher Kubernetes support. Google JIB for building Docker container images.

10. [STOMP over WebSocket](https://www.toptal.com/java/stomp-spring-boot-websocket) (SockJS), real time messaging, based on [RabbitMQ STOMP](https://www.rabbitmq.com/stomp.html) message broker.
10. OSS service, based on [Minio](https://min.io/) and SFTP integration. Asynchronous [Progressive Download](https://www.nginx.com/resources/glossary/progressive-download/) resources. Chunked resource upload. The media player will play back that content using sequential byte-range requests. Refers to [a request for partial content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) (HTTP 206). This type of request is typically used to retrieve a large asset in smaller segments. This technique is employed by HTTP Progressive Download to avoid long buffering times.

11. [Quartz](http://www.quartz-scheduler.org/) support. Distributed job scheduling, based on JDBC. Dynamic Quartz job configuration, served by served by database configuration
table `quartz_job_configuration`. Reduce lots of Quartz job and trigger boilerplate codes.
11. [STOMP over WebSocket](https://www.toptal.com/java/stomp-spring-boot-websocket) (SockJS), real time messaging, based on [RabbitMQ STOMP](https://www.rabbitmq.com/stomp.html) message broker.

12. Multi-environment support.
12. [Quartz](http://www.quartz-scheduler.org/) support. Distributed job scheduling, based on JDBC. Dynamic Quartz job configuration, served by served by database configuration table `quartz_job_configuration`. Reduce lots of Quartz job and trigger boilerplate codes.

13. [Knife4j](https://doc.xiaominfo.com/) API visualization. Enhanced Swagger API documentation.
13. Multi-environment support.

14. [Async log output](https://examples.javacodegeeks.com/enterprise-java/logback/logback-ayncappender-example/). Log file compressed by standard GNU zip ([gzip](https://en.wikipedia.org/wiki/Gzip)) compression algorithm. [ELK](https://www.elastic.co/what-is/elk-stack) log aggregation.
14. [Knife4j](https://doc.xiaominfo.com/) API visualization. Enhanced Swagger API documentation.

15. JVM log configuration for JVM garbage collection.
15. [Async log output](https://examples.javacodegeeks.com/enterprise-java/logback/logback-ayncappender-example/). Log file compressed by standard GNU zip ([gzip](https://en.wikipedia.org/wiki/Gzip)) compression algorithm. [ELK](https://www.elastic.co/what-is/elk-stack) log aggregation.

16. AOP based request log, configurable for turning on or off.
16. JVM log configuration for JVM garbage collection.

17. Customized method argument validation.
17. AOP based request log, configurable for turning on or off.

18. Customized method argument validation.

- [Date time range validator](https://github.com/johnnymillergh/muscle-and-fitness-server/blob/master/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/validation/validator/DateTimeRangeValidator.java)
- [Enum value validator](https://github.com/johnnymillergh/muscle-and-fitness-server/blob/master/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/validation/validator/EnumValueValidator.java)

18. Docker container log persistence. Size and time based rolling policy.
19. Docker container log persistence. Size and time based rolling policy.

19. [Startup and deployment statistics](https://github.com/johnnymillergh/muscle-and-fitness-server/blob/master/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/helper/SpringBootStartupHelper.java).
20. [Startup and deployment statistics](https://github.com/johnnymillergh/muscle-and-fitness-server/blob/master/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/helper/SpringBootStartupHelper.java).

20. Customized startup banner.
21. Customized startup banner.

## Usage

Expand Down Expand Up @@ -119,22 +120,49 @@ Here is the highlights of **Muscle and Fitness Server**:

1. Install global dependencies (optional if installed):

```
npm install -g conventional-changelog-cli
```sh
$ npm install -g conventional-changelog-cli
```

2. This will *not* overwrite any previous changelogs. The above generates a changelog based on commits since the last semver tag that matches the pattern of "Feature", "Fix", "Performance Improvement" or "Breaking Changes".

```
conventional-changelog -p angular -i CHANGELOG.md -s
```sh
$ conventional-changelog -p angular -i CHANGELOG.md -s
```

3. If this is your first time using this tool and you want to generate all previous changelogs, you could do:

```sh
$ conventional-changelog -p angular -i CHANGELOG.md -s -r 0
```

## 𝛌 Example

1. Require the expression to be true, otherwise throws an exception (if provided).

```java
import static com.jmsoftware.maf.springcloudstarter.function.BooleanCheck.requireTrue;
requireTrue(1 != 1, anotherBoolean -> log.info("aBoolean = {}", anotherBoolean))
.orElseThrow(() -> new IllegalArgumentException("aBoolean is expected to be true"));
```
conventional-changelog -p angular -i CHANGELOG.md -s -r 0

2. Make Function have cache ability.

```java
val cacheMap = Maps.<String, String>newHashMap();
cacheMap.put("key1", "1");
cacheMap.put("key2", "2");
final Function<String, String> stringProcess = input -> {
log.info("No cache return value found. input: {} Re-calculating…", input);
return StrUtil.subSuf(input, 3);
};
val result1 = cacheFunction(stringProcess, "key1", cacheMap);
val result2 = cacheFunction(stringProcess, "key2", cacheMap);
val result3 = cacheFunction(stringProcess, "key3", cacheMap);
```


## CI (Continuous Integration)

- [Travis CI](https://travis-ci.com/github/johnnymillergh/media-streaming) is for publishing Docker Hub images of SNAPSHOT and RELEASE.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
* @see <a href='https://juejin.cn/post/6892298625058078727#heading-2'>Java 函数式编程最佳实践 - 赋予函数缓存能力</a>
**/
public class Cache {
private Cache() {
}

/**
* Cache function r.
*
Expand All @@ -32,4 +35,25 @@ public static <T, R> R cacheFunction(Function<T, R> function, T t, Map<T, R> cac
cache.put(t, result);
return result;
}

/**
* Cache function r.
*
* @param <T> the type parameter
* @param <R> the type parameter
* @param function the function
* @param t the t
* @param cache the cache
* @return the r
* @see com.jmsoftware.maf.springcloudstarter.FunctionalInterfaceTests#testCacheFunction()
*/
public static <T, R> R cacheFunction(Function<T, R> function, T t, com.google.common.cache.Cache<T, R> cache) {
R r = cache.getIfPresent(t);
if (r != null) {
return r;
}
R result = function.apply(t);
cache.put(t, result);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* @see <a href='https://juejin.cn/post/6892298625058078727#heading-4'>Java 函数式编程最佳实践 - 赋予函数处理异常的能力</a>
**/
public class ExceptionHandling {
private ExceptionHandling() {
}

/**
* Compute and deal exception r.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
* @see <a href='https://juejin.cn/post/6892298625058078727#heading-3'>Java 函数式编程最佳实践 - 赋予函数报错返回默认值能力</a>
**/
public class ExceptionReturnDefault {
private ExceptionReturnDefault() {
}

/**
* Compute or get default r.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
**/
@Slf4j
public class FunctionLog {
private FunctionLog() {
}

/**
* Log function r.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* @see <a href='https://juejin.cn/post/6892298625058078727#heading-1'>Java 函数式编程最佳实践 - 赋予方法重试能力</a>
**/
public class Retry {
private Retry() {
}

/**
* Retry function.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.jmsoftware.maf.springcloudstarter;

import cn.hutool.core.util.StrUtil;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.jmsoftware.maf.springcloudstarter.function.functionalinterface.ThrowExceptionFunction;
import com.jmsoftware.maf.springcloudstarter.function.functionalinterface.ThrowExceptionRunnable;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.junit.jupiter.api.Assertions;
Expand All @@ -19,6 +21,7 @@
import static com.jmsoftware.maf.springcloudstarter.function.ExceptionReturnDefault.computeOrGetDefault;
import static com.jmsoftware.maf.springcloudstarter.function.FunctionLog.logFunction;
import static com.jmsoftware.maf.springcloudstarter.function.Retry.retryFunction;
import static fj.Show.anyShow;

/**
* FunctionalInterfaceTests
Expand Down Expand Up @@ -47,6 +50,7 @@ void testRequireTrue() {
* Test cache function.
*/
@Test
@SneakyThrows
void testCacheFunction() {
val cacheMap = Maps.<String, String>newHashMap();
cacheMap.put("key1", "1");
Expand All @@ -62,6 +66,27 @@ void testCacheFunction() {
Assertions.assertEquals("2", result2);
Assertions.assertEquals("3", result3);
Assertions.assertEquals(3, cacheMap.size());

val guavaCache = CacheBuilder
.newBuilder()
.maximumSize(2)
.expireAfterWrite(Duration.ofSeconds(3))
.<String, String>removalListener(notification -> log.info("Removed cache: {}", notification))
.build();
guavaCache.put("key4", "4");
guavaCache.put("key5", "5");
val result4 = cacheFunction(stringProcess, "key4", guavaCache);
val result5 = cacheFunction(stringProcess, "key5", guavaCache);
val result6 = cacheFunction(stringProcess, "key6", guavaCache);
anyShow().print("Before cache invalidated: ");
anyShow().println(guavaCache.asMap().entrySet());
Assertions.assertEquals("4", result4);
Assertions.assertEquals("5", result5);
Assertions.assertEquals("6", result6);
Thread.sleep(Duration.ofSeconds(4).toMillis());
Assertions.assertNull(guavaCache.getIfPresent("key5"), "The value of Guava cache map is supposed to be null");
anyShow().print("After cache invalidated: ");
anyShow().println(guavaCache.asMap().entrySet());
}

@Test
Expand Down

0 comments on commit 7497cdb

Please sign in to comment.