복수의 실장이 있는 인터페이스를 자동 접속하는 스프링 부트
통상의 봄에서는, 인터페이스를 자동 접속하는 경우는, Spring 콘텍스트파일로 그 실장을 정의합니다.
- 스프링 부츠는 어때?
- 우리가 어떻게 이것을 달성할 수 있을까?
현재 인터페이스가 아닌 클래스만 자동 배선하고 있습니다.
이 질문의 또 다른 부분은 스프링 부트프로젝트 내의 Junit 클래스의 클래스 사용에 관한 것입니다.
예를 들어 Calendar Util을 사용하는 경우 Calendar Util을 자동 연결하면 늘 포인터 예외가 발생합니다.이 경우 우리가 할 수 있는 일은 무엇인가?지금은 "new"로 초기화했습니다.
사용하다@Qualifier
주석은 동일한 인터페이스의 콩을 구별하기 위해 사용됩니다.
Spring Boot 매뉴얼을 참조하십시오.
또, 같은 인터페이스의 모든 콩을 주입하려면 , 자동 배선만 하면 됩니다. List
인터페이스의
(스프링/스프링 부트/스프링 부트 테스트에서도 동일)
다음 예:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public interface MyService {
void doWork();
}
@Service
@Qualifier("firstService")
public static class FirstServiceImpl implements MyService {
@Override
public void doWork() {
System.out.println("firstService work");
}
}
@Service
@Qualifier("secondService")
public static class SecondServiceImpl implements MyService {
@Override
public void doWork() {
System.out.println("secondService work");
}
}
@Component
public static class FirstManager {
private final MyService myService;
@Autowired // inject FirstServiceImpl
public FirstManager(@Qualifier("firstService") MyService myService) {
this.myService = myService;
}
@PostConstruct
public void startWork() {
System.out.println("firstManager start work");
myService.doWork();
}
}
@Component
public static class SecondManager {
private final List<MyService> myServices;
@Autowired // inject MyService all implementations
public SecondManager(List<MyService> myServices) {
this.myServices = myServices;
}
@PostConstruct
public void startWork() {
System.out.println("secondManager start work");
myServices.forEach(MyService::doWork);
}
}
}
질문의 두 번째 부분에서는 먼저 이 유용한 답변을 살펴보십시오.
구현 이름을 지정하여 작업을 수행할 수도 있습니다.
예:
@Autowired
MyService firstService;
@Autowired
MyService secondService;
다음 명령어가 있다고 가정합니다.GreetingService
public interface GreetingService {
void doGreetings();
}
2개의 구현이 있습니다.HelloService
@Service
@Slf4j
public class HelloService implements GreetingService{
@Override
public void doGreetings() {
log.info("Hello world!");
}
}
그리고.HiService
@Slf4j
@Service
public class HiService implements GreetingService{
@Override
public void doGreetings() {
log.info("Hi world!");
}
}
또 다른 인터페이스가 있습니다.즉,BusinessService
용건을 묻다
public interface BusinessService {
void doGreetings();
}
그렇게 하는 방법에는 몇 가지 있다
#1. 사용@Autowired
@Component
public class BusinessServiceImpl implements BusinessService{
@Autowired
private GreetingService hiService; // Spring automatically maps the name for you, if you don't want to change it.
@Autowired
private GreetingService helloService;
@Override
public void doGreetings() {
hiService.doGreetings();
helloService.doGreetings();
}
}
구현 빈 이름을 변경해야 할 경우 예를 들어 이름을 빈으로 설정하여 다른 답변을 참조하십시오.@Service("myCustomName")
및 적용@Qualifier("myCustomName")
#2. 컨스트럭터 주입을 사용할 수도 있습니다.
@Component
public class BusinessServiceImpl implements BusinessService {
private final GreetingService hiService;
private final GreetingService helloService;
public BusinessServiceImpl(GreetingService hiService, GreetingService helloService) {
this.hiService = hiService;
this.helloService = helloService;
}
@Override
public void doGreetings() {
hiService.doGreetings();
helloService.doGreetings();
}
}
이 경우
public BusinessServiceImpl(@Qualifier("hiService") GreetingService hiService, @Qualifier("helloService") GreetingService helloService)
단, 스프링 부츠를 사용하고 있습니다.2.6.5
그리고.
public BusinessServiceImpl(GreetingService hiService, GreetingService helloService)
잘 되고 있어요.스프링 씨가 자동으로 이름을 불러주니까
#3. 또,Map
이 때문에
@Component
@RequiredArgsConstructor
public class BusinessServiceImpl implements BusinessService {
private final Map<String, GreetingService> servicesMap; // Spring automatically get the bean name as key
@Override
public void doGreetings() {
servicesMap.get("hiService").doGreetings();
servicesMap.get("helloService").doGreetings();
}
}
List
모든 서비스를 실행해도 정상적으로 동작합니다.다만, 특정의 실장을 필요로 하는 경우는, 실장의 이름을 정의할 필요가 있습니다.제 참고 자료는 여기 있습니다.
이번 건은 제가@RequiredArgsConstructor
롬복에서.
댓글에 기재되어 있듯이@Qualifier
주석: 문서에서 설명한 대로 다양한 구현을 구별할 수 있습니다.
테스트의 경우 를 사용하여 동일한 작업을 수행할 수도 있습니다.예를 들어 다음과 같습니다.
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyClassTests {
@Autowired
private MyClass testClass;
@MockBean
@Qualifier("default")
private MyImplementation defaultImpl;
@Test
public void givenMultipleImpl_whenAutowiring_thenReturnDefaultImpl() {
// your test here....
}
}
복수의 실장 인터페이스를 자동 접속하는 경우는, 다음의 2개의 어프로치가 있습니다.
즉, @Primary 주석으로 표시된 특정 구현을 사용하도록 인터페이스를 자동 연결하려고 할 때마다 Spring 애플리케이션에 알립니다.이것은 디폴트 자동 배선 설정과 같습니다.인터페이스의 실장 클러스터별로 1회만 사용할 수 있습니다.→ @Primary Docs
이번 봄의 주석을 통해 옵션 중 선택하는 인터페이스에 대한 참조를 정의하는 모든 장소에서 정확한 구현을 선택할 수 있습니다.→ @Qualifier 문서
상세한 것에 대하여는, 메뉴얼의 링크를 참조해 주세요.
public interface SomeInterfaces {
void send(String message);
String getType();
}
- 카프카 서비스
@Component
public class SomeInterfacesKafkaImpl implements SomeInterfaces {
private final String type = "kafka";
@Override
public void send(String message) {
System.out.println(message + "through Kafka");
}
@Override
public String getType() {
return this.type;
}
}
- 리디스 서비스
@Component
public class SomeInterfacesRedisImpl implements SomeInterfaces {
private final String type = "redis";
@Override
public void send(String message) {
System.out.println(message + "through Redis");
}
@Override
public String getType() {
return this.type;
}
}
- 마스터.
@Component
public class SomeInterfacesMaster {
private final Set<SomeInterfaces> someInterfaces;
public SomeInterfacesMaster(Set<SomeInterfaces> someInterfaces) {
this.someInterfaces = someInterfaces;
}
public void sendMaster(String type){
Optional<SomeInterfaces> service =
someInterfaces
.stream()
.filter(service ->
service.getType().equals(type)
)
.findFirst();
SomeInterfaces someService =
service
.orElseThrow(() -> new RuntimeException("There is not such way for sending messages."));
someService .send(" Hello. It is a letter to ....");
}
}
- 시험
@SpringBootTest
public class MultiImplementation {
}
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeInterfacesMasterTest extends MultiImplementation {
@Autowired
private SomeInterfacesMaster someInterfacesMaster;
@Test
void sendMaster() {
someInterfacesMaster.sendMaster("kafka");
}
}
따라서 Open/Closed 원칙에 따라 기존 코드를 깨지 않고 구현만 추가하면 됩니다.
@Component
public class SomeInterfacesRabbitImpl implements SomeInterfaces {
private final String type = "rabbit";
@Override
public void send(String message) {
System.out.println(message + "through Rabbit");
}
@Override
public String getType() {
return this.type;
}
}
- 테스트 v2
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeInterfacesMasterTestV2 extends MultiImplementation {
@Autowired
private SomeInterfacesMaster someInterfacesMaster;
@Test
void sendMasterV2() {
someInterfacesMaster.sendMaster("rabbit");
}
}
같은 인터페이스를 여러 개 실장하고 있는 경우, Spring은 클래스에 자동 접속할 필요가 있는 인터페이스를 알아야 합니다.종업원의 휴대 전화 번호 및 이메일 주소의 간단한 예를 다음에 나타냅니다.-
종업원 클래스:
public class Employee {
private String mobileNumber;
private String emailAddress;
...
/** Getters & Setters omitted **/
}
인터페이스 Employee Validator:
public interface EmployeeValidator {
public Employee validate(Employee employee);
}
모바일 번호 검증 도구의 첫 번째 구현 클래스:
@Component(value="EmployeeMobileValidator")
public class EmployeeMobileValidator implements EmployeeValidator {
@Override
public Employee validate(Employee employee) {
//Mobile number Validation logic goes here.
}
}
이메일 주소 검증기의 두 번째 구현 클래스:
@Component(value="EmployeeEmailValidator")
public class EmployeeEmailValidator implements EmployeeValidator {
@Override
public Employee validate(Employee employee) {
//Email address validation logic goes here.
}
}
이제 위의 검증자를 개별적으로 클래스에 자동 연결할 수 있습니다.
직원 서비스 인터페이스:
public interface EmployeeService {
public void handleEmployee(Employee employee);
}
직원 서비스 구현 클래스
@Service
public class EmployeeServiceImpl implements EmployeeService {
/** Autowire validators individually **/
@Autowired
@Qualifier("EmployeeMobileValidator") // Autowired using qualifier for mobile validator
private EmployeeValidator mobileValidator;
@Autowired
@Qualifier("EmployeeEmailValidator") // Autowired using qualifier for email valodator
private EmployeeValidator emailValidator;
@Override
public void handleEmployee(Employee employee) {
/**You can use just one instance if you need**/
employee = mobileValidator.validate(employee);
}
}
언급URL : https://stackoverflow.com/questions/51766013/spring-boot-autowiring-an-interface-with-multiple-implementations
'IT' 카테고리의 다른 글
동적으로 변경된 HTML을 뒤로 단추에 저장 (0) | 2023.04.03 |
---|---|
React 라우터 글로벌헤더 (0) | 2023.04.03 |
워드프레스 투고를 위해 이미지에 자동 클래스를 추가하는 방법 (0) | 2023.04.03 |
이 react-scripts eject 명령어는 무엇을 합니까? (0) | 2023.04.03 |
웹 팩에 정적 JSON 파일 로드 (0) | 2023.04.03 |