无论如何@ Inject/@将内部类自动装入一个外部类?

Eri*_* B. 4 java spring dependency-injection

在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();
       ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用@Component注释内部类,使其成为公共类,使其成为公共静态等,但似乎我尝试过的每个组合总是会抛出一个或另一个错误.

作为一个私有内部类,Spring抱怨它缺少一个构造函数,即使我定义了一个.

作为一个带注释的@Component公共静态类,Spring抱怨它找到了两个bean - TestClass @ TestClassInner和testClass.TestClassInner.如果我使用a @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();
    }
}
Run Code Online (Sandbox Code Playgroud)

引发错误(公共和私有内部类都抛出相同的错误):

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
Run Code Online (Sandbox Code Playgroud)

我只是尝试使用我的测试类(上面)的静态公共嵌套类,它似乎正确注入.另一方面,在我的实际控制器中,它发现了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)
Run Code Online (Sandbox Code Playgroud)

编辑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;

}
Run Code Online (Sandbox Code Playgroud)

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/>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

Sot*_*lis 13

可以通过@Component注释声明和实例化内部类bean ,但解决方案很难看,但我稍后会介绍它.首先,这里是如何使用<bean>XML声明来完成的.特定

package com.example;

public class Example {
    @Autowired
    private Inner inner;
    public class Inner {        
    }
}
Run Code Online (Sandbox Code Playgroud)

你有

<bean name="ex" class="com.example.Example" />
<bean name="inner" class="com.example.Example$Inner">
    <constructor-arg ref="ex"></constructor-arg>
</bean>
Run Code Online (Sandbox Code Playgroud)

对于内部类,任何构造函数都隐式声明其第一个参数作为封闭类型的实例.

所以

public Inner() {}
Run Code Online (Sandbox Code Playgroud)

以上将实际编译为

public Inner (Example enclosingInstance) {}
Run Code Online (Sandbox Code Playgroud)

使用Java代码时,语法会隐式提供该参数的参数

enclosingInstance.new Inner();
Run Code Online (Sandbox Code Playgroud)

Spring使用反射来实例化bean类并初始化bean.这里描述的概念也适用于反思.将Constructor用于初始化Inner类已具有其第一个参数是封闭类的类型.这就是我们在这里通过声明一个明确的做法constructor-arg.

使用的解决方案@Component取决于一些事情.首先,你必须知道上面讨论的所有事情.基本上,对于一个Constructor对象,当你调用时newInstance(),你需要传递一个封闭类的实例作为第一个参数.其次,您必须知道Spring如何处理注释.当带注释的类有一个带注释@Autowired的构造函数时,它就是构造函数,它将选择初始化bean.它还使用ApplicationContext解析bean作为参数注入构造函数.

利用这两个事实,你可以写一个这样的课程

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

    }
}
Run Code Online (Sandbox Code Playgroud)

这里,我们的内部类有一个@Autowired构造函数,因此Spring确切地知道Constructor要使用哪个对象.因为@Autowired它也会尝试从ApplicationContext匹配中找到一个bean,并为构造函数的每个参数注入.在这种情况下,唯一的参数是类型Example,封闭类.既然Example也是注释的@Component,它也是上下文中的bean,所以Spring可以将它注入到内部类的构造函数中.