Saturday, 20 July 2019

Annotations Based Configuration in Spring

JSR-250 Annotations in the Spring

Spring also provides support for JSR-250 annotations which include @PostConstruct, @PreDestroy and @Resource annotations.

@PostContruct – This annotation is applied to a method to indicate that it should be invoked after all dependency injection is complete.
@PreDestroy – This is applied to a method to indicate that it should be invoked before the bean is removed from the Spring context, i.e. just before it’s destroyed.
@Resource – This duplicates the functionality of @Autowired combined with @Qualifier as you get the additional benefit of being able to name which bean you’re injecting, without the need for two annotations.

@Required

The @Required annotation applies to bean property setter methods, as in the following example:

package com.searchendeca.application;

import org.springframework.beans.factory.annotation.Required;

public class HelloWorld {

private GreetingName greet;

public GreetingName getGreet() {
return greet;
}
@Required
public void setGreet(GreetingName greet) {
this.greet = greet;
}

private String mMessage;

public String getMessage() {
return mMessage;
}

public void setMessage(String pMessage) {
this.mMessage = pMessage;
}

}

<bean id="helloWorldService"
class="com.searchendeca.application.HelloWorld" scope="singleton" >
<property name="message" value="Welcome to Search Endeca" />
<!-- <property name="greet" ref="greet" /> -->
</bean>
If I dont define the property then we will be facing the below exception.

Caused by: org.springframework.beans.factory.BeanInitializationException: Property 'greet' is required for bean 'helloWorldService'

Hence it @Required got worked.

@Autowired

<bean id="helloWorldService"
class="com.searchendeca.application.HelloWorld" scope="singleton">
<!-- <property name="message" value="Welcome to Search Endeca" /> -->
<!-- <property name="greet" ref="greet" /> -->
</bean>
private GreetingName greets;

public GreetingName getGreets() {
return greets;
}
@Autowired
public void setGreets(GreetingName greets) {
this.greets = greets;
}
By the above autowired happens through the byName.
@Autowired, @Inject, @Resource, and @Value annotations are handled by a Spring
BeanPostProcessor implementations which in turn means that you cannot apply these
annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if
any). These types must be wired up explicitly via XML or using a Spring @Bean method.


@Qualifier

Because autowiring by type may lead to multiple candidates, it is often necessary to have more control
over the selection process. One way to accomplish this is with Spring’s @Qualifier annotation. You
can associate qualifier values with specific arguments, narrowing the set of type matches so that a
specific bean is chosen for each argument.

<bean id="helloWorldService"
class="com.searchendeca.application.HelloWorld" scope="singleton">
  <property name="message" value="Welcome to Search Endeca first" /> 
<!-- <property name="greet" ref="greet" /> -->
</bean>
  <bean id="greets1" class="com.searchendeca.application.GreetingName">
  <qualifier value="first"/>
<property name="name" value="Syed" />
</bean> 
<bean id="greets2" class="com.searchendeca.application.GreetingName">
<qualifier value="second"/>
<property name="name" value="Ghouse" />
</bean>
package com.searchendeca.application;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;

public class HelloWorld {

private GreetingName greets;

public GreetingName getGreets() {
return greets;
}
@Autowired
@Qualifier("first")
public void setGreets(GreetingName greets) {
this.greets = greets;
}

private String mMessage;

public String getMessage() {
return mMessage;
}

public void setMessage(String pMessage) {
this.mMessage = pMessage;
}

}

Output: Hello::Syed

when @Qualifier("second")

Output: Hello::Ghouse


@Resource 

It takes a name attribute, and by default Spring interprets that value as the bean name to be
injected. In other words, it follows by-name semantics, as demonstrated in this example:

<bean id="helloWorldService"
class="com.searchendeca.application.HelloWorld" scope="singleton">
  <property name="message" value="Welcome to Search Endeca first" /> 
<!-- <property name="greet" ref="greet" /> -->
</bean>
  <bean id="greets" class="com.searchendeca.application.GreetingName">
  <qualifier value="first"/>
<property name="name" value="Syed" />
</bean>
private GreetingName greets;

