Till now, we have seen XML Based configuration. Now in this article, we will learn how to use the annotation-based configuration in Spring Framework.
Spring 2.5 came in 2007, introduced the Annotation-based configuration. It helps in injecting the dependencies. It has method-level annotations i.e the annotation is applied on the bean property of the setter method.
The following is the list of annotations that we will be using in the coming articles and also you should be aware of which annotation does what.
Annotation |
Description |
Applied on |
@Required | It is applied to bean property setter methods. Fails the configuration if dependency is not injected. | Constructor, Field & Method |
@Autowired | It autowired the appropriate bean into class members. | Constructor, Field & Method |
@Qualifier | It filters what beans should be used to @Autowire a field. | Constructor, Field & Method |
@Bean | It says that the method produces beans that are managed by a container. | Method |
@Configuration | It makes a class a source of beans definition. | Class |
@ComponentScan | It tells spring to scan the package for configuration. | Class |
@Component | It makes a class into the bean and will be auto-detected. | Class |
@Service | It is a specialized version of @Component. | Class |
@Controller | It is a specialized version of @Component to annotate Controllers while developing web-based apps. | Class |
@Repository | It is used to annotate Data Access Object Class. | Class |
@Lazy | It makes @Bean and @Component be initialized on demand rather than eagerly. | Class & Method |
@Value | It indicates a default value for any field or parameter. | Constructor, Field & Method |
To enable annotation wiring in Spring Container, First, we have to enable the annotation-based configuration inside the configuration file like the following.
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- To activate annotation in spring --> <context:annotation-config /> </beans>
There is also one more way, in which we can activate the annotation-based configuration by specifying the bean definition of RequiredAnnotationBeanPostProcessor class in the config file.
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- To activate the annotation in spring --> <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"></bean> </beans>
Now, we will take an example of how to implement this annotation in the spring Framework.
Example for @Required Annotation
@Required: It is applied to bean property setter methods. It fails the configuration if dependency is not injected.
Create a Spring Project Go to File> New > Other > Search maven > Select Maven Project > Next > Search Filter org.apache.maven.archetypes/webapp > Next > Enter Group Id & Archetype id > Finish.
In this example, we will be creating an Interface called Number, and two classes that will implement the Number Interface are Roman Number and Real Number. Following are the files that we will create
- pom.xml – (because it’s a maven project)
- Number.java
- RealNumbers.java & RomanNumber.java
- App.java
- beans.xml – configuration file.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>New</groupId> <artifactId>DependencyInjection</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>DependencyInjection Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.4</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.4</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>DependencyInjection</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
Number.java
- In this interface, we have one method typeOfNumbers().
package com.codedec.annotation; public interface Numbers { void typeOfNumber(); }
RomanNumber.java
The @Required annotation is applied on the setter method means it will inject the dependencies.
package com.codedec.annotation; import org.springframework.beans.factory.annotation.Required; public class RomanNumber implements Numbers { private String numberType; @Required public void setNumberType(String numberType) { this.numberType = numberType; } @Override public void typeOfNumber() { System.out.println("Number in Roman Form :"+numberType); } }
RealNumber.java
The @Required annotation is applied on the setter method means it will inject the dependencies.
package com.codedec.annotation; import org.springframework.beans.factory.annotation.Required; public class RealNumber implements Numbers { private String numberType; @Required public void setNumberType(String numberType) { this.numberType = numberType; } @Override public void typeOfNumber() { System.out.println("Number in Real Form: "+numberType); } }
beans.xml
- In this XML file, we have used the RequiredAnnotationBeanPostProcessor class to enable annotation-based configuration.
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"></bean> <bean id="realNum" class="com.codedec.annotation.RealNumber"> <property name="numberType" value="1"></property> </bean> <bean id="romanNum" class="com.codedec.annotation.RomanNumber"> <property name="numberType" value="I"></property> </bean> </beans>
App.java
- In this class, we get the bean definition from the context and will call the method typeOfNumber().
package com.codedec.annotation; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Numbers numbers = context.getBean("realNum", Numbers.class); numbers.typeOfNumber(); Numbers numbers1 = context.getBean("romanNum", Numbers.class); numbers1.typeOfNumber(); } }
Output
Number in Real Form: 1 Number in Roman Form :I
Thus, we get the above output by using the annotation-based configuration.
Note: If you don’t supply dependencies from the beans.xml file then it will throw an exception BeanInitializationException
Modify the above beans.xml file. Here, On-Line no:13, we are not supplying dependencies. Run the App.java once again.
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"></bean> <bean id="realNum" class="com.codedec.annotation.RealNumber"> </bean> <bean id="romanNum" class="com.codedec.annotation.RomanNumber"> <property name="numberType" value="I"></property> </bean> </beans>
Output
Caused by: org.springframework.beans.factory.BeanInitializationException: Property 'numberType' is required for bean 'realNum' at org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.postProcessPropertyValues(RequiredAnnotationBeanPostProcessor.java:158) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1418) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
Thus, If we apply @Required annotation and if you don’t provide the dependencies it would throw the above exception.
Thus, this was all about @Required annotation with a simple and clear example. In the next article, we will understand @Autowire annotation using a simple example.