如何在Spring中为在运行时动态创建的对象注入依赖项?

时间:2017-03-25 11:19:12

标签: java spring spring-boot dependency-injection factory-pattern

public class PlatformEventFactory {

    public PlatformEvent createEvent(String eventType) {
        if (eventType.equals("deployment_activity")) {
            return new UdeployEvent();
        }


        return null;
    }
}

我有一个工厂类,它根据eventType创建PlatformEvent类型对象。

在创建private RedisTemplate<String, Object> template对象后,UdeployEvent类依赖于我想要注入的UdeployEvent

@Component
public class UdeployEvent implements PlatformEvent {

    private RedisTemplate<String, Object> template;
    private UDeployMessage uDeployMessage;

    private static final Logger logger = LoggerFactory.getLogger(UdeployEvent.class);

    public UdeployEvent() {
        uDeployMessage = new UDeployMessage();
    }


    /*public void sendNotification() {

    }*/

    public RedisTemplate<String, Object> getTemplate() {
        return template;
    }

    @Autowired
    public void setTemplate(RedisTemplate<String, Object> template) {
        this.template = template;
        System.out.println("Injection done");
    }
}

UdeployEvent返回新对象时,我得到模板的空指针异常。我相信原因是因为它不是指弹簧启动时创建的同一个bean。 如何在运行时为新创建的对象注入依赖项。

3 个答案:

答案 0 :(得分:4)

您不应手动创建组件。让Spring来做这件事。使用ApplicationContext获取组件实例。所有字段都将自动注入:

@Component
public class PlatformEventFactory {

    @Autowired
    private ApplicationContext context;

    public PlatformEvent createEvent(String eventType) {
        if (eventType.equals("deployment_activity")) {                
            return context.getBean(UdeployEvent.class);
        }

        return null;
    }
}

要使Spring在每次请求时都创建UdeployEvent组件的新实例,请将组件范围指定为SCOPE_PROTOTYPE

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class UdeployEvent implements PlatformEvent {

    private RedisTemplate<String, Object> template;

    public RedisTemplate<String, Object> getTemplate() {
        return template;
    }

    @Autowired
    public void setTemplate(RedisTemplate<String, Object> template) {
        this.template = template;
        System.out.println("Injection done");
    }

    ...
}

现在每次调用context.getBean(UdeployEvent.class) Spring都会创建具有完全初始化依赖关系的组件的新实例。

答案 1 :(得分:1)

当您手动创建对象时,不会在创建的对象中执行依赖项注入,并且该字段为空。

简单的方法是使用AutowireCapableBeanFactory autowireBean() 例如:

@Component
public class PlatformEventFactory {

    @Autowired  
    private AutowireCapableBeanFactory beanFactory;

    public PlatformEvent createEvent(String eventType) {
        if (eventType.equals("deployment_activity")) {
            PlatformEvent platformEvent = new UdeployEvent();
            beanFactory.autowireBean(platformEvent);
            return platformEvent;
        }

        return null;
    }
}

beanFactory.autowireBean(platformEvent)应该注入你的字段,它应该可以正常工作。

@Configuration有更多的扩展解决方案,但是它们产生了大量的样板代码,并没有给予太多回报。

Haven在Spring中看不到更清洁的解决方案(比如Guice中的@AssistedInject)。

来源: http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html

答案 2 :(得分:0)

你应该将你的bean注释为SCOPE_PROTOTYPE,正如@ ken-bekov指出的那样。

要获取原型bean的实例,您可以使用注入(自动装配)org.springframework.beans.factory.ObjectProvider<T>,而不是ApplicationContext。此提供商的类型参数应为UdeployEvent 另外,您可以在get方法中为类构造函数或工厂方法提供参数。这种方法的一个缺点是不会静态检查对get的调用。

解决问题的另一种方法是尝试使用Google's AutoFactory