@Autowired no funciona si se aplica a un bean compartido entre dos subprocesos

Tengo algunos problemas con un escenario muy básico: tengo una aplicación web Java (primavera 3) y quiero almacenar algún objeto en una pila. Luego, quiero administrar los objetos en la pila con un planificador, por lo que implementé un trabajo de cuarzo. Llano y simple. Inyecto la pila en la primera clase de servicio y en la clase de trabajo con la anotación @Autowired. Para la clase de servicio, la tabla se inyecta con éxito, pero para la clase de trabajo, la tabla es nula. aquí está el código:

la clase para compartir

package it.unifi.det.telemat.vr.data;
@Component
public class IndexedNodesStack extends HashMap<IndexedObject, Boolean>{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Override
    public synchronized int size() {
        // TODO Auto-generated method stub
        return super.size();
    }

    //all the HashMap methods are implemented in a synchronized wrapper method

}

la primera clase (@Autowired tiene éxito)

package it.unifi.det.telemat.vr.service;
@Service
public class InnerNodeManager extends ConcreteNodeManager{

    @Autowired
    private IndexedNodesStack indexedNodesStack; //<--- it is actually autowired!


    private void manageIndexedNodes(Boolean isPut, String lri, String features)
    {
        IndexedObject indexedObject = new IndexedObject();
        indexedObject.setId(lri);
        if(features != null && isPut)
            indexedObject.generateFeatures(features);

        indexedNodesStack.put(indexedObject, isPut);
    }

}

la clase de trabajo (@Autowired falla)

package it.unifi.det.telemat.vr.service.scheduler;
@Component
public class QuartzJSearchJob extends QuartzJobBean{

    @Autowired
    private IndexedNodesStack indexedNodesStack; //<--- this variable is null :-(

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException
    {
        //do work       
    }
}

EDIT: aquí está el servlet.xml

<context:component-scan base-package="it.unifi.det.telemat.vr" />

<bean name="searchJob"
class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="it.unifi.det.telemat.vr.service.scheduler.QuartzJSearchJob" />
</bean>

<bean id="searchJobTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="searchJob" />
    <property name="cronExpression" value="0/50 * * * * ?" />
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
    <list>
        <ref bean="searchJobTrigger" />
        </list>
    </property>
</bean>

tal vez me falta algo de conocimiento sobre el intercambio de recursos entre subprocesos, ya que es mi primer intento en este campo. ¿Qué me estoy perdiendo?

preguntado el 03 de mayo de 12 a las 18:05

deberá mostrar cómo está creando el objeto para explicar por qué Spring no lo inicializaría correctamente. como se inicializa? -

el trabajo se crea a través de la anotación @Component (edité mi pregunta para corregirla) -

6 Respuestas

El cableado automático solo funciona si el bean se crea desde la fábrica Spring bean. ¿Creó el objeto sin usar bean factory, es decir, lo creó usando new QuartzJSearchJob() ¿sintaxis?

contestado el 03 de mayo de 12 a las 18:05

Intento crearlo con la anotación @Component - mavvamaldo

¿Puedes publicar tu configuración de bean? Agregar @Component no ayuda si la fábrica de frijoles no crea el bean. - gigadot

puedes intentar usar setBeanName en lugar de setJobClass con el valor del nombre del bean, por ejemplo quartzJSearchJob? - gigadot

Lo intenté pero el planificador no activa nada. ¿Es una pista de algo? Esto es lo que hice: <bean id="quartzJSearchJob" class="it.unifi.det.telemat.vr.service.scheduler.QuartzJSearchJob"> </bean> <bean name="searchJob" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="beanName" value="quartzJSearchJob" /> </bean> - mavvamaldo

Intente agregar un método que verifique si el campo está autoconectado correctamente en QuartzJSearchJob y anote el método con la anotación @PostConstruct. Si está autocableado correctamente, el problema es sobre la configuración de Quartz y no sé nada al respecto. - gigadot

ok, finalmente entiendo el punto. No funciona porque la primavera no crea una instancia del trabajo de búsqueda de cuarzo, sino el cuarzo. Los beans a inyectar dentro del trabajo tienen que pasar por SchedulerFacoryBean. Aquí está la configuración que hace que las cosas funcionen.

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="searchJobTrigger" />
        </list>
    </property>
    <property name="schedulerContextAsMap">
    <map>
       <entry key="indexedNodesStack" value-ref="indexedNodesStack" />
    </map>
    </property>
</bean>

contestado el 04 de mayo de 12 a las 10:05

QuartzJSearchJob no se reconoce como un frijol porque no tiene una anotación de nivel de clase. Tratar @Component

contestado el 03 de mayo de 12 a las 18:05

mi culpa, omití @Component en la operación de pegado mientras estaba presente en el código. Edité mi pregunta. - mavvamaldo

Olvidas la propiedad "jobDetails":

<property name="jobDetails">
    <list>
        <ref bean="searchJob" />
    </list>
</property>

También necesitas usar org.springframework.scheduling.quartz.JobDetailFactoryBean en lugar de org.springframework.scheduling.quartz.JobDetailBean.

Insértalo así:

<bean name="searchJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="it.unifi.det.telemat.vr.service.scheduler.QuartzJSearchJob" />
</bean>

<bean id="searchJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="searchJob" />
    <property name="cronExpression" value="0/50 * * * * ?" />
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="searchJobTrigger" />
        </list>
    </property>
    <property name="jobDetails">
        <list>
            <ref bean="searchJob" />
        </list>
    </property>
</bean>

Respondido el 09 de enero de 15 a las 15:01

Tengo el mismo problema, lo resolví agregando SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); como primera línea de mi Job.execute(JobExecutionContext context) método.

respondido 24 nov., 16:16

Creo que debes asignar un valor en scheduleFactoryBean, setSchedulerContextAsMap(), pones tu objeto en este mapa, luego funcionará.

@Bean(name = "scheduler")
  public SchedulerFactoryBean schedulerFactory()
  {
    SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
    schedulerFactory.setDataSource(dataSource);
    schedulerFactory.setAutoStartup(true);
    schedulerFactory.setGlobalJobListeners(globalJobListeners);
    schedulerFactory.setSchedulerContextAsMap(contextMap());
    schedulerFactory.setQuartzProperties(schedulerProperties());
    return schedulerFactory;
  }

Respondido el 18 de diciembre de 14 a las 09:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.