在 Spring/JSR-330 中,有没有办法正确声明一个需要依赖注入(inject)的内部类,以便我可以将它注入(inject)到外部类中?
例如:
@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)静态等,但似乎我尝试过的每一种组合最终都会抛出一个或另一个错误。
作为私有(private)内部类,Spring 提示它缺少构造函数,即使我定义了一个。
作为带注释的 @Component
公共(public)静态类,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();
}
}
抛出错误(公共(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
我刚刚尝试在我的测试类(上图)中使用静态公共(public)嵌套类,它似乎注入(inject)正确。另一方面,在我的实际 Controller 中,它发现了 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;
}
应用程序上下文.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 类并初始化您的 beans。此处描述的概念也适用于反射。 Constructor
用于初始化 Inner
类的第一个参数必须是封闭类的类型。这就是我们在这里通过声明一个 constructor-arg
来明确地做的事情。 .
使用@Component
的解决方案取决于几件事。首先,您必须了解上面讨论的所有内容。基本上,用 Constructor
对象,当你调用newInstance()
,您需要将封闭类的实例作为第一个参数传递。其次,你必须知道 Spring 是如何处理注解的。当带注释的类有一个用 @Autowired
注释的构造函数时,这是它将选择初始化 bean 的构造函数。它还使用 ApplicationContext
解析要作为参数注入(inject)构造函数的 bean。
根据这两个事实,您可以编写这样的类
@Component
public class Example {
@Component
public class Inner {
@Autowired
public Inner() {}
}
}
在这里,我们的内部类有一个 @Autowired
构造函数,因此 Spring 确切地知道哪个 Constructor
要使用的对象。因为 @Autowired
它还将尝试从 ApplicationContext
中找到一个 bean。为构造函数具有的每个参数匹配和注入(inject)。在这种情况下,唯一的参数是 Example
类型, 封闭类。自 Example
也用 @Component
注释,它也是上下文中的一个bean,所以Spring可以将它注入(inject)到内部类的构造函数中。
关于java - 无论如何@Inject/@Autowire 一个内部类到一个外部类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24213823/