【问题标题】:Autowiring a DAO into a Service将 DAO 自动装配到服务中
【发布时间】:2014-11-08 10:57:36
【问题描述】:

我正在使用 Spring 并尝试将 DAO 自动连接(使用注释)到服务中,然后将其连接到控制器中。有

@Autowired
Movie movieDao;

它自己不起作用,因为我认为 new 方法被调用,因此 DAO 不是由 Spring 管理的。以下确实有效,但如果我必须将该上下文配置复制并粘贴到每个方法中,它看起来会很混乱

    @Autowired
    MovieDao movieDao;

    @Override
    public List<Movie> findAll() {
        GenericXmlApplicationContext context = new GenericXmlApplicationContext();
        context.load("classpath:app-context.xml");
        context.refresh();
        MovieDao movieDao = (MovieDao) context.getBean("movieDao", MovieDao.class);
        return movieDao.findAll();
    }

此代码在我的服务类中的位置。有没有更优雅的方法来确保我的 DAO 正确初始化,而不是将该方法的前 4 行复制并粘贴到每个 Service 方法中?

[编辑] 包含上述代码的类是一个名为 MovieServiceImpl 的类,它本质上对应于this page 中描述的架构中的 DataServicesImpl 类。 (我将添加该架构的摘要/描述以及我即将尝试做的事情)。这是代码:http://pastebin.com/EiTC3bkj

【问题讨论】:

  • 你能给我们更多关于这个包含movieDao字段的类的上下文吗?一般来说,我推荐构造函数注入而不是字段注入,主要是因为这个原因。
  • 谢谢,我在帖子中添加了一些内容,并会尽快尝试更新。自动装配构造函数听起来可能会解决问题 - 我会试一试,再次感谢。
  • 我认为这里的主要问题是每次调用此方法时您都在创建一个新的 applicationContext 。像这样使用时,Spring 无法注入依赖项。这是一个网络应用程序吗?如果是这样,您应该使用 ContextLoaderListener 设置上下文,例如 this 。 contextLoaderListener的原因描述here
  • 是的,它是一个网络应用程序。感谢您的建议和链接。
  • 为什么要为每个 findAll() 调用加载 spring 上下文? @Autowired 已经注入了这个字段

标签: java spring service dao autowired


【解决方案1】:

我认为主要问题是您想直接实例化您的服务(使用new)而不是使用 Spring:

MovieService movieService = new MovieServiceImpl();

当您执行此操作时,您的 MovieServiceImpl 实例已构建但未初始化(@Autowired MovieDao 字段为 null)。

如果你想通过字段注入正确地实例化你的对象,你需要使用 Spring。正如documentationthis example 中所述,您可以自动检测所有带注释的bean,并使用组件扫描在您的上下文中初始化它们。

示例

在您的情况下,使用注释 on@Component@Service 等)和 in@Autowired@Inject 等)您的 bean ,您的项目可能如下所示:

弹簧配置app-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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Use component scanning to auto-discover your beans (by annotation) and initialize them -->
    <context:component-scan base-package="com.se325.a01" />

    <!-- No need to declare manually your beans, because beans are auto-discovered thanks to <context:component-scan/> -->

</beans>

你的应用程序的入口点App.java

package com.se325.a01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.se325.a01.model.Movie;
import com.se325.a01.service.MovieService;

public class App {
    public static void main(String[] args) {
        // Let's create the Spring context based on your app-context.xml
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});
        // Now your context is ready. All beans are initialised.
        // You can retrieve and use your MovieService
        MovieService movieService = context.getBean("movieService");

        Movie matrixMovie = new Movie("Matrix");
        movieService.create(matrixMovie);
    }
}

实际上,在使用 Spring 时,了解上下文是如何初始化的非常重要。在上面的例子中,可以总结为:

  1. 您的入口点App#main 被调用。
  2. 配置app-context.xmlClassPathXmlApplicationContext加载。
  3. 感谢&lt;context:component-scan base-package="com.se325.a01" /&gt; 行扫描包com.se325.a01。所有带注释的 bean(@Component@Service 等)都已构建但尚未初始化。
  4. 当所有 bean 都构建完成后,Spring 通过注入依赖项来初始化它们。在示例中,标记依赖关系的 @Autowired 注释也通过 &lt;context:component-scan ... \&gt; 行被发现。
  5. 上下文已准备好所有 bean :)

注意事项

所有这些答案都说明了如何使用组件扫描和注释在 main 入口点中使用 Spring。但是,如果您正在开发服务器应用程序,则入口点是 WEB-INF/web.xml

正如@chrylis 所说,字段注入很容易出错。 更喜欢使用基于构造函数的注入

【讨论】:

    猜你喜欢
    • 2012-06-18
    • 2011-04-04
    • 2018-01-27
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多