当前位置: 首页 > 面试题库 >

无论如何将内部类@ Inject / @ Autowire转换为外部类?

申屠洛华
2023-03-14
问题内容

在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

我刚刚尝试将静态公共嵌套类与测试类一起使用(上面),它似乎可以正确注入。另一方面,在我的实际控制器中,它发现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>

问题答案:

可以通过@Component注释声明和实例化内部类Bean ,但是解决方案很丑陋,但稍后会介绍。首先,这是使用<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。并且这里描述的概念也适用于反射。将Constructor用于初始化Inner类必须具有其第一个参数是封闭类的类型。这就是我们在这里通过声明一个constructor- arg

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

根据这两个事实,您可以编写这样的类

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

    }
}

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



 类似资料:
  • 我试过用@Component注释内部类,使其成为公共类,使其成为公共静态类,等等,但似乎我试过的每一种组合都以抛出这样或那样的错误结束。 作为一个私有的内部类,Spring抱怨它缺少一个构造函数,即使我定义了一个。 作为一个带注释的公共静态类,Spring抱怨它发现了两个bean-TestClass@TestClassInner和TestClass.TestClassInner。如果我使用,它会抱

  • 尝试将实体转换为dto时,使用modelmapper时出错。 我的java类是: 用户类: Rol等级: 用户到类: 当我尝试映射用户时。类到UserDTO。当modelmapper出现下一个错误时初始化: 此外,我尝试使用此modelmapper配置: 错误: 如果RolDTO类是外部化的,模型映射器工作正常。我希望你能帮助我解决这个问题。 谢谢。

  • 问题内容: 是否可以从Java内部类中获取对它的引用? 即 问题答案: 您可以像这样访问外部类的实例:

  • 为什么我不能这样做/是否有解决方法来实现这一点: 这两个编译错误是 > On

  • 问题内容: 尝试检查正在运行的Java的当前版本时,收到错误消息“ java不被识别为内部或外部命令,可操作程序或批处理文件”。 我正在运行Windows 7 OS,并且已经下载了最新的JDK,并觉得我可能像从前无法使用命令“ java -version”检查Java版本之前从机器上删除了Java。 我必须下载什么软件才能使Java在我的计算机上再次运行? 编辑: 确保所有环境变量都指向当前Jav

  • 问题内容: 因此,我最近安装了Python版本2.7.5,并对其进行了一些循环处理,但问题是,当我转到cmd并键入时出现错误: 无法将“ python”识别为内部或外部命令 我尝试设置路径,但无济于事。 这是我的路: C:\ Program Files \ Python27 如您所见,这是安装Python的地方。我不知道该怎么办 有人可以帮忙吗? 问题答案: 您需要将该文件夹添加到Windows路