为什么Service不用Spring注入Controller?

时间:2012-09-13 10:19:09

标签: spring spring-mvc

我遇到控制器和服务注入问题。在Junit测试中,它正在工作所有数据都添加到数据库中,并且我的测试junit没有错误返回。但是当我在Controller中注入服务时,系统返回一个空对象而不是实例化:

我的服务:

package mypackage.services
public interface ExampleService {
public abstract String helloWorld();
}

package mypackage.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service("exampleService")
@Scope("singleton")
public class ExampleServiceImpl implements ExampleService {
@Override
public String helloWorld(){
    return "Hello World !";
}
}

我的控制器:

package mypackage.controller;

import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/planning")
public class PlanningController {

@Autowired
public ExampleService exampleService;

@RequestMapping(method = RequestMethod.GET)
public final ModelAndView planning(final HttpServletRequest request) {
    exampleService.helloWorld();
    final ModelAndView mav = new ModelAndView("planning", "tasks", "tasks");
    return mav;
}
}

弹簧servlet.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
   http://www.springframework.org/schema/jee
   http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
   http://www.springframework.org/schema/data/jpa
   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">


<!-- Use @Component annotations for bean definitions -->
<context:component-scan base-package="mypackage.services" />                                          
<context:component-scan base-package="mypackage.controller" />

<!-- Use @Controller annotations for MVC controller definitions -->
<mvc:annotation-driven />
<aop:aspectj-autoproxy proxy-target-class="true" />

<!-- View resolver -->
<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/" />
    <property name="suffix" value=".jsp" />
</bean>
<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="order" value="1" />
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
        </map>
    </property>
    <property name="defaultViews">
        <list>
            <!-- Renders JSON View -->
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

        </list>
    </property>
</bean>

<mvc:interceptors>
    <!-- Resolve the device that originated the web request -->
    <bean
        class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
</mvc:interceptors>

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myDatasource" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myPU" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true" />
            <property name="database" value="ORACLE" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
            <prop key="hibernate.c3p0.maxSize">1</prop>
            <prop key="hibernate.c3p0.minSize">1</prop>
            <prop key="hibernate.c3p0.acquireIncrement">1</prop>
            <prop key="hibernate.c3p0.idleTestPeriod">300</prop>
            <prop key="hibernate.c3p0.maxStatements">0</prop>
            <prop key="hibernate.c3p0.timeout">1800</prop>
            <prop key="hibernate.c3p0.checkoutTimeout">0</prop>
            <prop key="hibernate.c3p0.preferredTestQuery">SELECT * FROM dual</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

和我的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

 <display-name>Archetype Created Web Application</display-name>

 <servlet>
   <servlet-name>spring</servlet-name>
<servlet-class>
  org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>    
</servlet>

 <servlet-mapping>
 <servlet-name>spring</servlet-name>
 <url-pattern>*.html</url-pattern>
 <url-pattern>*.json</url-pattern>
 </servlet-mapping>

 <listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.xml</param-value>
 </context-param>
 <filter>
    <filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
  </filter>

  <filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
  </filter-mapping>
  <resource-ref>
<description>My DataSource Reference</description>
<res-ref-name>jdbc/myDatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
  </resource-ref>

  <session-config>
   <session-timeout>
     30
   </session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  </web-app>

我的测试:

...
@Autowired
private ApplicationContext applicationContext;

@Test
public void testPlanning() {
    LOGGER.debug("Start testPlanning");

    boolean c = applicationContext.containsBean("exampleService");
    System.out.println(c);

    final PlanningController avc = new PlanningController();        
    final Object mav = avc.planning(request);
    Assert.assertEquals(200, response.getStatus());
    Assert.assertTrue(mav instanceof ModelAndView);
    ModelAndViewAssert.assertViewName((ModelAndView) mav, "planning");
    final BindingResult result = mock(BindingResult.class);
    when(result.hasErrors()).thenReturn(true);
    LOGGER.debug("End testPlanning");
}

我从一个班级继承我的考试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-servlet.xml"})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class})

public abstract class N2WIAppConfigTest {

private static final Logger LOGGER = LoggerFactory
        .getLogger(PlanningControllerTest.class);

@BeforeClass
public static void setUpClass() throws Exception {
    // rcarver - setup the jndi context and the datasource
    LOGGER.debug("CALL setUpClass");
    try {
        // Create initial context
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.naming.java.javaURLContextFactory");
        System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
        SimpleNamingContextBuilder builder = SimpleNamingContextBuilder
                .emptyActivatedContextBuilder();
        // Construct DataSource
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass("oracle.jdbc.driver.OracleDriver");
        ds.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
        ds.setUser("nemo2");
        ds.setPassword("nemo2");
        builder.bind("java:comp/env/jdbc/myDatasource", ds);
        builder.activate();
    } catch (NamingException ex) {
        System.out.println("###################################");
        ex.printStackTrace();

    }

}
}

我尝试在我的测试中加载ApplicationContext,如果加载了服务,则情况就是如此。但是在PlanningController中,不会注入服务。

PlanningController中出现问题。 ExampleService没有注入,也不明白为什么。你有什么想法吗?

非常感谢

2 个答案:

答案 0 :(得分:1)

要使@Autowire工作,我们需要配置一系列事项

    在context.xml中
  • <context:annotation-config />您错过了这个。
  • {li} xmlns:context="http://www.springframework.org/schema/context<beans ..标记中
  • Spring {Ster}类型注释,如@Controller, @Component, @Service等。

答案 1 :(得分:0)

那是因为在这一行:

final PlanningController avc = new PlanningController();    

你是手动创建一个bean实例而不是将它留给spring,所以spring无法自动连接依赖项。

您应该将bean创建留给容器(在本例中为spring)或自己设置bean属性。

在您的情况下,您可以使用

访问弹簧管理的PlanningController实例
applicationContext.getBean(PlanningController.class);