无论如何@ Inject / @将内部类自动装入一个外部类? [英] Anyway to @Inject/@Autowire an inner class into an outer class?

查看:454
本文介绍了无论如何@ Inject / @将内部类自动装入一个外部类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Spring / JSR-330中,有没有办法正确声明需要依赖注入的内部类,这样我可以将它注入外部类?

In Spring/JSR-330, is there a way to properly declare an inner class which requires dependency injection, such that I can inject it into the outer class?

例如:

@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注释内部类,使其成为公共类,使其成为公共静态等,但似乎我尝试的每个组合总是会抛出一个或另一个错误。

I've tried annotating the inner class with @Component, making it a public class, making it public static, etc, but it seems that every combination I've tried always ends up throwing one error or another.

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

As a private inner class, Spring complains that it is missing a constructor, even if I define one.

作为带注释的 @Component 公共静态类,Spring抱怨它找到两个bean - TestClass @ TestClassInner和testClass.TestClassInner。如果我使用 @Qualifier ,它会抱怨找不到bean。

As an annotated @Component public static class, Spring complains that it find two beans - TestClass@TestClassInner and testClass.TestClassInner. And if I use a @Qualifier, it then complains that the bean cannot be found.

我认为我是误解了这些内部bean如何工作/与Spring交互以正确理解是否/如何声明它们。

I presume I am misunderstanding how these inner beans work/interact with Spring to properly understand if/how to declare them.

这是否可能?

编辑

所以这里有一些我尝试过的组合(包括尝试实现基于@SotiriosDelimanolis响应的新构造函数):

So here are a few combinations I've tried (including tried implementing a new constructor based on @SotiriosDelimanolis response):

    // How to declare this class?
@Component
public class TestClassInner{
    @Autowired private ProviderService providerService;

    public TestClassInner(){
        super();
    }
    public TestClassInner( TestClass t){
        super();
    }
}

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

Throws error (both public and private inner class throw the same error):

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个匹配的类:

I just tried using a static public nested class with my test class (above) and it seems to inject properly. On the other hand, in my actual controller, it discovers 2 matching classes:

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:

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:




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>


推荐答案

可以通过声明和实例化内部类bean @Component 注释,但解决方案很难看,但我稍后会介绍。首先,您可以使用XML中的< bean> 声明来完成此操作。给定

It is possible to declare and instantiate inner class beans through @Component annotations, but solution is ugly, but I will get to it later. First, here's how you can do it with <bean> declarations in XML. Given

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>

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

For inner classes, any constructor implicitly declares its first parameter as an instance of the enclosing type.

所以

public Inner() {}

上面的

实际上会被编译为

above would actually be compiled to

public Inner (Example enclosingInstance) {}

使用Java代码,该参数的参数为隐含地提供语法

With Java code, the argument for that parameter is implicitly provided with the syntax

enclosingInstance.new Inner();

Spring使用反射来实例化bean类并初始化bean。这里描述的概念也适用于反思。用于初始化 Inner 类的构造函数必须使其第一个参数属于封闭类的类型。这就是我们通过声明一个 constructor-arg 来明确地做的事情。

Spring uses reflection to instantiate your bean classes and initialize your beans. And the concept described here also applies to reflection. The Constructor used to initialize the Inner class has to have its first parameter be of the type of the enclosing class. That's what we are doing explicitly here by declaring a constructor-arg.

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

The solution for using @Component depends on a few things. First, you have to know all the things discussed above. Basically, with a Constructor object, when you call newInstance(), you need to pass an instance of the enclosing class as the first argument. Second, you have to know how Spring processes the annotation. When the annotated class has a single constructor annotated with @Autowired, that's the constructor it will choose to initialize the bean. It also uses the ApplicationContext to resolve beans to inject as arguments to the constructor.

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

Playing on those two facts, you can write a class like this

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

    }
}

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

Here, our inner class has an @Autowired constructor, so Spring knows exactly which Constructor object to use. Because of the @Autowired it will also try to find a bean from the ApplicationContext to match and inject for every parameter the constructor has. In this case, the only parameter is of type Example, the enclosing class. Since Example is also annotated with @Component, it's also a bean in the context, so Spring can inject it into the constructor of the inner class.

这篇关于无论如何@ Inject / @将内部类自动装入一个外部类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