KeyGenerator의 새로운 인터페이스 추가 여부 검토
Closed this issue · 5 comments
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;
}
}
#61 PR에 대해 오프라인으로 논의하며 잠시 이 이슈에 대해 이야기 한 적이 있는데요.
정확히 첫번째 코멘트와 동일한 형태의 구현은 아니어도, Object generate(Object... params)
형태의 인터페이스가 필요하다는 것에는 동의를 했던 기억이 납니다.
이 인터페이스의 추가 작업을 진행하도록 할까요?
@oliviarla 이에 대해서는 어떻게 생각하나요?
Spring에서 KeyGenerator interface 살펴보니, 아래 method만 정의되어 있습니다.
- public Object generate(Object target, Method method, Object... params)
KeyGenerator 구현한 SimpleKeyGenerator 확인해 보니 2가지 메소드가 있습니다.
- public Object generate(Object target, Method method, Object... params)
- public static Object generateKey(Object... params)
위에 언급한 기능은 generateKey()
메소드로 제공하는 것이 좋겠습니다.
@jhpark816 님이 말씀하신 것 처럼 public static Object generateKey(Object... params)
메서드를 제공하면 될 것 같습니다.