我的一项服务中的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被正确注入。
由于
答案 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
}
在这种情况下,你总是知道要注射什么。