[SPRING] 런타임“qualifier”변수를 사용하여 서비스를 동적으로 주입하는 방법은 무엇입니까?
SPRING런타임“qualifier”변수를 사용하여 서비스를 동적으로 주입하는 방법은 무엇입니까?
런타임 값이 주어진 구성 요소 / 서비스를 주입하는 간단한 방법을 찾을 수 없습니다.
@ Spring의 문서를 읽기 시작했습니다 : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers 그러나 @Qualifier 주석에 전달 된 값을 variabilize하는 방법을 찾을 수 없습니다.
그런 인터페이스를 가진 모델 엔터티가 있다고 가정 해 봅시다.
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
내 클라이언트 코드에서 다음과 같은 작업을 수행합니다.
@Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
... 내 서비스는 다음과 같습니다.
@Service
public class DoService {
@Inject
// FIXME what kind of #$@& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
@Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
caseService가 UKCaseService가 될 것으로 예상합니다 (아래 관련 코드 참조).
public interface CaseService {
void modify(Case caze);
}
@Service
@Qualifier("uk")
public class UKCaseService implements CaseService {
}
@Service
@Qualifier("us")
public class USCaseService implements CaseService {
}
따라서 스프링 기능 중 하나를 사용하여 가장 간단하고 우아하고 효율적인 방식 으로이 모든 것을 어떻게 "고정"합니까? 본질적으로 NO .properties, NO XML, 주석 만 있습니다. 그러나 Spring은 caseService를 주입하기 전에 "case"를 알아야하기 때문에 DoService에서 무언가 잘못되었다고 생각합니다 ...하지만 클라이언트 코드가 caseService에 대해 알지 못하고 이것을 달성하는 방법은 무엇입니까?! 나는 이것을 알아낼 수 없다 ...
나는 이미 여기에 몇 가지 문제를 읽었지만 대부분의 경우 실제로는 내가 필요로하는 것과 동일한 요구 및 / 또는 구성을 가지고 있지 않거나 게시 된 답변이 나에게 만족스럽지 않습니다 (필수 사항처럼 보입니다) 해결 방법 또는 (이전) Spring 기능의 (이전) 사용법).
일치하는 Bean이 둘 이상있을 때 Spring은 이름으로 어떻게 자동 와이어 링합니까? =>는 컴포넌트와 유사한 클래스만을 참조합니다
스프링에서 자동으로 연결할 Bean을 동적으로 정의 (자격자 사용) => 정말로 흥미롭지 만 가장 정교하게 대답 된 답변 (4 투표)은 ... 거의 3 1/2 세입니다! (2013 7 월)
Spring 3-다른 객체 속성을 기반으로 런타임에 동적 자동 배선 => 여기에서 매우 비슷한 문제이지만 대답은 실제로 실제 디자인 패턴 (공장과 같은)과 같은 해결책입니까? 그리고 모든 코드를 ServiceImpl에 구현하는 것을 좋아하지 않습니다 ...
Spring @Autowiring, 객체 팩토리를 사용하여 구현을 선택하는 방법은 무엇입니까? => 두 번째 대답은 흥미롭게 보이지만 그 저자는 확장되지 않으므로 Java Config & stuff에 대해 조금 알지만, 그가 무엇을 이야기하고 있는지 잘 모르겠습니다 ...
XML이없는 Spring의 속성을 기반으로 런타임에 다른 서비스를 주입하는 방법 => 흥미로운 토론, 특히 대답은 있지만 사용자에게는 속성이 설정되어 있지만 내가 가지고 있지 않습니다.
또한 이것을 읽으십시오 : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references => 식에서 "@"사용에 대한 확장 된 예를 찾을 수 없습니다. 누군가 이것에 대해 알고 있습니까?
편집하다: 다른 유사한 문제를 발견했지만 아무도 정답을 얻지 못했습니다. @Autowired를 사용하여 팩토리 패턴과 같은 구현을 동적으로 주입하는 방법 스프링 한정자 및 속성 자리 표시 자 스프링 : 속성 자리 표시 자와 함께 @Qualifier 사용 봄에 조건부 자동 배선을 수행하는 방법은 무엇입니까? 스프링의 동적 주입 @Qualifier의 SpEL은 동일한 Bean을 참조합니다. SpEL을 사용하여 Spring에서 메소드 호출 결과를 주입하는 방법은 무엇입니까?
팩토리 패턴이 해결책일까요? @Autowired를 사용하여 팩토리 패턴과 같은 구현을 동적으로 주입하는 방법
해결법
-
==============================
1.BeanFactory를 사용하여 이름으로 컨텍스트에서 Bean을 동적으로 얻을 수 있습니다.
BeanFactory를 사용하여 이름으로 컨텍스트에서 Bean을 동적으로 얻을 수 있습니다.
@Service public class Doer { @Autowired BeanFactory beans; public void doSomething(Case case){ CaseService service = beans.getBean(case.getCountryCode(), CaseService.class) service.doSomething(case); } }
참고 사항. 국가 이름과 같은 것을 빈 이름으로 사용하는 것은 약간 이상하게 보입니다. 접두사를 적어도 추가하거나 다른 디자인 패턴을 고려하는 것이 좋습니다.
국가별로 콩을 갖고 싶다면 다른 접근법을 제안합니다. 국가 코드별로 필요한 서비스를 받으려면 레지스트리 서비스를 도입하십시오.
@Service public class CaseServices { private final Map<String, CaseService> servicesByCountryCode = new HashMap<>(); @Autowired public Cases(List<CaseService> services){ for (CaseService service: services){ register(service.getCountryCode(), service); } } public void register(String countryCode, CaseService service) { this.servicesByCountryCode.put(countryCode, service); } public CaseService getCaseService(String countryCode){ return this.servicesByCountryCode.get(countryCode); } }
사용법 예 :
@Service public class DoService { @Autowired CaseServices caseServices; public void doSomethingWith(Case case){ CaseService service = caseServices.getCaseService(case.getCountryCode()); service.modify(case); } }
이 경우 CaseService 인터페이스에 String getCountryCode () 메소드를 추가해야합니다.
public interface CaseService { void modify(Case case); String getCountryCode(); }
또는 CaseService.supports (Case case) 메소드를 추가하여 서비스를 선택할 수 있습니다. 또는 인터페이스를 확장 할 수없는 경우 일부 초 기자 또는 @Configuration 클래스에서 CaseServices.register (String, CaseService) 메소드를 호출 할 수 있습니다.
업데이트 : Spring은 이미 PluginRegistry를 생성하기 위해 상용구 코드를 재사용하기 위해 멋진 플러그인 추상화를 제공한다는 것을 언급하지 않았습니다.
예:
public interface CaseService extends Plugin<String>{ void doSomething(Case case); } @Service @Priority(0) public class SwissCaseService implements CaseService { void doSomething(Case case){ // Do something with the Swiss case } boolean supports(String countryCode){ return countryCode.equals("CH"); } } @Service @Priority(Ordered.LOWEST_PRECEDENCE) public class DefaultCaseService implements CaseService { void doSomething(Case case){ // Do something with the case by-default } boolean supports(String countryCode){ return true; } } @Service public class CaseServices { private final PluginRegistry<CaseService<?>, String> registry; @Autowired public Cases(List<CaseService> services){ this.registry = OrderAwarePluginRegistry.create(services); } public CaseService getCaseService(String countryCode){ return registry.getPluginFor(countryCode); } }
-
==============================
2.이 SO 답변에 따르면 @Qualifier를 사용하면 많은 도움이되지 않습니다 : 한정자로 ApplicationContext에서 Bean 가져 오기
이 SO 답변에 따르면 @Qualifier를 사용하면 많은 도움이되지 않습니다 : 한정자로 ApplicationContext에서 Bean 가져 오기
대체 전략에 관해서는 :
유스 케이스는 애플리케이션 시작시 Bean이 작성되는 시나리오를 중심으로 돌아가지만 applicationContext가 Bean 주입을 완료 한 후에 선택한 Bean을 해결해야합니다.
from https://stackoverflow.com/questions/42909283/how-to-dynamically-inject-a-service-using-a-runtime-qualifier-variable by cc-by-sa and MIT license