Spring Dependency Injection Using Java Container Configuration

I'm new to Java and Spring, coming from the C # and .NET world, so carry with me - what I'm trying to do might be uncomfortable ...

I am trying to set up Spring DI using Java configuration and annotations rather than XML configuration, however I have several problems. This is for a standalone app, not a web app. I have worked through the springsource documentation and as far as I can tell my most basic configuration should be correct ... but it is not. Check out the below code:

Java Configuration Annotated Class:

package birdalerter.common;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import birdalerter.process.ISightingsProcessor;
import birdalerter.process.SightingsProcessor;

@Configuration
@ComponentScan({"birdalerter.process", "birdalerter.common"})
public class AppConfig {
    @Bean
    @Scope("prototype")
    public ISightingsProcessor sightingsProcessor(){
        return new SightingsProcessor();
    }
}

      

Configure a component that implements the ISightingsProcessor interface:

package birdalerter.process;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import org.springframework.stereotype.Component;

import birdalerter.domainobjects.IBirdSighting;
@Component
public class SightingsProcessor implements ISightingsProcessor{

    private LinkedBlockingQueue<IBirdSighting> queue;
    private List<ISightingVisitor> sightingVisitors = new ArrayList<ISightingVisitor>();

    public SightingsProcessor(){
    }

    ...
}

      

Configure Factory Component:

package birdalerter.process;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class ProcessorFactory {
    private ISightingsProcessor sightingsProcessor;

    @Autowired
    @Required
    private void setSightingsProcessor(ISightingsProcessor sightingsProcessor){
        this.sightingsProcessor = sightingsProcessor;
    }

    public ISightingsProcessor getSightingsProcessor(){
        return this.sightingsProcessor;
    }
}

      

Connect AnnotationConfigApplicationContext and check:

@Test
public void testProcessingDI(){
    @SuppressWarnings("resource")
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(AppConfig.class);
    context.refresh();


    ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();
    System.out.println(processor);
    Assert.assertTrue(processor != null);
}

      

The SightingsProcessor is not injected by the setter and the assert does not work because the returned object is null. I hope I missed something very obvious.

Thanks in advance.

Edited in response to Meriton:

Thanks for the answer Meriton.

Why doesn't Spring know about the newly created object? Spring does not maintain dependencies throughout the entire lifecycle of an application and adds when needed when new objects are created that are configured as beans?

I don't want to use directly context.getBean(ISightingsProcessor.class)

, if I can help it be honest, I would like the dependency to be injected in the setter method without manual intervention - it just seems cleaner.

I use ProcessorFactory

since interface ISightingsProcessor

extends Runnable

- the implementation object must run as a thread. The application will configure itself to have n * threads, with each one running during the loop. I don't think it is possible (I may be wrong, please report this) to have annotations @Autowired

in method declarations, so I use Factory to supply a new instance of a nested ISightingsProcessor

concrete class.

Yes, I just looked at the annotation @Scope

- you are right, you need to go to the declaration AppConfig

@Bean

(which I made in this edit), thanks for that.

+3


source to share


1 answer


ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();

      

This calls the ProcessorFactory constructor and then the getter of the instance created by the constructor. Spring cannot know about this newly created object and therefore does not inject its dependencies. You have to ask Spring for a ProcessorFactory, for example with

ProcessorFactory pf = context.getBean(ProcessorFactory.class);
ISightingsProcessor processor = pf.getSightingsProcessor();

      

However, I don't know why you need the ProcessorFactory class. You can just get ISightingsProcessor directly:



ISightingsProcessor processor = context.getBean(ISightingsProcessor.class);

      

In addition, Java Configuration and Bean Scanning are independent ways to declare beans. Currently, you therefore declare ISightingsProcessor twice: once with the @Bean -annotated factory method and once with the component validation and @Component annotation in the class. Doing any of this will. In fact, doing both can cause one bean definition to override the other.

Oh, and the annotation @Scope

is for bean definitions (the ones you comment out with @Bean

or @Component

). It will probably be ignored at injection points ( @Autowired

).

0


source







All Articles