복붙노트

[SPRING] 어쨌든 생성자 인수가 필요한 빈을 @Autowire로 보내려면?

SPRING

어쨌든 생성자 인수가 필요한 빈을 @Autowire로 보내려면?

저는 Spring 3.0.5를 사용하고 있으며 가능한 한 @Autowire 주석을 클래스 멤버에게 사용하고 있습니다. autowire에 필요한 콩 중 하나는 생성자에 대한 인수가 필요합니다. Spring 문서를 살펴 봤지만 생성자 인수에 주석을 추가하는 방법에 대한 참조를 찾을 수없는 것 같습니다.

XML에서는 bean 정의의 일부로 사용할 수 있습니다. @Autowire 주석에 대한 비슷한 메커니즘이 있습니까?

전의:

@Component
public class MyConstructorClass{

  String var;
  public MyConstructorClass( String constrArg ){
    this.var = var;
  }
...
}


@Service
public class MyBeanService{
  @Autowired
  MyConstructorClass myConstructorClass;

  ....
}

이 예제에서는 @Autowire 주석을 사용하여 MyBeanService에서 "constrArg"값을 어떻게 지정합니까? 이 일을 할 수있는 방법이 있습니까?

감사,

에릭

해결법

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

    1.@Value 주석이 필요합니다.

    @Value 주석이 필요합니다.

    public class SimpleMovieLister {
    
      private MovieFinder movieFinder;
      private String defaultLocale;
    
      @Autowired
      public void configure(MovieFinder movieFinder, 
                            @Value("#{ systemProperties['user.region'] }"} String defaultLocale) {
          this.movieFinder = movieFinder;
          this.defaultLocale = defaultLocale;
      }
    
      // ...
    }
    

    참조 : 표현식 언어> 주석 구성

    더 명확히하기 위해, 시나리오에서 MybeanService와 MyConstructorClass라는 두 클래스를 다음과 같이 연결합니다.

    @Component
    public class MyBeanService implements BeanService{
        @Autowired
        public MybeanService(MyConstructorClass foo){
            // do something with foo
        }
    }
    
    @Component
    public class MyConstructorClass{
        public MyConstructorClass(@Value("#{some expression here}") String value){
             // do something with value
        }
    }
    

    업데이트 : MyConstructorClass의 여러 인스턴스가 서로 다른 값을 필요로하는 경우 Qualifier 주석을 사용해야합니다

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

    2.아니, 네가 의미하는 방식이 아니야. MyConstructorClass를 나타내는 bean은 클라이언트 Bean을 필요로하지 않고 구성 가능해야하므로 MyBeanService는 MyConstructorClass가 구성되는 f}에 대해 say를 얻지 못합니다.

    아니, 네가 의미하는 방식이 아니야. MyConstructorClass를 나타내는 bean은 클라이언트 Bean을 필요로하지 않고 구성 가능해야하므로 MyBeanService는 MyConstructorClass가 구성되는 f}에 대해 say를 얻지 못합니다.

    이것은 autowiring 문제가 아닙니다. 여기에서 문제는 MyConstructorClass가 @Component라는 점을 감안할 때 Spring이 MyConstructorClass를 인스턴스화하는 방법입니다. 구성 요소 검사를 사용하고 있으므로 MyConstructorClass를 명시 적으로 지정하지 않아도됩니다.

    @Sean이 말했듯이 여기서 한 가지 대답은 constructor 매개 변수에 @Value를 사용하여 Spring이 시스템 등록 정보 또는 등록 정보 파일에서 생성자 값을 가져 오는 것입니다. 대안은 MyBeanService가 MyConstructorClass를 직접 인스턴스화하는 것이지만, 그렇게하면 MyConstructorClass는 더 이상 Spring bean이 아닙니다.

  3. ==============================

    3.글쎄, 나는 때때로 같은 질문을한다. 필자가 아는 한, 생성자에 동적 매개 변수를 추가하려면이 작업을 수행 할 수 없습니다. 그러나 공장 패턴이 도움이 될 수 있습니다.

    글쎄, 나는 때때로 같은 질문을한다. 필자가 아는 한, 생성자에 동적 매개 변수를 추가하려면이 작업을 수행 할 수 없습니다. 그러나 공장 패턴이 도움이 될 수 있습니다.

    public interface MyBean {
        // here be my fancy stuff
    }
    
    public interface MyBeanFactory {
        public MyBean getMyBean(/* bean parameters */);
    }
    
    @Component
    public class MyBeanFactoryImpl implements MyBeanFactory {
        @Autowired
        WhateverIWantToInject somethingInjected;
    
        public MyBean getMyBean(/* params */) {
            return new MyBeanImpl(/* params */);
        }
    
        private class MyBeanImpl implements MyBean {
            public MyBeanImpl(/* params */) {
                // let's do whatever one has to
            }
        }
    }
    
    @Component
    public class MyConsumerClass {
        @Autowired
        private MyBeanFactory beanFactory;
    
        public void myMethod() {
            // here one has to prepare the parameters
            MyBean bean = beanFactory.getMyBean(/* params */);
        }
    }
    

    자, MyBean은 그 자체로 봄베이가 아니지만 충분히 가깝습니다. Dependency Injection은 bean 자체가 아닌 factory를 injection하기도하지만, 새로운 MyBean 구현물 위에 새로운 factory를 삽입해야한다.

    또한, MyBean은 다른 빈들에 접근 할 수 있습니다 - 공장의 자동 채워진 것들에 접근 할 수 있기 때문입니다.

    그리고 분명히 getMyBean 함수에 일부 논리를 추가하려고 할 수도 있습니다. 이는 허용되는 추가 노력이지만, 불행히도 더 좋은 해결책은 없습니다. 문제는 대개 동적 매개 변수가 데이터베이스 나 사용자 상호 작용과 같은 외부 소스에서 온다는 것이므로 정보를 즉시 사용할 수있는 경우에만 중간 실행시에만 해당 Bean을 인스턴스화해야하므로 팩토리가 적절해야합니다 .

  4. ==============================

    4.다음과 같이 구성 요소를 구성 할 수도 있습니다.

    다음과 같이 구성 요소를 구성 할 수도 있습니다.

    package mypackage;
    import org.springframework.context.annotation.Configuration;
       @Configuration
       public class MyConstructorClassConfig {
    
    
       @Bean
       public MyConstructorClass myConstructorClass(){
          return new myConstructorClass("foobar");
       }
      }
    }
    

    Bean 어노테이션을 사용하면 반환 된 빈을 BeanFactory에 등록하도록 Spring에 지시한다.

    그래서 당신은 당신이 원하는대로 그것을 autowire 수 있습니다.

  5. ==============================

    5.@Autowired 및 @Value를 사용해야합니다. 이 주제에 대한 자세한 내용은이 게시물을 참조하십시오.

    @Autowired 및 @Value를 사용해야합니다. 이 주제에 대한 자세한 내용은이 게시물을 참조하십시오.

  6. ==============================

    6.대안으로는 getter와 setter로 가질 수있는 생성자에 매개 변수를 전달하는 대신 @PostConstruct에서 원하는대로 값을 초기화하는 것입니다. 이 경우 Spring은 기본 생성자를 사용하여 빈을 생성 할 것이다. 아래 예가 있습니다.

    대안으로는 getter와 setter로 가질 수있는 생성자에 매개 변수를 전달하는 대신 @PostConstruct에서 원하는대로 값을 초기화하는 것입니다. 이 경우 Spring은 기본 생성자를 사용하여 빈을 생성 할 것이다. 아래 예가 있습니다.

    @Component
    public class MyConstructorClass{
    
      String var;
    
      public void setVar(String var){
         this.var = var;
      }
    
      public void getVar(){
        return var;
      }
    
      @PostConstruct
      public void init(){
         setVar("var");
      }
    ...
    }
    
    
    @Service
    public class MyBeanService{
      //field autowiring
      @Autowired
      MyConstructorClass myConstructorClass;
    
      ....
    }
    
  7. ==============================

    7.대부분의 해답은 상당히 오래된 것이므로 그 당시에는 불가능했을 수도 있지만 가능한 모든 유스 케이스를 만족시키는 해법이 실제로 존재합니다.

    대부분의 해답은 상당히 오래된 것이므로 그 당시에는 불가능했을 수도 있지만 가능한 모든 유스 케이스를 만족시키는 해법이 실제로 존재합니다.

    그래서 답은 다음과 같습니다.

    이러한 문제를 해결하는 솔루션은 ApplicationContext를 사용하여 수동으로 객체를 생성하는 것입니다.

    @Component
    public class MyConstructorClass
    {
        String var;
    
        public MyConstructorClass() {}
        public MyConstructorClass(String constrArg) {
            this.var = var;
        }
    }
    
    @Service
    public class MyBeanService implements ApplicationContextAware
    {
        private static ApplicationContext applicationContext;
    
        MyConstructorClass myConstructorClass;
    
        public MyBeanService()
        {
            // Creating the object manually
            MyConstructorClass myObject = new MyConstructorClass("hello world");
            // Initializing the object as a Spring component
            AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
            factory.autowireBean(myObject);
            factory.initializeBean(myObject, myObject.getClass().getSimpleName());
        }
    
        @Override
        public void setApplicationContext(ApplicationContext context) throws BeansException {
            applicationContext = context;
        }
    }
    

    이는 다음과 같은 이유로 멋진 솔루션입니다.

    명심해야 할 점은 인스턴스화하려는 클래스에서 인수를 취하지 않는 (그리고 비어있을 수있는) 생성자가 있어야한다는 것입니다 (또는 필요한 경우 @Autowired 생성자).

  8. ==============================

    8.또 다른 대안으로, 이미 객체의 인스턴스가 생성되어 있고 그것을 @autowired 의존 관계로 추가하여 내부의 모든 @autowired 변수를 초기화하려는 경우 다음과 같이 할 수 있습니다.

    또 다른 대안으로, 이미 객체의 인스턴스가 생성되어 있고 그것을 @autowired 의존 관계로 추가하여 내부의 모든 @autowired 변수를 초기화하려는 경우 다음과 같이 할 수 있습니다.

    @Autowired 
    private AutowireCapableBeanFactory autowireCapableBeanFactory;
    
    public void doStuff() {
       YourObject obj = new YourObject("Value X", "etc");
       autowireCapableBeanFactory.autowireBean(obj);
    }
    
  9. from https://stackoverflow.com/questions/6739566/anyway-to-autowire-a-bean-that-requires-constructor-arguments by cc-by-sa and MIT license