春天@Autowired不工作(不总是)

时间:2013-07-19 19:06:03

标签: spring spring-mvc annotations autowired

我的一项服务中的autowire注释存在一些问题。我花了很多时间来寻找解决方案,但我不知道自己做错了什么。我的应用程序看起来像这样。

这是我的控制器:

package control.peso.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import control.peso.data.ResumenMedicionPeso;
import control.peso.service.HomeService;

@Controller
public class HomeController {

    @Autowired
    private HomeService homeService; //NOPMD

    @RequestMapping(value = "json/resumen_mediciones.action")
    @ResponseBody
    public final ResumenMedicionPeso
            dataJsonPeso(final HttpServletRequest req) {
        final ResumenMedicionPeso peso = homeService.getResumenMediciones();

        return peso;
    }
}

我的服务层:

package control.peso.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import control.peso.dao.PesoDAO;
import control.peso.data.ResumenMedicionPeso;

@Service
@Transactional(readOnly = true)
public class HomeService {

    @Autowired
    private PesoDAO pesoDAO; //NOPMD

    public final ResumenMedicionPeso getResumenMediciones() {
        final ResumenMedicionPeso resumMedicionPeso = new ResumenMedicionPeso();
        resumMedicionPeso.setMaxPeso(pesoDAO.getMaxPeso());
        resumMedicionPeso.setMinPeso(pesoDAO.getMinPeso());
        resumMedicionPeso.setMaxGrasa(pesoDAO.getMaxGrasa());
        resumMedicionPeso.setMinGrasa(pesoDAO.getMinGrasa());
        resumMedicionPeso.setMaxPorcenGrasa(pesoDAO.getMaxPorcenGrasa());
        resumMedicionPeso.setMinPorcenGrasa(pesoDAO.getMinPorcenGrasa());
        resumMedicionPeso.setMaxMusculo(pesoDAO.getMaxMusculo());
        resumMedicionPeso.setMinMusculo(pesoDAO.getMinMusculo());
        resumMedicionPeso.setMaxPorcenMusculo(pesoDAO.getMaxPorcenMusculo());
        resumMedicionPeso.setMinPorcenMusculo(pesoDAO.getMinPorcenMusculo());

        return resumMedicionPeso;
    }
}

我的道:

package control.peso.dao;

import java.util.List;

import org.hibernate.SessionFactory;

import control.peso.model.MedicionPeso;

public class PesoDAO implements IPesoDAO {

    private SessionFactory sessionFactory;

    public final SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public final void setSessionFactory(
            final SessionFactory pSessionFactory) {
        this.sessionFactory = pSessionFactory;
    }

    @Override
    public final void addPeso(final MedicionPeso peso) {
        getSessionFactory().getCurrentSession().save(peso); //NOPMD
    }

    @Override
    public final void updatePeso(final MedicionPeso peso) {
        getSessionFactory().getCurrentSession().update(peso);  //NOPMD
    }

    @Override
    public final void deletePeso(final Integer idPeso) {
        getSessionFactory().getCurrentSession()
        .delete(new MedicionPeso(idPeso));
    }

    @Override
    public final MedicionPeso getPesoById(final Integer idPeso) {
        @SuppressWarnings("unchecked") //NOPMD
        final List<MedicionPeso> list = getSessionFactory() // NOPMD
                .getCurrentSession()
                        .createQuery("from MedicionPeso where idPeso = ?")
                .setParameter(0, idPeso).list();

        return list.get(0); //NOPMD
    }

    @Override
    public final List<MedicionPeso> getPesos() {
        @SuppressWarnings("unchecked")
        final List<MedicionPeso> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("from MedicionPeso medicionPeso "
                        + "order by medicionPeso.fechaMedicion desc")
                .list();

        return list;
    }

    public final Float getMaxPeso() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(peso) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMinPeso() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select min(peso) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMaxGrasa() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(pesoGrasa) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMinGrasa() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select min(pesoGrasa) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMaxPorcenGrasa() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(pesoGrasa) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMinPorcenGrasa() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select min(porcentajeGrasa) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    /**
     * Recupera la medicion de musculo con valor maximo.
     * @return El valor maximo de las mediciones de musculo.
     */
    public final Float getMaxMusculo() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(porcentajeGrasa) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMinMusculo() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select min(pesoMusculo) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMaxPorcenMusculo() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(porcentajeMusculo) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

    public final Float getMinPorcenMusculo() {
        @SuppressWarnings("unchecked")
        final List<Float> list = getSessionFactory() //NOPMD
                .getCurrentSession()
                .createQuery("select max(porcentajeMusculo) from MedicionPeso")
                .list();

        return (Float) list.get(0); //NOPMD
    }

}

我的dao界面:

package control.peso.dao;

import java.util.List;

import control.peso.model.MedicionPeso;

public interface IPesoDAO {

    void addPeso(MedicionPeso peso);

    void updatePeso(MedicionPeso peso);

    void deletePeso(Integer idPeso);

    MedicionPeso getPesoById(Integer idPeso);

    List<MedicionPeso> getPesos();
}

