简体   繁体   English

Spring @Autowired在一个类新实例上

[英]Spring @Autowired on a class new instance

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 MyClass with @Component and use it with an @Autowired , then the @Autowired MyRepository is resolved just fine. 我知道如果我使用@Component注释我的MyClass并将其与@Autowired一起使用,那么@Autowired MyRepository就可以解决了。 Problem is I am in a situation that I need to create new instances of MyClass with reflection. 问题是我需要使用反射创建MyClass新实例。 So MyRepository is never resolved and is null all the time. 所以MyRepository永远不会被解析,并且一直都是null。

Is there a way to use @Autowired in this situation? 在这种情况下有没有办法使用@Autowired

Explaining better my situation: I have some implementations of AbstractClass . 更好地解释我的情况:我有一些AbstractClass实现。 In a setup phase of my application I create a HashMap of these implementations. 在我的应用程序的设置阶段,我创建了这些实现的HashMap Basically: 基本上:

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

Then I have a generic Controller that maps to the url /{class}?options=... Using the {class} @PathVariable , the HashMap above and reflection I am able to create a instance of a class based on the given options (this part is important). 然后我有一个通用的Controller映射到url /{class}?options=...使用{class} @PathVariable ,上面的HashMap和反射我能够根据给定的options创建一个类的实例(这部分很重要)。 Do you guys think there's a better way of doing this? 你们认为有更好的方法吗?

Thanks in advance 提前致谢

Spring itself offers some functionality for doing auto-wiring in your objects which you created by new or newInstance() or whatever. Spring本身提供了一些功能,可以在newnewInstance()或其他任何东西创建的对象中进行自动连接。

To use it you need an AutowireCapableBeanFactory which 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 @Autowired properties 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 AutowireCapableBeanFactory advises against using this interface for most use-cases: AutowireCapableBeanFactory的javadoc建议不要在大多数用例中使用此接口:

This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactory or ListableBeanFactory for typical use cases. BeanFactory的这个子接口并不适用于普通的应用程序代码:对于典型的用例,坚持使用BeanFactoryListableBeanFactory

Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. 其他框架的集成代码可以利用此接口来连接和填充Spring无法控制其生命周期的现有Bean实例。 This is particularly useful for WebWork Actions and Tapestry Page objects, for example. 例如,这对WebWork Actions和Tapestry Page对象特别有用。

One work around is instead of binding the MyClass to the Hashmap to bind a Factory class. 一种解决方法是将MyClass绑定到Hashmap以绑定Factory类。 MyClassFactory. 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. 通过这种方式,您可以将构造委派给具体工厂,该工厂将完成实例化正确的类并初始化正确的存储库。

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. 工厂也可以是Component,然后您需要将hashmap绑定到工厂实例而不是工厂类。 But lets say it is not a component: 但是我们可以说它不是一个组件:

//@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. 如果将其标记为组件,则还可以使用ApplicationContextAware接口(如果要自动装配ApplicationContext)。

You can use Factory Design Pattern over here. 您可以在此处使用Factory Design Pattern

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. 在AbstractClass的所有实现上添加@Component。
  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); } } } 

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. 现在,从这个工厂,您可以获得HashMap,然后在需要时获取实现。 It will be very easy when you add new implementation of AbstractClass as factory will take care of it. 当您添加AbstractClass的新实现时,它将非常容易,因为工厂将负责处理它。

One approach is to declare @Component on top of MyClass . 一种方法是在MyClass之上声明@Component

Then, in the setup phase, you can pass the instance of MyClass instead of MyClass.class itself, in the HashMap. 然后,在设置阶段,您可以在HashMap中传递MyClass实例而不是MyClass.class本身。 There won't be any need to create instances via reflection. 不需要通过反射创建实例。

Note: You can fetch the instance of MyClass from your ApplicationContext in the setup phase. 注意:您可以在设置阶段从ApplicationContext中获取MyClass的实例。

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);
  }

}

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不会抱怨重复的定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM