0
votes

I opened a question some hrs ago, which got marked as a duplicate, however it was not a duplicate of the marked question, whatever.

Since then, I managed to get some things done, and work stuff out, so here is my question:

I was trying to @Autowire a spring bean into another one, however my problem was that the @Autowired field was always null, depsite of the fact that they were both managed beans and worked correctly by themselves.

I found out, that you can reach the ApplicationContext in a bean by implementing the ApplicationContextAware interface, which I did. It was called and the right context was given to it.

This way, I can call getBean() on the context, which returns the bean I wanted to @Autowire in the first place, which is a yaay, but this seems like a workaround for a bigger problem.

Can you help me what might be wrong? I tried @Autowiring both as field, method and constructor parameter, none worked. These beans are both singleton beans and are used as basis for HesianServiceExporter, in order to reach them from another servlet.

I guess is I'm missing some crucial config information here, but I can't see why a field injection would not work, while at the same time an interface implementation does. Is it a case, where the bean which I want to @Autowire is not ready yet, so it can't be injected?

As some of you requested, here is my code. Don't know how it helps, but:

@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;
    }
}

And my 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>

And lastly, my ApplicationInitializer is annotated like this:

@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);

    }
}

And here is HelloWorld bean, which is (what the name would suggest) a really simple bean. It's in the same package as PersistenceBean:

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

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

Thanks in advance.

1
Please show your code - Ivan
edited, so you can see my code - László Stahorszki
Could you please add code for HelloWorld with package to which that class belongs? - Ivan
Here you go, I didn't include it, because it's as simple of a bean as it gets - László Stahorszki
Base package in your context.xml in question is different from one mentioned in your last comment. Could you please double check that? - Ivan

1 Answers

0
votes

Okay, I got it... Boy did it took some time.

So, as it turns out, the context I described didn't include the one that caused the problem, but I didn't want to spam the thread with my whole module.

The missing part is that I'm remoting these beans, just and only the ones that have trouble with Autowiring (I didn't know that at the time).

The way I remoted them was I wrote an implementation to the BeanDefinitionRegistryPostProcessor.

The problem with this was that I instantiated the remote beans as soon as the function of the interface got invoked, which means: before Spring normally would instantiate the beans I want to remote => too early.

Me calling the getBean() too early meant that at the of instantiating the bean, the AutowiredCapableBeanPostProcessor (or sg. like this) was not registered in the list of factories and I didn't have control of it either.

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

The solution was that in the Remote Exporter bean, when the postProcessBeanDefinitionRegistry() function got invoked, I just simply saved the Registry, and implemented the InstantiationAwareBeanPostProcessor and did the actual remoting when postProcessAfterInstantiation() got invoked => When the bean has been instantiated the "normal" way => the Autowiring will be done, as well as the remote bean will be created.

Sorry for stealing your time, I really appreciate it.