java - mvc - spring setter injection annotation example



無論如何,@注入/ @ Autowire內部類到外部類? (1)

在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註釋內部類,使其成為一個公共類,使其成為公共靜態等,但似乎我嘗試過的每個組合總是拋出一個錯誤或另一個錯誤。

作為一個私有的內部類,Spring抱怨說它缺少一個構造函數,即使我定義了一個構造函數。

作為一個帶註釋的@Component公共靜態類,Spring抱怨說它找到了兩個bean - 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();
    }
}

拋出錯誤(公共和私人內部類都拋出相同的錯誤):

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

我只是嘗試使用我的測試類(上面)靜態公共嵌套類,它似乎正確注入。 另一方面,在我的實際控制器中,它發現了兩個匹配的類:

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>

可以通過@Component註釋來聲明和實例化內部類的bean,但是解決方案很難看,但是我稍後會介紹。 首先,您可以通過XML中的<bean>聲明來實現這一點。 特定

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函數必須使其第一個參數為封閉類的類型。 這就是我們通過聲明一個constructor-arg在這裡明確的。

使用@Component的解決方案取決於幾件事情。 首先,你必須知道上面所討論的所有事情。 基本上,通過一個Constructor對象,當你調用newInstance() ,你需要傳遞一個封閉類的實例作為第一個參數。 其次,你必須知道Spring如何處理註釋。 當註釋類有一個用@Autowired註解的構造函數時,它將會選擇初始化這個bean。 它還使用ApplicationContext來解析bean,將其作為參數注入到構造函數中。

玩這兩個事實,你可以寫一個這樣的課

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

    }
}

在這裡,我們的內部類有一個@Autowired構造函數,所以Spring知道使用哪個Constructor對象。 由於@Autowired它也將嘗試從ApplicationContext找到一個bean,以匹配和注入構造函數所具有的每個參數。 在這種情況下,唯一的參數是類型Example ,封閉類。 由於Example也用@Component註解,所以它也是上下文中的一個bean,所以Spring可以將它注入到內部類的構造函數中。





dependency-injection