How to inject dependencies in spring for objects created dynamically at runtime?

public class PlatformEventFactory {

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


        return null;
    }
}

      

I have a factory class that creates type objects PlatformEvent

based on eventType.

The UdeployEvent class has a dependency on private RedisTemplate<String, Object> template

which I want to add after the object is created 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");
    }
}

      

When a new object is returned for UdeployEvent

, I get a null pointer exception for the template. I believe the reason for this is that it does not belong to the same bean that is created when spring boot. How can I inject dependencides for newly created objects at runtime.

+3


source to share


3 answers


You cannot create components manually. Let Spring. Use ApplicationContext

to get an instance of a component. All fields will be automatically entered:

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

      

In order for Spring to create a new instance of a bean UdeployEvent

every time you request it, specify the scope of the bean as 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");
    }

    ...
}

      

Now every time you call context.getBean(UdeployEvent.class)

Spring a new bean instance is created with fully initialized dependencies.

+3


source


When you create objects manually, dependency injection is not performed on the created object and the field is null.

An easy way would be to use AutowireCapableBeanFactory

autowireBean()

Example:

@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)

should enter your fields and it should work fine.



There are more advanced solutions with @Configuration, but they produce a lot of boilerplate code and don't provide much in return.

Haven't seen a cleaner solution in Spring (like @AssistedInject in Guice).

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

+1


source


You should annotate your bean as SCOPE_PROTOTYPE

@ ken-bekov pointed out.

To get a prototype bean instance, you can use injected (auto-notified) org.springframework.beans.factory.ObjectProvider<T>

rather than ApplicationContext

. The type parameter of this provider must be UdeployEvent

.
Alternatively, you can provide arguments for the class constructor or factory method in the method get

. One disadvantage of this approach is that the call get

will not be checked statically.

Another way to solve your problem is to use Google AutoFactory .

0


source







All Articles