无论如何将内部类@ Inject / @ Autowire转换为外部类?
在Spring / JSR-330中,是否有一种方法可以正确地声明需要依赖项注入的内部类,以便可以将其注入外部类?
例如:
@Componentpublic 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)
@Controllerpublic 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
解析豆子作为构造函数的参数注入。
根据这两个事实,您可以编写这样的类
@Componentpublic class Example {
@Component
public class Inner {
@Autowired
public Inner() {}
}
}
在这里,我们的内部类具有@Autowired
构造函数,因此Spring确切知道Constructor
要使用哪个对象。因此,@Autowired
它还会尝试从中找到一个bean
ApplicationContext
来匹配并为构造函数具有的每个参数注入。在这种情况下,唯一的参数是type
Example
,即封闭类。由于Example
也用注释@Component
,它也是上下文中的bean,因此Spring可以将其注入内部类的构造函数中。
以上是 无论如何将内部类@ Inject / @ Autowire转换为外部类? 的全部内容, 来源链接: utcz.com/qa/399518.html