YKH
YKH

Reputation: 127

How to change the dependency dynamically in runtime

I'm a spring developer.

During development, there was a need to change the dependency dynamically.

this is Module A is called if module B is faulted.

Since the A and B modules were similar APIs that call different APIs, I created an abstraction with Interface and injected it where it used its dependencies.

The interface and implementation are shown below.

public interface BookService {
    <T> Optional <ResponseEntity <T >> findBookListByQuery (BookSearchRequestUriVariables variables, Class <T> clazz);
}
@ Slf4j
@Service
@Primary
public class KakaoBookService implements BookService {
    @Override
    public <T> Optional <ResponseEntity <T >> findBookListByQuery (BookSearchRequestUriVariables variables, Class <T> clazz) {
        try {
            ResponseEntity <T> exchange = restTemplate.exchange (kakaoProperties.getBookSearchURL (),
                                                               HttpMethod.GET,
                                                               new HttpEntity (httpHeaders),
                                                               clazz,
                                                               variables.getUriVariables ());
            return Optional.ofNullable (exchange);
        } catch (Exception e) {
            log.info ("findBookListByQuery exception: {}", e.getMessage ());
            return Optional.empty ();
        }
    }
}
@Service
public class NaverBookService implements BookService {

@Override
    public <T> Optional <ResponseEntity <T >> findBookListByQuery (BookSearchRequestUriVariables variables, Class <T> clazz) {
        changeKakaoVariablesToNaverVariables (variables);
        return Optional.of (restTemplate.exchange (url, HttpMethod.GET, new HttpEntity (httpHeaders), clazz, variables.getUriVariables ()));
    }

    private BookSearchRequestUriVariables changeKakaoVariablesToNaverVariables (BookSearchRequestUriVariables variables) {
        Map <String, String> uriVariables = variables.getUriVariables ();

        uriVariables.put ("page", String.valueOf ((Integer.parseInt (variables.getUriVariables (). get ("page")) * 10) + 1));

        String sort = variables.getUriVariables (). Get ("sort");
        if (sort.equals ("accuracy")) sort = "sim";
        else if (sort.equals ("latest")) sort = "date";
        uriVariables.put ("sort", sort);

        return variables;
    }
}

The actual place to use is below. The first thing to do is to call the kakao API. If there is an error, call the Naver API.

public BookSearchKakaoResponse findBookListByQuery (BookSearchRequestUriVariables variables) {

        saveToBookHistory (getJwtMember (). getMemberName (), variables.getUriVariables (). get ("query"));
        Optional <ResponseEntity <BookSearchKakaoResponse >> bookListByKakao = kakaoBookService.findBookListByQuery (variables, BookSearchKakaoResponse.class);

        if (! bookListByKakao.isPresent ()) {// call NAVER API
            return naverBookService.findBookListByQuery (...);
        }
        return bookListByKakao.get (). getBody ();
    }

I have kakaoBookService, I want to combine and naverBookService with bookService.

If the module calling the kakao API fails, I want to inject a module calling the naver API into the bookService.

Please tell me what to do.

I thought it would be a good idea to combine them according to the Dependency Inversion Principle and Open Closed Principle.

Please let me know if the direction I'm thinking about is a code design issue.

Thank you.

Upvotes: 0

Views: 722

Answers (1)

R.G
R.G

Reputation: 7131

You may use @Qualifier annotation to achieve the same. When the bean is provided to you , the container would have autowired all the dependencies. You may use the correct service based on the usecase

@Slf4j
@Service
@Primary
@Qualifier("kakao")
public class KakaoBookService implements BookService {}


@Service
@Qualifier("naver")
public class NaverBookService implements BookService {}

Now autowire both beans to the service that uses it .

@Autowired @Qualifier("kakao")
    BookService kakaoBookService;

@Autowired @Qualifier("naver")
    BookService naverBookService;

Though it is possible to dynamically obtain the bookService bean from the application context on condition , autowiring the dependencies is a cleaner approach.

Upvotes: 1

Related Questions