Defining a Java class as <bean> with annotation

The solution to this <indexentry content="annotation-based DI:Java class, defining as with annotation">problem is to define <context:component-scan> in an application context (XML) file. When Spring reads this element, it will start scanning the beans from the Java package defined by its attribute, base-package. You can instruct Spring to treat the Java class as <bean> by declaring class-level annotation @Component. In short, defining annotation-based configuration is a two-step process, as follows:

  1. Scanning the package: This can be done by reading the base-package attribute of <context:component-scan>. Spring will start scanning for the classes in that Java package.
  2. Defining beans: Out of Java classes in the said Java package, Spring will consider as <bean> only those which have class-level annotation—@Component is defined. Let's change our example to incorporate this configuration:
//Updated Spring application context (XML) 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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<context:annotation-config />
<context:component-scan base-package="com.packet.spring.annotation.di"/>
</beans>


//Updated Professor class
@Component
public class Professor {
@Value(value="Nilang")
private String name;
//Constructor
public Professor() {
System.out.println("Object of Professor is created");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

//Updated Subject class
@Component
public class Subject {
private Professor professor;
public Subject() {
System.out.println("Object of Subject is created");
}
//Setter injection method
@Autowired
public void setProfessor(Professor professor) {
System.out.println("setting the professor through setter method injection ");
this.professor = professor;
}
public void taughtBy() {
if(professor !=null) {
System.out.println("This subject is taught by "+professor.getName());
}
}
}

Spring will consider Professor and Subject classes as a <bean> through @Component annotation, so there is no need to define them in an application context (XML) file. You can inject the value for primitive properties with the @Value annotation. In the preceding example, we have set the value of the name property of the Professor bean with the @Value annotation directly at property level.  Alternatively, you can inject the primitive values to property at a setter method level, as per the following snippet:

  @Autowired 
public void setName(@Value("Komal") String name) {
this.name = name;
}

You need to set the @Autowired annotation on the setter method and inject the value of that property with the @Value annotation. When you run this code, you will get the desired output, similar to what we got with pure XML-based configuration.

The element <context:component-scan> does all the things that <context:annotation-config /> can. If you keep both of them in application context (XML) files, there is no harm; but then <context:component-scan> is just suffice, and you can omit <context:annotation-config />.

You can pass multiple packages to <context:component-scan> as comma separated string to its base-package attribute. What's more, you can define various filters (include and exclude) on <context:component-scan> to scan specific subpackages and eliminate others. 

Configuration can be done through annotation or with XML, or by mixing both of them. The DI configured with XML is executed after annotation-based DI. So it's possible that XML-based configuration overrides the annotation-based configuration for a bean's property (setter) wiring.

So far, we have learned about @Autowired, @Component, and @Value annotations. We will see a few more annotations that are used frequently in DI as follows:

Annotation—@Required: The  @Required annotation can be applied to a bean's setter method. It indicates that Spring must populate the value of a property from the setter method either through autowire or explicit setting of a property value. In other words, the bean property must be populated at configuration time. If this is not fulfilled, the container throws an exception.

As an alternative, you can use the @Autowired annotation with the attribute required—@Autowired (required=false). When you set it to false, Spring will ignore this property for autowire if the suitable bean is not available.

Annotation—@Qualifier: By default, the @Autowired annotation works with the type of bean's class. When there is more than one bean with the same type (class) configured, Spring will show an error when you try to autowire it with a property. In this case, you need to use the @Qualifier annotation. It will help to wire the specific bean out of available beans of the same type. You need to specify @Qualifier along with @Autowired to remove the confusion by declaring an exact bean. Let's understand this by looking at the following example:

public class Professor {
private String name;
//Constructor
public Professor() {
System.out.println("Object of Professor is created");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

@Component
public class Subject {
private Professor professor;
public Subject() {
System.out.println("Object of Subject is created");
}
//Setter injection method
@Autowired
@Qualifier("professor1")
public void setProfessor(Professor professor) {
System.out.println("setting the professor through setter method injection ");
this.professor = professor;
}
public void taughtBy() {
if(professor !=null) {
System.out.println("This subject is taught by "+professor.getName());
}
}
}

//Updated Application context (XML) file.

<context:component-scan base-package="com.packet.spring.annotation.di"/>
<bean id="professor1" class="com.packet.spring.annotation.di.Professor">
<property name="name" value="Ramesh" />
</bean>
<bean id="professor2" class="com.packet.spring.annotation.di.Professor">
<property name="name" value="Nilang" />
</bean>

In the previous code, the @Qualifier annotation is added along with @Autowired, with the value professor1 in the Subject class. This indicates to Spring to autowire the professor bean with id = professor1. In the Spring configuration file, we have defined two beans of the Professor type with different ID values. In absence of the @Qualifier annotation, Spring throws an error. The previous code produces output like the following:

...
org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [application-context.xml]
Object of Professor is created
Object of Subject is created
Object of Professor is created
setting the professor through setter method injection
Object of Professor is created
This subject is taught by Ramesh

Now Spring will inject the object of a <indexentry content="annotation-based DI:Java class, defining as with annotation">bean with similar ID as the value of the @Qualifier annotation. In previous cases, the object of bean with id = professor1 is injected into Subject.

You might be surprised that we have used XML-based configuration here. It's quite possible to define this with annotation in a Java class, but it's advisable to use XML configuration in case you need to define multiple beans of the same type with different ID.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.95.245