Java Spring @Autowired 在类新实例上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/52355132/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:24:50  来源:igfitidea点击:

Spring @Autowired on a class new instance

javaspringdependency-injectionautowired

提问by Jo?o Menighin

I'm not so familiar with Spring and I have the following situation:

我对Spring不太熟悉,我有以下情况:

A repository class:

一个存储库类:

@Repository
public class MyRepository {
    // ...
}

A class that uses the repository class:

使用存储库类的类:

public class MyClass extends AbstractClass {

    @Autowired
    private MyRepository myRepository;

    //...
}

I know that if I annotate my MyClasswith @Componentand use it with an @Autowired, then the @AutowiredMyRepositoryis resolved just fine. Problem is I am in a situation that I need to create new instances of MyClasswith reflection. So MyRepositoryis never resolved and is null all the time.

我知道,如果我MyClass用 with注释@Component并使用它@Autowired,那么@AutowiredMyRepository就可以很好地解决。问题是我处于一种需要MyClass使用反射创建新实例的情况。所以MyRepository永远不会解决并且一直为空。

Is there a way to use @Autowiredin this situation?

有没有办法@Autowired在这种情况下使用?

Explaining better my situation: I have some implementations of AbstractClass. In a setup phase of my application I create a HashMapof these implementations. Basically:

更好地解释我的情况:我有一些AbstractClass. 在我的应用程序的设置阶段,我创建了HashMap这些实现中的一个。基本上:

{"MyClass", MyClass.class}
//...

Then I have a generic Controllerthat maps to the url /{class}?options=...Using the {class}@PathVariable, the HashMapabove and reflection I am able to create a instance of a class based on the given options(this part is important). Do you guys think there's a better way of doing this?

然后我有一个Controller映射到 url的泛型/{class}?options=...使用{class}@PathVariableHashMap上面和反射我能够创建一个基于给定的类的实例options(这部分很重要)。你们认为有更好的方法吗?

Thanks in advance

提前致谢

采纳答案by Thomas Fritsch

Spring itself offers some functionality for doing auto-wiring in your objects which you created by newor newInstance()or whatever.

Spring本身通过提供为你的对象做自动装配的一些功能,你创建new或者newInstance()或什么的。

To use it you need an AutowireCapableBeanFactorywhich you get by Spring's normal dependency injection with @Autowired.

要使用它,您需要AutowireCapableBeanFactory通过 Spring 的常规依赖注入使用@Autowired.

@Autowired
private  AutowireCapableBeanFactory autowireCapableBeanFactory;

Then you use its autowireBean(Object)method to inject the @Autowiredproperties into your bean.

然后您使用它的autowireBean(Object)方法将@Autowired属性注入到您的 bean 中。

Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);


Design note:

设计说明:

Think well if you really need the approach above. The javadoc of AutowireCapableBeanFactoryadvises against using this interface for most use-cases:

如果您真的需要上述方法,请好好考虑。的 javadocAutowireCapableBeanFactory建议不要在大多数用例中使用此接口:

This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactoryor ListableBeanFactoryfor typical use cases.

Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example.

BeanFactory 的这个子接口不打算在正常的应用程序代码中使用:坚持BeanFactoryListableBeanFactory用于典型用例。

其他框架的集成代码可以利用此接口来连接和填充 Spring 无法控制其生命周期的现有 bean 实例。例如,这对于 WebWork Actions 和 Tapestry Page 对象特别有用。

回答by Jo?o Menighin

Yes, you can annotate all your AbstractClass implementation beans with @Component and use the next declaration

是的,您可以使用 @Component 注释所有 AbstractClass 实现 bean 并使用下一个声明

@Autowired
private List<AbstractClass> beans;

You can then convert that to a Map in a @PostConstruct method.

然后,您可以在 @PostConstruct 方法中将其转换为 Map。

Spring won't complain about duplicate definitions if you autowire Lists.

如果您自动装配列表,Spring 不会抱怨重复定义。

