Understanding spring @Configuration class
Migrating XML to @Configuration
It is possible to migrate the xml to a @Configuration
in a few steps:
Create a
@Configuration
annotated class:@Configuration
public class MyApplicationContext {
}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
}
}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 {
...
}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);
}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.
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:
- Typos -
@Configuration
classes are compiled and typos just won't allow compilations - 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
- Easier to navigate in IDE - between constructors of beans to understand the dependency tree.
- 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:
- Abuse - Code is easier to abuse than XMLs
- 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 theSpringApplication.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
- Register the class with an
AnnotationConfigApplicationContext
instance. - Specify the class as a
<bean>
in XML configuration with the corresponding XML-enabledApplicationContext
. - 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 andbeans {...}
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
How to Set Icon in a Column of Jtable
How to Make Anonymous Inner Classes in Java Static
Java Ternary Without Assignment
What Is the Easiest Way to Ignore a JPA Field During Persistence
How to Use Multiple Scanner Objects on System.In
Why Do I Get "Non-Static Variable This Cannot Be Referenced from a Static Context"
How to Read Request.Getinputstream() Multiple Times
Consider Defining a Bean of Type 'Package' in Your Configuration [Spring-Boot]
How to Write a Key Listener to Track All Keystrokes in Java
Java - Reading, Manipulating and Writing Wav Files
Do Any Jvm's Jit Compilers Generate Code That Uses Vectorized Floating Point Instructions
Java Inputstream Blocking Read
How to Add a Utf-8 Bom in Java
Converting an Int to a Binary String Representation in Java
Differencebetween 'Super' and 'Extends' in Java Generics