복붙노트

[SPRING] 어쨌든 @ Inject / @ Autowire로 내부 클래스를 외부 클래스에 넣으시겠습니까?

SPRING

어쨌든 @ Inject / @ Autowire로 내부 클래스를 외부 클래스에 넣으시겠습니까?

Spring / JSR-330에는 종속 클래스 삽입이 필요한 내부 클래스를 올바르게 선언 할 수있는 방법이 있습니까? 예를 들어 외부 클래스에 삽입 할 수 있습니까?

예 :

@Component
public class TestClass{

    // How to declare this class?
    private class TestClassInner{
       @Autowired private SomeBean somebean;

       public boolean doSomeWork(){
          return somebean.doSomething();
       }               
    }

    // Inject the inner class here in the outer class such that the outer class can use an instance of it
    @Autowired TestClassInner innerClass;

    @PostConstruct
    public void init(){
        ...
    }

    public void someMethod(){
       innerClass.doSomeWork();
       ...
    }
}

나는 내부 클래스에 @Component 주석을 달고 public 클래스로 만들고 public static으로 만들려고 시도했지만, 시도한 모든 조합은 항상 하나의 에러 또는 다른 것을 던지는 것으로 끝난다.

개인적인 내부 클래스 인 Spring은 생성자를 정의하더라도 생성자가 누락되었다고 불평합니다.

주석이있는 @Component public static 클래스 인 Spring은 TestClass @ TestClassInner와 testClass.TestClassInner라는 두 개의 빈을 찾는다 고 불평합니다. @Qualifier를 사용하면 bean을 찾을 수 없다는 불만이 생깁니다.

나는 이들 내부 bean이 Spring을 어떻게 작동하는지 / 상호 작용 하는지를 오해하고 있다고 생각한다.

이것은 가능한가?

편집하다

그래서 내가 시도한 몇 가지 조합 (@SotiriosDelimanolis 응답을 기반으로 새 생성자를 구현하는 시도 포함) :

    // How to declare this class?
@Component
public class TestClassInner{
    @Autowired private ProviderService providerService;

    public TestClassInner(){
        super();
    }
    public TestClassInner( TestClass t){
        super();
    }
}

오류를 throw합니다 (public 및 private 내부 클래스 모두 동일한 오류가 발생 함).

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.ia.exception.TestClass$TestClassInner]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.ia.exception.TestClass$TestClassInner.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1030)
    ... 54 more

난 그냥 내 테스트 클래스 (위)와 정적 대중 중첩 클래스를 사용하여 시도하고 제대로 주입 것 같습니다. 반면에 실제 컨트롤러에서는 2 개의 일치하는 클래스를 찾습니다.

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ia.web.ContractController$InnerClass] is defined: expected single matching bean but found 2: com.ia.web.ContractController$InnerClass,contractController.InnerClass
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865)

편집 2

@Controller
public class ContractController {

    @Component
    static public class InnerClass extends AttachmentControllerSupport{

        /**
         * 
         */
        public InnerClass() {
            super();
            // TODO Auto-generated constructor stub
        }

        public InnerClass( ContractController c){
            super();
        }
    }

    @Autowired private InnerClass innerclass;

    @Autowired private AttachmentControllerSupport attachmentControllerSupport;
    @Autowired private ContractService contractService;

}

applicationContext.xml :

<context:component-scan base-package="com.ia">
    <context:exclude-filter expression=".*_Roo_.*" type="regex"/>
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<context:spring-configured/>

restmvc-config.xml :

<mvc:annotation-driven conversion-service="applicationConversionService" >
  <mvc:argument-resolvers>
    <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" />
  </mvc:argument-resolvers>
</mvc:annotation-driven>

해결법

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

    1.@Component 주석을 통해 내부 클래스 bean을 선언하고 인스턴스화하는 것은 가능하지만 솔루션은 추악하다.하지만 나중에 설명하겠다. 먼저 XML에서 선언을 사용하여이를 수행 할 수 있습니다. 주어진

    @Component 주석을 통해 내부 클래스 bean을 선언하고 인스턴스화하는 것은 가능하지만 솔루션은 추악하다.하지만 나중에 설명하겠다. 먼저 XML에서 선언을 사용하여이를 수행 할 수 있습니다. 주어진

    package com.example;
    
    public class Example {
        @Autowired
        private Inner inner;
        public class Inner {        
        }
    }
    

    너는 가질거야.

    <bean name="ex" class="com.example.Example" />
    <bean name="inner" class="com.example.Example$Inner">
        <constructor-arg ref="ex"></constructor-arg>
    </bean>
    

    내부 클래스의 경우 모든 생성자가 암시 적으로 첫 번째 매개 변수를 둘러싸는 유형의 인스턴스로 선언합니다.

    그래서

    public Inner() {}
    

    위의 내용은 실제로 컴파일 될 것입니다.

    public Inner (Example enclosingInstance) {}
    

    Java 코드를 사용하면 해당 매개 변수에 대한 인수에 내재적으로 구문이 제공됩니다

    enclosingInstance.new Inner();
    

    Spring은 리플렉션을 사용하여 Bean 클래스를 인스턴스화하고 Bean을 초기화한다. 여기에 설명 된 개념은 리플렉션에도 적용됩니다. Inner 클래스를 초기화하는 데 사용되는 생성자는 첫 번째 매개 변수를 둘러싸는 클래스 유형으로 지정해야합니다. 이것이 constructor-arg를 선언함으로써 명시 적으로 여기에서 수행하는 작업입니다.

    @Component를 사용하는 솔루션은 몇 가지 사항에 달려 있습니다. 첫째, 위에서 언급 한 모든 것을 알아야합니다. 기본적으로 Constructor 객체를 사용하여 newInstance ()를 호출하면 둘러싸는 클래스의 인스턴스를 첫 번째 인수로 전달해야합니다. 둘째, Spring이 어노테이션을 어떻게 처리 하는지를 알아야한다. 주석이 달린 클래스에 @Autowired로 주석 처리 된 단일 생성자가있는 경우 생성자가 Bean을 초기화하도록 선택합니다. 또한 ApplicationContext를 사용하여 Bean을 생성자에 인수로 삽입합니다.

    이 두 가지 사실을 실행하면 다음과 같은 클래스를 작성할 수 있습니다.

    @Component
    public class Example {
        @Component
        public class Inner {
            @Autowired
            public Inner() {}
    
        }
    }
    

    여기, 우리 내부 클래스에는 @Autowired 생성자가 있으므로 Spring은 사용할 생성자 객체를 정확히 알고 있습니다. @Autowired 때문에, ApplicationContext로부터 bean을 찾아서 생성자가 가진 모든 매개 변수에 일치시키고 삽입하려고 시도 할 것이다. 이 경우 유일한 매개 변수는 둘러싼 클래스 인 Example입니다. Example 또한 @Component로 주석 처리되었으므로 컨텍스트의 Bean이기도하므로 Spring은 내부 클래스의 생성자에이를 삽입 할 수 있습니다.

  2. from https://stackoverflow.com/questions/24213823/anyway-to-inject-autowire-an-inner-class-into-an-outer-class by cc-by-sa and MIT license