Git Product home page Git Product logo

arcus-spring's People

Contributors

brido4125 avatar hjyun328 avatar hyeonjae avatar jhpark816 avatar kiheyunkim avatar lynix94 avatar minkikim89 avatar oliviarla avatar sanha avatar uhm0311 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arcus-spring's Issues

Setter에 null이 들어가지 않도록 수정

현재 코드 구현 상 아래와 같이 ArcusCache 객체 생성 시 setter로 데이터를 주입해주고 있다.
이 때 사용자가 configuration으로 설정하지 않은 필드는 null값을 가지게 되는데, 이를 그대로 setter에 넣어주어 null 값을 setter에 넣는 형태가 된다.
setter에 null을 입력하는 상황은 혼란을 줄 수 있으므로 setter에 값을 입력하기 전 null인지 검사하고 입력하거나, ArcusCache의 생성자에 ArcusCacheConfiguration 객체를 입력받도록 하는 방안이 괜찮아보인다.

@SuppressWarnings("deprecation")
protected Cache createCache(String name, ArcusCacheConfiguration configuration) {
  ArcusCache cache = new ArcusCache();
  cache.setName(name);
  cache.setServiceId(configuration.getServiceId());
  cache.setPrefix(configuration.getPrefix());
  cache.setArcusClient(client);
  cache.setArcusFrontCache(configuration.getArcusFrontCache());
  cache.setExpireSeconds(configuration.getExpireSeconds());
  cache.setFrontExpireSeconds(configuration.getFrontExpireSeconds());
  cache.setTimeoutMilliSeconds(configuration.getTimeoutMilliSeconds());
  cache.setOperationTranscoder(configuration.getOperationTranscoder());
  cache.setForceFrontCaching(configuration.isForceFrontCaching());
  cache.setWantToGetException(true);

  return cache;
}

createArcusKey()에서 arcusKey 생성 부분 수정.

현재 createArcusKey() 메소드에서 arcusKey 생성 부분이 아래와 같습니다.

  public String createArcusKey(final Object key) {
    String keyString, arcusKey;

    . . .
    arcusKey = serviceId + name + ":" + keyString;
    if (this.prefix != null) {
      arcusKey = serviceId + prefix + ":" + keyString;
    }
    . . .

    return arcusKey;
  }

위의 코드는 불필요하게 GC 부담을 가중시킬 수 있으므로, 아래와 변경하는 것이 좋겠습니다.

    if (this.prefix != null) {
      arcusKey = serviceId + prefix + ":" + keyString;
    } else {
      arcusKey = serviceId + name + ":" + keyString;
    }

사용자 가이드 문서 작성

1.13.4 버전 기준의 README의 내용을 포함하여 사용자 가이드 문서를 작성한다.

작성할 내용

  • arcus-spring 프로젝트의 개요
  • 의존성 추가 방법 (Maven, Gradle)
  • Bean 생성 방법
    • arcus-spring에서 제공하는 KeyGenerator 구현체 2가지에 대한 설명
  • Cacheable 어노테이션을 사용하는 예시
  • CacheManager를 사용하는 예시
  • FrontCache를 사용하는 예시
    • FrontCache를 사용하지 않을 때와 사용하는 경우의 각 연산에 대한 success, failure 표 작성
    • DefaultArcusFrontCache 사용법
  • 주의 사항
    • spring-devtools 사용 시 ClassLoader에 의한 버그 발생
    • ArcusCache 구현체의 캐시 키 생성 로직에 의한 강제 hash 값 붙임 현상

다음 버전 release 일정 문의

안녕하세요.
사내에서 스프링 latest 버전으로의 bump up을 준비하고 있는 프로젝트가 있습니다.
#63 PR이 반영된 다음 release 일정이 언제인지 알 수 있을까요?
가능하시다면 minor fix 버전으로라도 패치 해 주신다면 감사하겠습니다!

KeyGenerator의 새로운 인터페이스 추가 여부 검토

AS-IS

KeyGenerator

현재 KeyGenerator의 유일한 인터페이스는 다음과 같습니다.

Object generate(Object target, Method method, Object... params);

Implementation of KeyGenerator

단, 현재 구현 상 매개변수 target과 method는 사용하지 않습니다.

public class StringKeyGenerator implements KeyGenerator {
  @Override
  public Object generate(Object target, Method method, Object... params) {
    int hash = 0;
    StringBuilder keyBuilder = new StringBuilder();
    for (int i = 0, n = params.length; i < n; i++) {
      if (i > 0) {
        keyBuilder.append(DEFAULT_SEPARTOR);
      }
      if (params[i] != null) {
        keyBuilder.append(params[i]);
        hash ^= ArcusStringKey.light_hash(params[i].toString());
      }
    }

    return new ArcusStringKey(keyBuilder.toString().replace(' ', '_') + hash);
  }
}

