2013-07-19 4 views
2

У меня есть некоторые проблемы с аннотацией автозапуска в одном из моих сервисов. Я потратил много часов, чтобы найти решение, но у меня нет идеи, что я делаю неправильно. Мое приложение выглядит так.Spring @Autowired не работает (не всегда)

Вот мой контроллер:

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 
    } 

} 

Мой дао интерфейс:

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(); 
} 

Это мой диспетчеру-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> 

Так что, когда я запускаю мой веб-приложение, мой контроллер Autowires правильно сервис, но мой объект DAO в моей службе имеет нулевое значение (не впрыскивается должным образом) ,

Любые идеи?

Любопытно, потому что из другой службы тот же DAO правильно вводится.

Благодаря

ответ

2

в вашем HomeService, вы указали реализацию IPesoDAO, а не интерфейса. попробуйте изменить его на IPesoDAO и посмотрите, поможет ли это.

Кроме того, вы также можете создать интерфейс IHomeService и иметь существующую HomeService осуществить это, опять же, изменив контроллер для ссылки на интерфейс, а не реализация

+0

Спасибо. Я рад, что Spring заставил меня создать интерфейс .. но это исправить проблему. – coder

0

У вас есть странное сочетание аннотаций на основе и XML-декларация beans, которая делает код непонятным - лучше всего использовать аннотации как можно больше и использовать конфигурацию XML только для конкретных вещей (источники данных, связанные с jpa-файлами, сторонние компоненты).

Использование @Autewired самостоятельно также вводит в заблуждение - в этом случае Spring попытается найти bean-элемент, названный вашим аннотированным членом класса.

В вашем конкретном случае, вы объявляете DAO боб в XML как:

<!-- 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 

} 

Это, вероятно, привести к сбою инъекции, так как весна будет пытаться для поиска bean, называемого «pesoDao» (это соглашение об именах по умолчанию), но у вас есть «PesoDao» в XML.

Чтобы решить эту проблему, а также не беспокоиться о таких проблемах, вы можете явно указать свои аннотированные компоненты, а также явно указывать это имя при автоподготовке (используйте аннотацию @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 
} 

В этом случае, вы всегда будете знать, что будет вводиться.

+0

Проблема с использованием аннотаций в значительной степени заключается в том, что они заключают в себе связь фасоли друг с другом и рассеивают конфигурацию поверх кода. Это не значит, что все плохо, но есть причины, чтобы уменьшить их использование. –

+0

Истинно, если вы разрабатываете свои компоненты таким образом, чтобы вы могли использовать их вне контейнера IoC, то есть когда все ваши компоненты имеют подходящие конструкторы/геттеры/сеттеры, чтобы вставлять все зависимости вручную.В таком случае я бы определенно удалил аннотацию и использовал конфигурацию XML. Однако, если вы знаете, что вы будете использовать контейнер IoC в любом случае - почему бы не облегчить жизнь? Во всяком случае, мой основной момент состоял в том, чтобы сказать «выберите то, что вы предпочитаете - XML ​​или аннотации, не используйте случайный микс». –

+0

На самом деле, я предпочитаю конфигурацию XML, даже если внутри контейнера IoC. Я использую только аннотации для тех функций, которые _must_ будут использоваться для работы bean-компонента, или где я делаю то, что трудно сделать другим способом (есть несколько ключевых вещей, подобных этому, но не так много). Мне нравится отделять конфигурацию от кода; это способствует лучшей тестируемости. –

1

Главное, чтобы понять, что ваше обслуживание - @Transactional, что означает, что Spring должен будет создать транзакционный прокси-сервер вокруг него. Это отдельный объект, который вводится вместо bean, который будет делегировать все вызовы его методам на исходный компонент, открывать и закрывать транзакции до и после.

Как incomplete-co.de предложил, что ваша служба вводится как класс, а не как интерфейс.

В этом случае единственным способом автоматического создания отдельного прокси-объекта является подкласс исходного класса обслуживания HomeService. Если все пойдет нормально, чем подкласс будет создан:

  • Первый заметный побочный эффект будет то, что конструктор HomeService будет называться дважды - потому, что в Java вы вынуждены вызвать конструктор суперкласса, поэтому конструктор прокси вызовет конструктор HomeService в дополнение к построению самого компонента.

  • Второй эффект будет то, что подкласс Java наследует все базовые поля суперкласса, они не инициализируются, т.е. pesoDAO ссылка прокси экземпляра будет нулевым. Это нормально, потому что значения поля не нужны для прокси, потому что он вызовет метод исходного компонента, которые инициализируются.

  • Третье, что эта схема будет работать, только если методы суперкласса не объявлены окончательными.

В вашем случае, когда метод прокси называется вместо того, чтобы делегировать вызов оригинального боба он ведет себя как суперкласс, но с его полей осталось неинициализированным.

Поэтому я рекомендую следовать incomplete-co.de совет и вводя службу в качестве интерфейса, интерфейсы более подходят для проксирования, потому что прокси-структура не должна бороться с ограничениями подкласса.

P.S. Еще одно небольшое ограничение заключается в том, что в подклассе структура должна будет иметь стратегию для решения, какой унаследованный конструктор вызывать - в Spring/CGLIB предпочтительнее конструктор без параметров, поэтому вам придется создать его, если компилятор не сделал это автоматически.

Так что это некоторые практические причины (я не упоминаю о хороших принципах OOD здесь), почему весной мы вынуждены вводить услуги в качестве интерфейсов.