Understanding Spring @Configuration Class

Understanding spring @Configuration class

Migrating XML to @Configuration

It is possible to migrate the xml to a @Configuration in a few steps:

  1. Create a @Configuration annotated class:

    @Configuration
    public class MyApplicationContext {

    }
  2. For each <bean> tag create a method annotated with @Bean:

    @Configuration
    public class MyApplicationContext {

    @Bean(name = "someBean")
    public SomeClass getSomeClass() {
    return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
    }

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass() {
    return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
    }
    }
  3. In order to import beanFromSomewhereElse we need to import it's definition. It can be defined in an XML and the we'll use @ImportResource:

    @ImportResource("another-application-context.xml")
    @Configuration
    public class MyApplicationContext {
    ...
    }

    If the bean is defined in another @Configuration class we can use the @Import annotation:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
    ...
    }
  4. After we imported other XMLs or @Configuration classes, we can use the beans they declare in our context by declaring a private member to the @Configuration class as follows:

    @Autowired
    @Qualifier(value = "beanFromSomewhereElse")
    private final StrangeBean beanFromSomewhereElse;

    Or use it directly as parameter in the method which defines the bean that depends on this beanFromSomewhereElse using @Qualifier as follows:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
    return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
  5. Importing properties is very similar to importing bean from another xml or @Configuration class. Instead of using @Qualifier we'll use @Value with properties as follows:

    @Autowired
    @Value("${some.interesting.property}")
    private final String someInterestingProperty;

    This can be used with SpEL expressions as well.

  6. In order to allow spring to treat such classes as beans containers we need to mark this in our main xml by putting this tag in the context:

    <context:annotation-config/>

    You can now import @Configuration classes exactly the same as you would create a simple bean:

    <bean class="some.package.MyApplicationContext"/>

    There are ways to avoid spring XMLs altogether but they are not in the scope of this answer. You can find out one of these options in my blog post on which I'm basing my answer.


The advantages and disadvantages of using this method

Basically I find this method of declaring beans much more comfortable than using XMLs due to a few advantages I see:

  1. Typos - @Configuration classes are compiled and typos just won't allow compilations
  2. Fail fast (compile time) - If you forget to inject a bean you'll fail on compile time and not on run-time as with XMLs
  3. Easier to navigate in IDE - between constructors of beans to understand the dependency tree.
  4. Possible to easily debug configuration startup

The disadvantages are not many as I see them but there are a few which I could think of:

  1. Abuse - Code is easier to abuse than XMLs
  2. With XMLs you can define dependencies based on classes that are not available during compile time but are provided during run-time. With @Configuration classes you must have the classes available at compile time. Usually that's not an issue, but there are cases it may be.

Bottom line: It is perfectly fine to combine XMLs, @Configuration and annotations in your application context. Spring doesn't care about the method a bean was declared with.

What is the difference between @Configuration and @Component in Spring?

@Configuration Indicates that a class declares one or more @Bean
methods and may be processed by the Spring container to generate bean
definitions and service requests for those beans at runtime

@Component Indicates that an annotated class is a "component". Such
classes are considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.

@Configuration is meta-annotated with @Component, therefore
@Configuration classes are candidates for component scanning

You can see more here:

http://docs.spring.io/spring-framework/docs/4.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html

A @Configuration is also a @Component, but a @Component cannot act like a @Configuration.

Why Spring Boot Application class needs to have @Configuration annotation?

You understood it right.

@Configuration

@Configuration is an analog for xml file. Such classes are sources of bean definitions by defining methods with the @Bean annotation.

@Configuration is:

  • not required, if you already pass the annotated class in the sources parameter when calling the SpringApplication.run() method;
  • required, when you don't pass the annotated class explicitly, but it's in the package that's specified in the @ComponentScan annotation of your main configuration class.

For readability, classes that are even explicitly passed as sources may anyway be annotated with @Configuration - just to show the intentions more clearly.

Your current class is not really source of bean definitions, because it doesn't have any, but if you had @Bean annotated methods, Spring would see them.

@EnableAutoConfiguration

Can be used with or without @Configuration. It tells Spring to setup some basic infrastructure judging by what you have in the classpath. It's done by invoking a so called import class that's derived from the value of the @Import annotation that @EnableAutoConfiguration includes. Only one class should be annotated with @EnableAutoConfiguration, duplicating it doesn't do anything.

This answer may also be helpful to understand the Spring Boot initialization process: Which piece of code in Spring Boot actually registers dispatcher servlet for SpringMVC?

How do I use a configuration class to configure properties for my application in Spring Boot?

Here lies the problem

@Autowired
public ---> static <---- Config configuration;

Spring can't autowire static fields. You need to remove static from the autowired field

Then you would not be able to use this field inside the main method because main is declared as static. The solution here is the following. You need to retrieve the bean after the application context is loaded programmatically without the use of @Autowired

@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {

ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);

Config configuration = ctx.getBean(Config.class);

String fullname = configuration.name + " " + configuration.surname + " " + configuration.age;
System.out.println(fullname);
}

}

When is a spring @configuration class executed?

A @Configuration annotated class is just that, a class annotated with the @Configuration annotation. It does nothing on its own.