public class SimpleStringKeyGenerator implements KeyGenerator {
  @Override
  public Object generate(Object target, Method method, Object... params) {
    StringBuilder keyBuilder = new StringBuilder();
    for (int i = 0, n = params.length; i < n; i++) {
      if (i > 0) {
        keyBuilder.append(DEFAULT_SEPARTOR);
      }
      if (params[i] != null) {
        keyBuilder.append(params[i]);
      }
    }
    return new ArcusStringKey(keyBuilder.toString());
  }
}

Usage

따라서 CacheManager를 직접 주입 받아 사용할 경우, KeyGenerator를 다음과 같이 사용해야 합니다.

@Service
public class ProductService {
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private KeyGenerator keyGenerator;

    /*
        using the "testCache" cache with 60 expire seconds and "TEST-PRODUCT" prefix.
    */
    public Product getProduct_TestCache(int id) {
      Product product = cacheManager.getCache("testCache")
              .get(keyGenerator.generate(null, null, id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }
    
    /*
        using the "devCache" cache with 120 expire seconds and "DEV-PRODUCT" prefix.
    */  
    public Product getProduct_DevCache(int id) {
      Product product = cacheManager.getCache("devCache")
              .get(keyGenerator.generate(null, null, id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }

    /*
        using the "missingCache" cache with 60 expire seconds and "DEFAULT" prefix.
    */
    public Product getProduct_DefaultCache(int id) {
      Product product = cacheManager.getCache("missingCache")
              .get(keyGenerator.generate(null, null, id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }
    
}

Issue

두 매개변수를 null로 주어도 내부적으로 사용하지 않으니 올바르게 동작하지만, 얼핏 코드를 보면 KeyGenerator를 사용하는 인터페이스가 잘못되었단 느낌을 받기 쉽습니다.

TO-BE

따라서 다음과 같은 클래스를 추가하여 매개변수에 null을 넣을 필요 없는 인터페이스를 오버로딩으로 제공하면 좋을 것 같습니다.

New Class

public abstract class ArcusKeyGenerator implements KeyGenerator {
  public Object generate(Object... params) {
    return generate(null, null, params);
  }
}

Implementation of KeyGenerator

public class StringKeyGenerator extends ArcusKeyGenerator { // 상속 관계 변경
  @Override
  public Object generate(Object target, Method method, Object... params) {
    int hash = 0;
    StringBuilder keyBuilder = new StringBuilder();
    for (int i = 0, n = params.length; i < n; i++) {
      if (i > 0) {
        keyBuilder.append(DEFAULT_SEPARTOR);
      }
      if (params[i] != null) {
        keyBuilder.append(params[i]);
        hash ^= ArcusStringKey.light_hash(params[i].toString());
      }
    }

    return new ArcusStringKey(keyBuilder.toString().replace(' ', '_') + hash);
  }
}

public class SimpleStringKeyGenerator extends ArcusKeyGenerator { // 상속 관계 변경
  @Override
  public Object generate(Object target, Method method, Object... params) {
    StringBuilder keyBuilder = new StringBuilder();
    for (int i = 0, n = params.length; i < n; i++) {
      if (i > 0) {
        keyBuilder.append(DEFAULT_SEPARTOR);
      }
      if (params[i] != null) {
        keyBuilder.append(params[i]);
      }
    }
    return new ArcusStringKey(keyBuilder.toString());
  }
}

Usage

@Service
public class ProductService {
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private ArcusKeyGenerator keyGenerator;

    /*
        using the "testCache" cache with 60 expire seconds and "TEST-PRODUCT" prefix.
    */
    public Product getProduct_TestCache(int id) {
      Product product = cacheManager.getCache("testCache")
              .get(keyGenerator.generate(id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }
    
    /*
        using the "devCache" cache with 120 expire seconds and "DEV-PRODUCT" prefix.
    */  
    public Product getProduct_DevCache(int id) {
      Product product = cacheManager.getCache("devCache")
              .get(keyGenerator.generate(id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }

    /*
        using the "missingCache" cache with 60 expire seconds and "DEFAULT" prefix.
    */
    public Product getProduct_DefaultCache(int id) {
      Product product = cacheManager.getCache("missingCache")
              .get(keyGenerator.generate(id), Product.class);
      
      if (product == null) {
        return new Product(id);
      }
      return product;
    }
    
}

Spring 5 Webflux의 Cacheable annotation 지원

Spring 5 Webflux 모델에서는 Spring Cache의 annotation을 사용할 수 없다.
WebFlux 모델에서는 실제 Value Object가 아닌 Flux, Mono가 리턴이 되는 구조이기 때문이다.

public Mono<Object> mono() {
   ...
}

Spring 5의 Webflux 모델에 대해 이해하고, WebFlux 구조에서 Cache를 쉽게 적용할 수 있는 방법에 대해 고민하고 arcus-spring에서 이를 지원할 수 있도록 한다.

참고

https://dreamchaser3.tistory.com/17
https://stackoverflow.com/questions/48156424/spring-webflux-and-cacheable-proper-way-of-caching-result-of-mono-flux-type

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.