首页 > 解决方案 > Spring:ApplicationContextAware 有价值,但@Autowired 没有

问题描述

几个小时前我打开了一个问题,它被标记为重复,但它不是标记问题的重复,无论如何。

从那以后,我设法完成了一些事情,并解决了一些问题,所以这是我的问题:

我试图将一个spring bean @Autowire 放入另一个spring bean,但是我的问题是@Autowired 字段始终为空,尽管它们都是托管bean 并且它们自己可以正常工作。

我发现,您可以通过实现 ApplicationContextAware 接口来访问 bean 中的 ApplicationContext,我这样做了。它被调用并被赋予了正确的上下文。

这样,我可以在上下文中调用 getBean() ,它首先返回我想要 @Autowire 的 bean,这很不错,但这似乎是解决更大问题的一种解决方法。

你能帮我出什么问题吗?我尝试将@Autowiring 作为字段、方法和构造函数参数,但都没有。这些 bean 都是单例 bean,用作 HesianServiceExporter 的基础,以便从另一个 servlet 访问它们。

我想我在这里遗漏了一些关键的配置信息,但我不明白为什么字段注入不起作用,而同时接口实现却起作用。是不是我想要@Autowire 的bean 还没有准备好,所以它不能被注入?

正如你们中的一些人所要求的,这是我的代码。不知道它有什么帮助,但是:

@Service(Persistence.NAME)
public class PersistenceBean implements Persistence, ApplicationContextAware {

ApplicationContext context;

@Override
public User getUser() {
    User user = new User();
    user.setEmail(context.getBean(HelloWorld.class).getText());
    return user;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}

还有我的 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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context https://www.springframework.org/context/spring-context.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">


<context:annotation-config />
<context:component-scan base-package="hu.bme.sch.qpa" annotation-config="true"/>

<bean id="sessionFactory"
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource"
              ref="dataSource"/>
    <property name="packagesToScan"
              value="hu.bme.sch.qpa.global.entities"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">
                update
            </prop>
            <prop key="hibernate.dialect">
                org.hibernate.dialect.PostgreSQL95Dialect
            </prop>
        </props>
    </property>
</bean>

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url" value="jdbc:postgresql://localhost:5432/test"/>
    <property name="username" value="qpapp_server_user"/>
    <property name="password" value="root"/>
</bean>

<bean id="txManager"
      class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>

<bean id="persistenceExceptionTranslationPostProcessor" class=
        "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

</beans>

最后,我的 ApplicationInitializer 注释如下:

@ImportResource("/WEB-INF/app-core-servlet.xml")
@SpringBootApplication(scanBasePackages = "hu.bme.sch.qpa")
@EnableWebMvc
@Configuration
@EnableAutoConfiguration
public class CoreStarter extends SpringBootServletInitializer {

public static void main(String[] args) throws Exception {
    SpringApplication.run(CoreStarter.class, args);
}

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);

    }
}

这是HelloWorld bean,它(顾名思义)是一个非常简单的bean。它与 PersistenceBean 在同一个包中:

@Service(HelloWorld.NAME)
public class HelloWorldBean implements HelloWorld {

@Override
public String getText() {
    return "Hello World!!!! I'm remoted";
}
}

提前致谢。

标签: javaspringspring-boot

解决方案


好的,我明白了...男孩确实花了一些时间。

因此,事实证明,我描述的上下文不包括导致问题的上下文,但我不想用我的整个模块向线程发送垃圾邮件。

缺少的部分是我正在远程处理这些 bean,只是那些在自动装配上有问题的 bean(当时我不知道)。

我远程控制它们的方式是我为BeanDefinitionRegistryPostProcessor编写了一个实现。

这样做的问题是我在调用接口的函数后立即实例化了远程 bean,这意味着:在 Spring 通常会实例化我想要远程的 bean 之前 => 太早了。

我过早调用 getBean() 意味着在实例化 bean 时,AutowiredCapableBeanPostProcessor(或像这样的 sg.)没有在工厂列表中注册,我也无法控制它。

====================================TL;DR============ ======================

解决方案是在 Remote Exporter bean 中,当调用postProcessBeanDefinitionRegistry()函数时,我只是简单地保存了注册表,并实现了InstantiationAwareBeanPostProcessor并在调用postProcessAfterInstantiation()时进行了实际的远程处理=> 当 bean 被实例化时“正常”方式 => 将完成自动装配,并创建远程 bean。

很抱歉占用了你的时间,我真的很感激。


推荐阅读