public GreetingName getGreets() {
return greets;
}
@Resource
public void setGreets(GreetingName greets) {
this.greets = greets;
}
@PostConstruct and @PreDestroy
@PostConstruct also be used as the init-method if you dont want to use JSR-250.
@predestroy also be used as the destroy menthod f you dont want to use JSR-250.
public class Helloworld {
@PostConstruct
public void populateHelloworld2() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearHelloworld2() {
// clears the movie cache upon destruction...
}
}

Class path scanning.

We have seen examples from the previous samples where the XML based and annotation based, or mix and match. Now starting from this we are going to see only the annotation based without the xml based initialization also.

1.Partial XML based.

Define the following in the applicationContext.xml

<context:component-scan base-package="com.searchendeca.application"/>

In the Bean class define it as 

@Component(value="HelloWorld")
public class HelloWorld {
private String mMessage;

public String getMessage() {
return mMessage;
}

public void setMessage(String pMessage) {
this.mMessage = pMessage;
}
}
In the main class do the following.
ApplicationContext context = new FileSystemXmlApplicationContext("/src/main/resources/applicationContext.xml");
HelloWorld service = (HelloWorld) context.getBean("HelloWorld");
service.setMessage("Syed Ghouse Habib");
System.out.println(service.getMessage());
once the class is executed then the spring initialize the beans and look for it from the component value and map it.


Starting with Spring 3.0, many features provided by the Spring JavaConfig project are part of
the core Spring Framework. This allows you to define beans using Java rather than using the
traditional XML files. Take a look at the @Configuration, @Bean, @Import, and @DependsOn
annotations for examples of how to use these new features.

2.Without XML Configuration.

Define a simple bean class.

package com.searchendeca.application;

public class HelloWorld {

private String mMessage;

public String getMessage() {
return mMessage;
}

public void setMessage(String pMessage) {
this.mMessage = pMessage;
}


}


In the configuration class or the main define the below.

package com.searchendeca.application;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration //we are defining as the configuration class
public class Hello {
@Bean // through the anotaion we are defining  the Bean Configuration classes can contain bean definition methods annotated with @Bean:

public HelloWorld getHelloWorld() {
return new HelloWorld();
}

@SuppressWarnings("resource")
public static void main(String[] args) {
// We have seen two types of the Application context earlier, since we are using the No XMl based
//We are using the AnnotationConfigApplicationContext as the context.
AnnotationConfigApplicationContext contxt = new AnnotationConfigApplicationContext();
//Scaning for the Basepackages where our bean defined.
contxt.scan("com.searchendeca.application");
contxt.refresh();
//getting the insstance of the bean class.
HelloWorld service = contxt.getBean(HelloWorld.class);
service.setMessage("Syed Ghouse Habib");
//here we can mention the name for the bean and get it 
//@Bean(name= {"getHelloWorld1","Helloworld"}) Bean aliasing
//As discussed in the section called “Naming beans”, it is sometimes desirable to give a single bean
//multiple names, otherwise known asbean aliasing. The name attribute of the @Bean annotation //accepts a String array for this purpose.
//HelloWorld service = contxt.getBean("getHelloWorld1");
System.out.println(service.getMessage());
}
}

Using @ComponentScan

In the Bean class just define the @service or @component.

In the Configuration class do the following.

package com.searchendeca.application;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan(basePackages = {"com.searchendeca.application"}) // This scans for all the class defined in the package.
public class Hello {
@Autowired
public static HelloWorld getHelloWorld() {
return new HelloWorld("Syed");
}



@SuppressWarnings("resource")
public static void main(String[] args) {
AnnotationConfigApplicationContext contxt = new AnnotationConfigApplicationContext();
try {
contxt.register(HelloWorld.class);
contxt.refresh();
HelloWorld service = contxt.getBean(HelloWorld.class);
System.out.println(getHelloWorld().getMessage());

}
finally {
contxt.close();
        }
}
}

Using JSR 330 Standard Annotations

If you are using Maven, the javax.inject artifact is available in the standard Maven
repository.

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>


Dependency Injection with @Inject and @Named

@Inject
Instead of @Autowired, @javax.inject.Inject may be used as follows:

@Inject
public static HelloWorld getHelloWorld() {
return new HelloWorld("Syed");
}

@Named
Instead of @Component, @javax.inject.Named may be used as follows:

@Named
public class HelloWorld {

public HelloWorld() {

}

No comments:
Write comments