복붙노트

[SPRING] Spring 내에서 autowire 할 bean을 동적으로 정의 (한정자 사용)

SPRING

Spring 내에서 autowire 할 bean을 동적으로 정의 (한정자 사용)

XML 구성에 대한 주석을 선호하는 Java EE + Spring 응용 프로그램이 있습니다. 빈에는 항상 프로토 타입 범위가 있습니다.

이제 사용자 요청이 이루어진 국가에 따라 비즈니스 규칙이 적용됩니다. 그래서 나는 이와 같은 것을 갖게 될 것입니다 (이 예제는 크게 단순화되었습니다).

@Component
public class TransactionService {
    @Autowired
    private TransactionRules rules;
    //..
}


@Component
@Qualifier("US")
public class TransactionRulesForUS implements TransactionRules {
     //..
}

@Component
@Qualifier("CANADA")
public class TransactionRulesForCanada implements TransactionRules {
     //..
}

나는 자동 배선 메커니즘이 현재 요청한 국가를 기반으로 올바른 빈 (이 예에서는 미국 또는 캐나다)을 자동으로 주입하도록하는 방법을 찾고있었습니다. 국가는 ThreadLocal 변수에 저장되며 각 요청마다 변경됩니다. 또한 자신의 특별한 규칙이없는 모든 국가에 대해 글로벌 클래스가있을 것입니다.

Spring이 삽입 할 객체를 만드는 방법을 결정하는 방식을 사용자 정의해야한다고 생각합니다. 필자가 찾은 유일한 방법은 FactoryBean을 사용하는 것이었지만, 내가 기대했던 것만은 아니었다. 나는 이런 일을하기를 바랐다.

나는 올바른 길을 가고 있는가? 이것에 대한 아이디어가 있습니까?

감사.

해결법

  1. ==============================

    1.인스턴스 변수 또는 설정 메소드를 장식하는 데 사용되는 자신 만의 주석을 작성한 다음 주석을 처리하고 런타임시 올바른 구현을 해결하고 호출을 위임하는 일반 프록시를 삽입하는 사후 프로세서를 작성하십시오.

    인스턴스 변수 또는 설정 메소드를 장식하는 데 사용되는 자신 만의 주석을 작성한 다음 주석을 처리하고 런타임시 올바른 구현을 해결하고 호출을 위임하는 일반 프록시를 삽입하는 사후 프로세서를 작성하십시오.

    @Component
    public class TransactionService {
      @LocalizedResource
      private TransactionRules rules;
      //..
    }
    
    @Retention(RUNTIME)
    @Target({FIELD, METHOD})
    public @interface LocalizedResource {}
    

    다음은 빈 포스트 프로세서의 postProcessBeforeInitialization (bean, beanName) 메소드에 대한 알고리즘입니다.

    다음은 지역화 된 리소스를 만드는 데 사용되는 프록시 용 InvocationHandler입니다.

    public class LocalizedResourceResolver implements InvocationHandler {
      private final BeanFactory bf;
      public LocalizedResourceResolver(BeanFactory bf) {
        this.bf = bf;
      }
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String locale = lookupCurrentLocale();
        Object target = lookupTarget(locale);
        return method.invoke(target, args);
      }
    
      private String lookupCurrentLocale() {
        // here comes your stuff to look up the current locale
        // probably set in a thread-local variable
      }
    
      private Object lookupTarget(String locale) {
        // use the locale to match a qualifier attached to a bean that you lookup using the BeanFactory.
        // That bean is the target
      }
    }
    

    빈 유형에 대해 몇 가지 제어를 수행하거나 InvocationHandler에 요청 된 빈 유형을 추가해야 할 수도 있습니다.

    다음은 주어진 인터페이스의 구현을 지역에 따라 자동으로 감지하여 로케일에 해당하는 한정자로 등록하는 것입니다. 로케일 인식 인터페이스의 각 구현에 대해 하나씩 올바른 한정자와 함께 새 BeanDefinition을 레지스트리에 추가하기 위해 BeanDefinitionRegistryPostProcessor 또는 BeanFactoryPostProcessor를 구현할 수 있습니다. 로케일 인식 인터페이스의 이름이 TransactionRules 인 경우 동일한 패키지에서 구현의 이름을 TransactionRules_ISOCODE로 지정할 수 있습니다.

    그러한 명명 규칙을 가질 여력이 없다면 클래스 경로 검색과 주어진 구현의 로케일을 추측 할 수있는 방법이 필요합니다 (구현 클래스의 어노테이션 일 수도 있습니다). 클래스 패스 스캐닝은 가능하지만 꽤 복잡하고 느리기 때문에 피하십시오.

    다음은 어떤 일이 발생했는지 요약 한 것입니다.

    별로 사소하지는 않지만 작동합니다. 이것은 실제로 @PersistenceContext가 스프링에 의해 처리되는 방법입니다 (구현 룩업을 제외하고는 유스 케이스의 추가 기능 임).

  2. ==============================

    2.ThreadLocal 값을 기반으로 올바른 bean을 반환하는 Configuration 클래스를 제공 할 수 있습니다. 이것은 Spring 3를 사용한다고 가정합니다. 약간의 테스트를 해 각 요청에 대해 provider 메소드가 호출되었는지 확인했습니다. 여기 내가 한 일이있다.

    ThreadLocal 값을 기반으로 올바른 bean을 반환하는 Configuration 클래스를 제공 할 수 있습니다. 이것은 Spring 3를 사용한다고 가정합니다. 약간의 테스트를 해 각 요청에 대해 provider 메소드가 호출되었는지 확인했습니다. 여기 내가 한 일이있다.

    @Configuration
    public class ApplicationConfiguration
    {
        private static int counter = 0;
    
        @Bean( name="joel" )
        @Scope( value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
        List<String> getJoel()
        {
            return Arrays.asList( new String[] { "Joel " + counter++ } );
        }
    }
    

    그리고 내 컨트롤러의 값을 다음과 같이 참조하십시오.

    @Resource( name="joel" )
    private List<String> joel;
    

    프로 바이더의 구현에서는, 로케일의 ThreadLocal를 체크해, 올바른 TransactionRules 객체 등을 돌려 줄 수가 있습니다. ScopedProxy 항목은 컨트롤러에 삽입 되었기 때문에 Singleton Scoped이며 값은 요청 Scoped입니다.

  3. from https://stackoverflow.com/questions/7720454/dynamically-defining-which-bean-to-autowire-in-spring-using-qualifiers by cc-by-sa and MIT license