1

I am having trouble injecting a @Service bean into a QuartzJobBean. Using the tips from this question, I was able to inject a @Repository bean but not a @Service bean. Here's what I have:

A Repository bean to access MongoDB document:

public interface MyRepository extends MongoRepository<> {}

A Service bean to perform business logic:

@Service
public class MyService {
    @Autowired
    private MyRepository myRepository;

    public void method1() { ... }
}

I was able to use MyService from a Spring MVC controller, so I know Spring instantiated them properly.

Next I created a Job that extends from QuartzJobBean and try to inject MyService into it:

    <bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.MyJob" />  
    </bean>
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
       [jobDetails and triggers omitted]
       <property name="schedulerContextAsMap">
        <map>
           <entry key="myService">
                <ref bean="myService"/>
           </entry>

        </map>
    </property>
    </bean>

With this config, I got 'BeanCreationException: Cannot resolve reference to bean 'myService' while setting bean property 'schedulerContextAsMap'

If I change 'myService' in the schedulerContextAsMap to 'myRepository' it worked. But then I don't want to re-implement the business logic in the QuartzJobBean.

Why is it that myService bean is not visible to the SchedulerFactoryBean? BTW, I already have annotation-config and component-scan tags enabled.

[Update - Context Initialization] Here's my web.xml, as you can see spring-quartz.xml is referenced last so everything should have been initialized before it, no?

  <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
        /WEB-INF/spring/root-context.xml,
        /WEB-INF/spring/spring-security.xml,
        /WEB-INF/spring/spring-quartz.xml
      </param-value>
   </context-param>
  <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>appServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
      </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
     <url-pattern>/</url-pattern>
   </servlet-mapping>

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->
<!-- Factory bean that creates the Mongo instance -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
    <property name="host" value="localhost" />
</bean>

<!-- MongoTemplate for connecting and quering the documents in the database -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongo" ref="mongo" />
    <constructor-arg name="databaseName" value="test" />
</bean>

<!-- Use this post processor to translate any MongoExceptions thrown in @Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

<mongo:repositories base-package="com.repositories" />

</beans>

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven conversion-service="conversionService">
    <argument-resolvers>
        <beans:bean class="org.springframework.mvc.data.CustomArgumentResolver"/>           
        <beans:bean class="org.springframework.data.web.PageableArgumentResolver" />
    </argument-resolvers>
</annotation-driven>

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>

<!-- Only needed because we install custom converters to support the examples in the org.springframewok.samples.mvc.convert package -->
<beans:bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <beans:property name="formatters">
        <beans:bean class="org.springframework.mvc.convert.MaskFormatAnnotationFormatterFactory" />
    </beans:property>
</beans:bean>

<!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

<context:annotation-config />
<context:component-scan base-package="com" />
</beans:beans>
Community
  • 1
  • 1
azgolfer
  • 15,087
  • 4
  • 49
  • 46
  • 1
    How and when do you initialize your application context(s)? Based on your issue, most likely scheduler is being instantiated in a context before the context that instantiates the service. Edit your question to provide detail on how you initialize the context. – kaliatech Aug 22 '13 at 16:48
  • You're right. I moved my spring-quartz.xml file around and now the schedulerFactory is able to see the Service reference. Thanks. – azgolfer Aug 22 '13 at 17:37

1 Answers1

0

It seems as if you have resolved the issue per your comment on your question. However, just-in-case:

The underlying original problem is that you have only configured component scan in the servlet-context. As a result, the MyService annotation is getting processed only when the servlet context gets initialized. It is not available yet when the spring-quartz.xml is processed for the root context by the ContextLoaderListener.

You likely want to enable component scanning in your root-context.xml if you are using annotations for your Services, etc. but filter out anything, such as Controllers, that would be picked up by the component scan in your servlet context so that you don't get duplicate initializations.

If your services and web code share common packages names, then a common pattern is to use filters, component scanning everything except controllers in to the root context, and then scan only controllers (and servlets) in the servet context, using something like this:

root-context.xml

<context:component-scan base-package="package">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

servlet-context.xml

<context:component-scan base-package="package" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>

Of course, there are many other options. For more info:

Community
  • 1
  • 1
kaliatech
  • 17,579
  • 5
  • 72
  • 84