You need something to evaluate and process the class. This is done through bootstrapping. You have three options

  1. Register the class with an AnnotationConfigApplicationContext instance.
  2. Specify the class as a <bean> in XML configuration with the corresponding XML-enabled ApplicationContext.
  3. Place the class in a package that is component-scanned.

These options are detailed in the javadoc and, in a lot more detail, in the Spring IOC documentation.

Beans you declare in the @Configuration class live as long as their corresponding scope. Your testBean bean has singleton scope and therefore lives as long as the containing ApplicationContext.

Is @Configuration mandatory?

I think you are right that Spring will load the config class and also create instances but will not treat the instances as beans. Meaning: other service which uses the DemoService will create several instances for each usage and not as a singleton which would be the default scope when created as a bean.

public class DemoServiceUsage {

DemoService demoService;

public DemoServiceUsage(DemoService demoService) {
this.demoService = demoService;
}
}

public class NotAnnotatedConfiguration {
@Bean
public DemoService demoService() {
DemoService demoService = new DemoService();
System.out.println("demoService " + demoService.hashCode());
return demoService;
}

@Bean
public DemoServiceUsage demoServiceUsage1() {
return new DemoServiceUsage(demoService());
}

@Bean
public DemoServiceUsage demoServiceUsage2() {
return new DemoServiceUsage(demoService());
}
}

@Configuration
@Import({
NotAnnotatedConfiguration.class
})
public class ApplicationConfig {
}

@ContextConfiguration(classes = ApplicationConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class NotAnnotatedConfigurationTest {

@Autowired
DemoServiceUsage demoServiceUsage1;

@Autowired
DemoServiceUsage demoServiceUsage2;

@Test
public void load() {
assertNotNull(this.demoServiceUsage1);
assertNotNull(this.demoServiceUsage2);
}
}

Here you will see that you get multiple demoService outputs with different hashCodes. If demoService would be a bean we should only see one instance as it should have a singleton scope.

Will declaring @configuration on a class make it a spring bean?

Yes. @Configuration annotated class will register as a spring bean. Check the following snippet from documentation. The primary purpose of @configuration to act as a bean source.

When @Configuration classes are provided as input, the @Configuration
class itself is registered as a bean definition, and all declared
@Bean methods within the class are also registered as bean
definitions.

[1] https://docs.spring.io/spring/docs/4.3.25.RELEASE/spring-framework-reference/htmlsingle/#beans-java-basic-concepts

Spring Autowiring when using Configuration Class

I think what you want to achieve is the injection of a HelloWorld2 instance into the method that creates the HelloWorld @Bean?

This should do it:

@Configuration
public class Config {
@Bean
public HelloWorld helloWorld(HelloWorld2 helloWorld2){
HelloWorld a = new HelloWorld(helloWorld2);
a.setAttr1("Demo Attr1");
return a;

}

@Bean
public HelloWorld2 helloWorld2(){
HelloWorld2 a = new HelloWorld2();
a.setAttr2("Demo Attr2");
return a;
}
}

This might be a duplication of these questions:

  • Understanding Spring Autowired usage
  • Converting Spring XML file to Spring configuration class

How many ways are there to configure the Spring framework? What are the differences between them technically? (Not pros or cons..)

To avoid confusion, we should understand, that configuration definition and bean definition are two different things. There are three ways to define configuration, available in Spring 4 by default:

  • xml-based configuration, when you describe configuration in xml file;
  • java-based configuration, when configuration is Java class, marked with specific annotations;
  • groovy-based configuration, when configuration is file with Groovy code;

And there are two ways to add bean definitions into application:

  • configuration inside bean definition, when you add beans manually by declaration right in configuration.

    In this case definition will be based on configuration type. For xml-config it will be <bean/> tag, for java-based config - method with @Bean annotation and beans {...} construction for Groovy.

  • annotation based bean definition, when you mark bean classes with specific annotations (like @Component, @Service, @Controller etc). This type of config uses classpath scanning.

In this case you have to specify directive for scanning classpath. For xml-config it will be <context:component-scan base-package="..."/>, for java-config - @ComponentScan annotation, for Groovy ctx.'component-scan'(...) invocation.

As you see, you can use configurations and bean definitions in different combinations.

Note, that if you use xml based config, you can choose approach to drive dependency injection: manually in xml, or by using annotations (@Autowire, @Required etc). In late case you have to define <context:annotation-config/>. But do not confuse bean definition and dependency injection control.

Now based on this point of view lets try to answer your questions:

Why is the (so-called) Annotation Based Configuration actually using
ClassPathXmlApplicationContext but not
AnnotationConfigApplicationContext above?

Book's author mixed up concepts. Actually, this is a xml-based configuration with annotation-based bean definition.

The Java Based Configuration explained in the book seems like what
should be called Annotation Based Configuration.?

You're right - Java based configuration really actively uses annotations, and could be called Annotation based. But annotation is a part of Java. In addition this is a traditional term, specified in documentation.

How many ways are there to configure Spring framework?

So, by default, we have three ways to describe configuration, and two ways to define beans. That turns six ways to configure Spring framework(by default). But, of course, all of this ways can be used in combination with each other.



Related Topics



Leave a reply



Submit