public class PlatformEventFactory { public PlatformEvent createEvent(String eventType) { if (eventType.equals("deployment_activity")) { return new UdeployEvent(); } return null; } } Tengo una clase de fábrica que crea objetos de tipo PlatformEvent basados en eventType.
La clase UdeployEvent depende de private RedisTemplate<String, Object> template en la que quiero inyectar después de que se haya creado el objeto 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"); } } Cuando se devuelve el nuevo objeto para UdeployEvent , obtengo una excepción de puntero nulo para la plantilla. Creo que la razón de esto es porque no se refiere al mismo frijol que se crea cuando se inicia la primavera. ¿Cómo puedo inyectar dependencias para objetos recién creados en tiempo de ejecución?
No debe crear componentes manualmente. Deja que Spring haga esto. Use ApplicationContext para obtener una instancia del componente. Todos los campos se inyectarán automáticamente:
@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; } } Para que Spring cree una nueva instancia del componente UdeployEvent cada vez que lo solicite, especifique el alcance del componente como 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"); } ... } Ahora, cada vez que llame a context.getBean(UdeployEvent.class) , Spring creará una nueva instancia del componente con dependencias completamente inicializadas.
Cuando está creando objetos a mano, la inyección de dependencia no se realiza en el objeto creado y el campo es nulo.
La manera fácil sería usar AutowireCapableBeanFactory autowireBean() Ejemplo:
@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) debería inyectar sus campos y debería funcionar bien.
Hay soluciones más extendidas con @Configuration, pero producen una gran cantidad de código repetitivo y no dan mucho a cambio.
No he visto una solución más limpia en Spring (como @AssistedInject en Guice).
Fuente: http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
Debe anotar su bean como SCOPE_PROTOTYPE , como señaló @ken-bekov.
Para obtener una instancia de bean prototipo, puede usar org.springframework.beans.factory.ObjectProvider<T> inyectado (autocableado), en lugar de ApplicationContext . El parámetro de tipo de este proveedor debe ser UdeployEvent .
Además, puede proporcionar argumentos para el constructor de clases o el método de fábrica en el método get . Una desventaja de este enfoque es que la llamada para get no se verificará estáticamente.
Una forma más de resolver su problema es intentar usar AutoFactory de Google .