这是我的dispatcher-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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!--Routes -->
    <mvc:view-controller path="/" view-name="home"/>
    <mvc:view-controller path="/home" view-name="home"/>
    <mvc:view-controller path="/medicion" view-name="medicion_peso"/>

    <!-- Scans the classpath of this application for @Components to deploy as beans -->
    <context:component-scan base-package="control.peso" />

    <!-- Configures the @Controller programming model -->
    <mvc:annotation-driven />

    <!-- misc -->
    <!--
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    -->
    <!-- Tiles Resolver -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass">
            <value>
                org.springframework.web.servlet.view.tiles2.TilesView
            </value>
        </property>
    </bean>
    <bean id="tilesConfigurer"
        class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean>

    <!-- Application Message Bundle -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <!-- JSON Objets Definition -->
    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
            </list>
        </property>
    </bean>

    <!-- Beans Declaration -->
    <bean id="MedicionPeso" class="control.peso.model.MedicionPeso" />

    <!-- User DAO Declaration -->
    <bean id="PesoDAO" class="control.peso.dao.PesoDAO">
        <property name="sessionFactory" ref="SessionFactory" />
    </bean>

    <!-- Data Source Declaration -->
    <bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/juan" />
        <property name="user" value="root" />
        <property name="password" value="" />
        <property name="maxPoolSize" value="10" />
        <property name="maxStatements" value="0" />
        <property name="minPoolSize" value="5" />
    </bean>

    <!-- Session Factory Declaration -->
    <bean id="SessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="DataSource" />
        <property name="annotatedClasses">
            <list>
                <value>control.peso.model.MedicionPeso</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager" />

    <!-- Transaction Manager is defined -->
    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="SessionFactory" />
    </bean>

</beans>

因此,当我启动我的网络应用程序时,我的控制器正确地自动服务该服务,但我服务中的DAO对象具有空值(未正确注入)。

有什么想法吗?

很奇怪,因为从另一个服务中,相同的DAO被正确注入。

由于

3 个答案:

答案 0 :(得分:2)

HomeService中,您已指定IPesoDAO的实施,而不是界面。尝试将其更改为IPesoDAO,看看是否有帮助。

此外,您可能还想创建一个接口IHomeService并让现有的HomeService实现它,再次,更改控制器以引用接口,而不是实现

答案 1 :(得分:1)

要掌握的主要事情是您的服务是@Transactional,这意味着Spring必须围绕它创建事务代理。它是一个单独的对象,而不是bean,它将所有方法调用委托给原始bean,在前后打开和关闭事务。

由于 incomplete-co.de 建议您将服务注入类,而不是接口。

在这种情况下,自动创建单独代理对象的唯一方法是子类化原始服务类HomeService。如果一切都正常,那么将创建一个子类:

  • 第一个值得注意的副作用是HomeService的构造函数将被调用两次 - 因为在Java中你被迫调用超类的构造函数,所以代理的构造函数将调用HomeService的构造函数以及bean本身的构造。

  • 第二个影响是Java中的子类继承了超类的所有基本字段,它们没有被初始化,即代理实例的pesoDAO引用将为null 。没关系,因为代理不需要字段值,因为它会调用原始bean的方法,这些字段被初始化。

  • 第三件事是,只有当超级类的方法未被宣布为最终

  • 时,此方案才有效。

在您调用代理方法而不是将调用委托给原始bean的情况下,它表现为超类但其字段未初始化。

所以我建议遵循 incomplete-co.de 建议并将服务注入接口,接口更适合代理,因为代理框架不必与子类限制作斗争。

P.S。另一个小的限制是,在子类化框架中需要有一个策略来决定调用哪个继承的构造函数 - 在Spring / CGLIB中,无参数构造函数是首选,因此如果编译器没有自动执行此操作,您将被迫创建一个。

所以这些是一些实际的原因(我在这里没有提到好的OOD原则)为什么在Spring中我们被迫将服务作为接口注入。

答案 2 :(得分:0)

你有一个奇怪的基于注释和基于XML的bean声明的混合,这使得代码不清楚 - 尽可能多地使用注释并且仅将XML配置用于特定的东西(数据源,jpa相关的东西,第三)派对豆)。

单独使用@Autowired也会产生误导 - 在这种情况下,Spring会尝试查找名为注释类成员的bean。

在您的特定情况下,您将XML中的DAO bean声明为:

<!-- User DAO Declaration -->
<bean id="PesoDAO" class="control.peso.dao.PesoDAO">
    <property name="sessionFactory" ref="SessionFactory" />
</bean>

然后你试图把它注入:

@Service
@Transactional(readOnly = true)
public class HomeService {

    @Autowired
    private PesoDAO pesoDAO; //NOPMD

}

这可能会导致注入失败,因为Spring会尝试找到名为'pesoDao'的bean(这是默认的命名约定),但你有XML中的'PesoDao'。

要解决此问题并且从不担心此类问题,您可以显式命名带注释的bean,并在自动装配时显式提供此名称(使用@Qualifier注释)。

示例:

@Component("pesoDao")
public class PesoDAO implements IPesoDAO {

    private SessionFactory sessionFactory;
}

@Service("homeService")
@Transactional(readOnly = true)
public class HomeService {

    @Autowired
    @Qualifier("pesoDao")
    private PesoDAO pesoDAO; //NOPMD
}

在这种情况下,你总是知道要注射什么。