【问题标题】:Spring beans created but not autowiredSpring bean 创建但未自动装配
【发布时间】:2015-04-22 13:31:15
【问题描述】:

我知道有很多类似的问题。我看了很多,但问题仍然存在。

我有一个已创建但未自动装配的服务。没有(!)手动启动,无论是在项目中还是在测试中(如this question

Tomcat 输出显示,两个 bean 都已找到并创建。至少第一个服务没有注入它应该在的地方。我不知道第二个。

服务(接口):

public interface SchoolService {
  public School getSchool(String id);
}

服务(实施):

@Service
@Transactional
public class SchoolServiceImpl implements SchoolService {

  @Autowired
  private SchoolDAO schoolDAO;

  public School getSchool(String id) {
    //database things
    return school;
  }

}

它在哪里被“调用”

public class SchoolMenu implements Serializable {

  @Autowired
  private SchoolService schoolService;

  public SchoolMenu () {
    //here schoolService is null
    School school = schoolService.getSchool("id");
  }

}

应用程序上下文.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">


    <bean id="SchoolServiceImpl" class="content_management.School.service.SchoolServiceImpl"/>
    <bean id="SchoolDAOImpl" class="content_management.School.dao.SchoolDAOImpl"/>
</beans>

Tomcat 输出:

org.springframework.beans.factory.support.DefaultListableBeanFactory: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@57003970: defining beans [SchoolServiceImpl,SchoolDAOImpl]; root of factory hierarchy
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating shared instance of singleton bean 'SchoolServiceImpl'
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating instance of bean 'SchoolServiceImpl'
org.springframework.beans.factory.support.DefaultListableBeanFactory: Eagerly caching bean 'SchoolServiceImpl' to allow for resolving potential circular references
org.springframework.beans.factory.support.DefaultListableBeanFactory: Finished creating instance of bean 'SchoolServiceImpl'
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating shared instance of singleton bean 'SchoolDAOImpl'
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating instance of bean 'SchoolDAOImpl'
org.springframework.beans.factory.support.DefaultListableBeanFactory: Eagerly caching bean 'SchoolDAOImpl' to allow for resolving potential circular references
org.springframework.beans.factory.support.DefaultListableBeanFactory: Finished creating instance of bean 'SchoolDAOImpl'

我的错误在哪里?

【问题讨论】:

  • 在 Spring 有机会做任何事情之前,您正在尝试使用构造函数中的字段。

标签: java spring dependency-injection


【解决方案1】:

为了@Autowired 工作,SchoolMenu 还必须是一个 Spring bean。如果不是,您可以从应用程序上下文中获取schoolService。像这样的

ApplicationContext appContext = new ClassPathXmlApplicationContext("application-context.xml");
SchoolService schoolService = (SchoolService) appContext.getBean(SchoolService.class);

【讨论】:

    【解决方案2】:

    你在SchoolMenu的构造函数中访问schoolService

    public SchoolMenu () {
        //here schoolService is null
        School school = schoolService.getSchool("id");
    }
    

    此时,schoolService 尚未注入。不可能——在构造函数被调用之前什么都不会发生。

    您可以在 bean 初始化后声明要调用的方法,方法是使用 javax.annotation.PostConstruct 注释对其进行注释。在该方法中执行需要注入依赖项的操作,而不是在构造函数中。

    (还有其他几种实现方式,比如实现InitializingBean接口,但是这些都有些过时了)

    例子:

    public SchoolMenu () {
    }
    
    @PostConstruct
    public void init() {
        // schoolService is NOT null here
        School school = schoolService.getSchool("id");
    }
    

    【讨论】:

    • 更可取的是首先使用构造函数注入。
    • 构造函数注入有很多优点,但有一个很大的缺点:它无法解决依赖关系中的循环(无法初始化使用构造函数注入相互引用的两个服务 - 至少其中一个需要 setter 或字段注射)
    • 是的,但是 (1) 据我所知,情况并非如此,并且 (2) 循环依赖几乎总是设计问题的迹象。
    • 引用 (2)?我从未遇到过构造函数注入提供的依赖项不是每个 CDI “构造”的依赖项的情况。
    • 你是对的初始化,构造函数参数已完全初始化。我想这就是为什么如果这不是必需的,您会比预期更频繁地遇到循环依赖错误。
    【解决方案3】:

    您可以通过将此配置添加到应用程序上下文中来使用组件扫描,而不是在 xml 中定义 bean,Spring 将自动为您扫描和检测 bean。

    <context:component-scan base-package="content_management.School" />
    

    您还需要添加上下文命名空间,以便 application-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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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-4.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
     <context:component-scan base-package="content_management.School" />
    
     </beans>
    

    【讨论】:

    • 我添加了命名空间和扫描 sn-p,但我得到了XmlBeanDefinitionStoreException: Line 26 in XML document from ServletContext resource [/WEB-INF/applicationContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 26; columnNumber: 78; cvc-complex-type.2.4.c:
    • 你能显示你的 applicationContext.xml 的第 26 行,甚至更好地显示整个文件吗?好像语法错误
    • 第 26 行是 &lt;context: ... 行,我只是在两者之间裁剪了一些 cmets
    • 对不起,我错过了上下文的 schemaLocation。我已经更新了我的答案。还要验证基础包是否正确。它必须指向同时包含 SchoolDAO 和 SchoolService 的包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2016-09-27
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    相关资源
    最近更新 更多