回答by Pankaj Singhal

One approach is to declare @Componenton top of MyClass.

一种方法是@ComponentMyClass.

Then, in the setup phase, you can pass the instanceof MyClassinstead of MyClass.classitself, in the HashMap. There won't be any need to create instances via reflection.

然后,在安装阶段,可以通过实例MyClass,而不是MyClass.class它本身,在HashMap中。不需要通过反射创建实例。

Note:You can fetch the instance of MyClassfrom your ApplicationContextin the setup phase.

注意:您可以在设置阶段MyClass从您的实例中获取ApplicationContext

回答by Alexandar Petrov

One work around is instead of binding the MyClass to the Hashmap to bind a Factory class. MyClassFactory. This way you will delegate the construction to a concrete factory that will do the job to instantiate the correct class and initialize the correct repository.

一种解决方法是将 MyClass 绑定到 Hashmap 以绑定 Factory 类。我的类工厂。通过这种方式,您将构造委托给一个具体工厂,该工厂将完成实例化正确类并初始化正确存储库的工作。

Here is an example:

下面是一个例子:

{"MyClass", MyClassFactory.class}

The factory can be Component as well, then you need to bind the hashmap to the factory instance instead of the factory class. But lets say it is not a component:

工厂也可以是 Component ,那么你需要将 hashmap 绑定到工厂实例而不是工厂类。但可以说它不是一个组件:

//@Component   this is optional
    public MyClassFactory {
        //@Autowired optional
        ApplicationContext ctx;


       public MyClass createInstance() {
            MyRepository repo = ctx.getBean("")
            MyClass myclass = new MyClass(repo)
            return myclass;
       }
    }

If you mark it as component you can well also use ApplicationContextAware interface if you are going to autowire the ApplicationContext.

如果您将其标记为组件,如果您要自动装配 ApplicationContext,您也可以使用 ApplicationContextAware 接口。

回答by Rishabh Agarwal

You can use Factory Design Patternover here.

你可以在这里使用工厂设计模式

This might seem a little complicated in start but I am sure you will love it after you have implemented it.

这在开始时可能看起来有点复杂,但我相信您在实施后会喜欢它。

Steps:

脚步:

  1. Add @Component on all implementations of AbstractClass.
  2. Create a factory class as:

    @Component
    public class MyFactory {
    
        private final Map<String, AbstractClass> impletationMap = new HashMap<>();
    
        @Autowired
        ApplicationContext context;
    
        @PostConstruct
        public void initialize() {
            populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
        }
    
        private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
            while (classIterator.hasNext()) {
                AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
                impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
    
            }
        }
    }
    
  1. 在 AbstractClass 的所有实现上添加 @Component。
  2. 创建一个工厂类:

    @Component
    public class MyFactory {
    
        private final Map<String, AbstractClass> impletationMap = new HashMap<>();
    
        @Autowired
        ApplicationContext context;
    
        @PostConstruct
        public void initialize() {
            populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
        }
    
        private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
            while (classIterator.hasNext()) {
                AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
                impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
    
            }
        }
    }
    

When the Bean of this MyFactory class is initialized, then it will lookup for all beans of type AbstractClass and put them in the HashMap(implementationMap).

当初始化这个 MyFactory 类的 Bean 时,它会查找所有类型为 AbstractClass 的 bean 并将它们放入 HashMap(implementationMap)。

Now from this factory you can get the HashMap and then get the implementations as and when you require. It will be very easy when you add new implementation of AbstractClass as factory will take care of it.

现在,您可以从这个工厂获取 HashMap,然后在需要时获取实现。当您添加 AbstractClass 的新实现时,这将非常容易,因为工厂会处理它。

回答by Maruthi Adithya

Try this

尝试这个

@Component    
public class SomeClass extends AbstractClass {

  private static ApplicationContext applicationContext;

  public MyClass getMyClass(){
      // Now @Autowired MyRepository will work
      return applicationContext.getBean(MyClass.class);
  }

}