Spring Annotation Notes PDF
Spring Annotation Notes PDF
Spring Annotation Notes PDF
[1]
Inversion of Control in Spring – Using Annotation
From Spring 2.5, a complete set of configuration annotations has been introduced that
is related to Spring configuration XML such as Spring bean definition or Dependency
Injection. In addition, Spring 3 has also provided JSR-330 (Dependency Injection for
Java) annotation for DI as well as Spring-specialized annotation.
For a Spring IoC container to recognize annotations, we need to add the following
definition to the beans.xml configuration 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-3.2.xsd">
<context:annotation-config />
</beans>
[2]
Chapter 9
File Syntax
Employee.java package
org.packt.spring.chapter3.
annotation;
import
org.springframework.stereotype.
Service;
@Service
public class Employee {
public String toString() {
return "Annotation Based
Configuration";
}
}
beans.xml <context:annotation-config />
<context:component-scan base-
package="org.packt.spring.chapter3.
annotation"/>
File Syntax
Employee.java package org.packt.spring.chapter3.xml;
[3]
Inversion of Control in Spring – Using Annotation
File Syntax
beans.xml <bean id="employeeBean" class="org.packt.
Spring.chapter3.xml
.Employee ">
</bean>
For large applications, there would be more XML tags and that increases the
application's complexity. To eliminate this, we can use annotation in the Java
class and remove a few XML tags from the configuration file.
Bean management
Beans that need to be managed by Spring can be defined using the stereotype
annotation. Classes that are annotated with one of these stereotype annotations will
automatically be registered in the Spring application context if <context:component-
scan> is in the Spring XML configuration.
Stereotype annotation
@Component is a parent stereotype annotation and usually defines all beans.
Components are divided on the basis of layers by the Spring Framework and
it is recommended to use annotation as shown in the following figure:
@Component
There are four types of autocomponent scan annotations. They are as follows:
[4]
Chapter 9
@Component
The @Component annotation is a generic stereotype annotation that defines a class as
a bean.
Employee.java
The following code snippet shows the Employee class:
import org.springframework.stereotype.Component;
@Component
public class Employee {
//…
}
Here, the @Component annotation defines the Employee class as a Spring bean.
Whenever Spring detects a class annotated with @Component, it does the equivalent
of defining the class as a bean in the configuration XML file and creating a name for
this bean, which is actually the name of the class Employee.
@Repository
We must annotate all your repository classes with the @Repository annotation,
which is a marker for a class. A repository class serves as a Data Access Object
(DAO) in the persistence layer of the application. All your database access logic
should go in these DAO classes, as shown here:
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDAO
{
// database access logic
}
[5]
Inversion of Control in Spring – Using Annotation
@Service
We must annotate all your service classes with the @Service annotation, which is a
class-level annotation. All your business logic should go in the service classes:
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
// business logic
}
In the preceding example, the EmployeeService class is annotated with the Stereotype
annotation called @Service, which represents a component of the service layer.
@Controller
The @Controller annotation indicates that the annotated class is a Spring
component of type "controller". It is a class-level annotation indicating that an
annotated class serves the role of a controller in Spring MVC:
import org.springframework.stereotype.Controller;
@Controller
public class EmployeeController {
//...
}
// . . .
}
[6]
Chapter 9
[7]
Inversion of Control in Spring – Using Annotation
<context:component-scan/>
</beans>
If you add this definition in a Spring configuration XML file, then the container
will scan the classes that exist in the classpath, detects stereotyped classes, and
automatically register them to the Spring Container. It scans packages to find
and register beans within the ApplicationContext. The base-package property
can be used to define the search target package as follows:
<context:component-scan base-package="..."/>
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Override
public String toString() {
return "Annotation Based Configuration";
}
}
[8]
Chapter 9
Here, the EmployeeService class is annotated with @Service to indicate that this
class is an autoscan component.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
EmployeeService employeeService =
(EmployeeServiceImp)context.getBean("employeeService");
}
In the preceding code, we have used the name defined as property employeeService
to find the relevant bean.
<context:component-scan base-
package="org.packt.springframework.chapter3.
annotationbasedconfig"/>
</beans>
[9]
Inversion of Control in Spring – Using Annotation
We have included this definition in beans.xml to autodetect the class and register
the corresponding bean, where the base-package element is a package for the
classes. We have added the package org.packt.springframework.chapter3.
annotationbasedconfig as a value of the base-package attribute in beans.xml.
Spring will automatically scan and detect stereotyped classes inside this package
and register that bean definition to the container. Since the EmployeeService class
is annotated with @Service and resides inside this package, the employeeService
bean definition will be registered in the application context and we can get this bean
from ApplicationContext using the getBean method.
• <context:include-filter>
• <context:exclude-filter>
<context:component-scan>
<context:include-filter> <context:exclude-filter>
Each filter element needs the type and expression attributes to define the
component-scanning strategy. The filter type can be any one of these:
[ 10 ]
Chapter 9
The following example code snippet is trying to load the EmployeeDAO and
EmployeeService classes that match the regular expression specified in the
expression attribute of include-filter. The EmployeeDAO and EmployeeService
classes have not been annotated with the stereotype annotation.
<context:include-filter type="regex"
expression="org.packt.springframework.chapter3.includefilter.*DAO.
*" />
<context:include-filter type="regex" expression="org.packt.
springframework.chapter3.includefilter.*
Service.*" />
</context:component-scan>
[ 11 ]
Inversion of Control in Spring – Using Annotation
Here, in this XML, all filenames contain the DAO or Service (*DAO.* or *Services.*)
syntax, which will be detected and registered in the Spring Container, as we have
provided type as regex along with the corresponding expressions.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
Here, we have called the getBean method to load the EmployeeDAO and
EmployeeService beans from the ApplicationContext. When we run the
preceding main method, the output will be generated as follows, which indicates
that the filter has scanned and registered the bean definition in the container.
[ 12 ]
Chapter 9
<context:exclude-filter type="regex"
expression="org.packt.springframework.chapter3.
excludefilter.*DAO.*" />
</context:component-scan>
Here, in the configuration file, the entire matched component with the regular
expression will be detected and prevent Spring from registering the component
names in the container. So, when we call the getBean("employeeDAO") method,
it will result in the following:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'employeeDAO' is defined
@Scope("prototype")
public class EmployeeService {
//business logic
}
[ 13 ]
Inversion of Control in Spring – Using Annotation
The @Required annotation enforces the required properties of the bean. Before the
bean is used, the setter method annotated with the @Required annotation will be
called. The @Required annotation indicates that the affected bean property must
be populated in the configuration file during Spring configuration, otherwise the
Spring Container throws an exception, BeanInitializationException.
import org.springframework.beans.factory.annotation.Required;
String databaseUrl;
@Required
public void setDatabaseUrl(String databaseUrl) {
this.databaseUrl = databaseUrl;
}
}
The affected bean property must be populated either through an explicit property
value in the bean definition or through autowiring; if not populated at configuration
time, this will throw an exception and avoid NullPointerException or the like
later on.
<bean id="employeeDao"
class="org.packt.Spring.chapter3.requiredannotation.EmployeeDAO">
</bean>
[ 14 ]
Chapter 9
Here, in beans.xml, we are not passing a value for the property databaseUrl.
When we try to use the bean employeeDao, the following error message will be
throw, because the databaseUrl property has not been set:
org.springframework.beans.factory.BeanInitializationException:
Property 'databaseUrl' is required for bean 'employeeDao'
@Autowired
The @Autowired annotation is used to define the dependency provided in the
Spring Framework. It can be used to autowire beans on the setter method or on
a constructor, property, or method. We can autowire one or more parameters
to a constructor or method. More than one constructor can be set as autowired
even though only one constructor can be marked as required. If more than one
constructor has been marked as autowired, then Spring will use the constructor
that has the most arguments matched based on the beans in the Spring Container.
When @Autowired is unable to find at least one match, an exception will be thrown,
BeanCreationException.
In the PayrollSystem class, we are instantiating the bean using the getBean()
method. We have done the annotation-based configuration in beans.xml.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
public EmployeeDao getEmployeeDao() {
return employeeDao;
}
}
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDao {
@Override
public String toString() {
return "Data Access logic will reside in DAO";
}
}
[ 16 ]
Chapter 9
<context:annotation-config />
<context:component-scan base-
package="org.packt.spring.chapter3.annotation...onsetter" />
</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
EmployeeService employeeService =
(EmployeeService)context.getBean("employeeService");
System.out.println(employeeService.getEmployeeDao());
}
}
[ 17 ]
Inversion of Control in Spring – Using Annotation
We can easily observe that there is no relation between the two beans
employeeService and employeeDao. The @Autowired annotation on the setter
method setEmployeeDao() in the EmployeeService class will automatically
wire the employeeDao bean on the basis of type.
Ambiguity – BeanCreationException
If more than one bean match is found in ApplicationContext when matching by
type, and they aren't the Collection class or an array, an exception will be thrown,
BeanCreationException.
Let's understand this with an example. We have an Employee class and more
definitions in beans.xml results in more than one bean in ApplicationContext.
The EmployeeService class will have the setEmployee() method annotated
with @Autowired.
@Override
public String toString() {
return "From employee class";
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
[ 18 ]
Chapter 9
<bean id="employeeA"
class="org.packt.Spring.chapter3.Annotation.onsetter.Employee">
</bean>
<bean id="employeeB"
class="org.packt.spring.chapter3.annotation.onsetter.Employee">
</bean>
<bean id="employeeC"
class="org.packt.Spring.chapter3.Annotation.onsetter.Employee">
</bean>
<bean id="employee"
class="org.packt.Spring.chapter3.Annotation.onsetter.Employee">
</bean>
[ 19 ]
Inversion of Control in Spring – Using Annotation
In the preceding beans.xml file, we have multiple definitions for the bean Employee
with different IDs: employeeA, employeeB, employeeC, and employee. When one
and only one of these IDs matches with the property name in the EmployeeService
class (in this case, only id=employee matches the property name), the dependency
will be successfully injected.
So, the @Autowired annotation first looks for type, and if it finds that there is only
one bean of that type, even though the name is different, it will autowire it as there
is only one bean. If there are multiple beans of the same type, then Spring will look
to see whether there are any beans whose names match the name of the member
variable (in our case, id=employee matches employee). If any do, it will inject the
dependency of that matched bean.
But let's assume that we are restricted to changing the name of a bean defined
in XML, maybe because it was referred by other beans in XML with that name.
Another approach to solve this ambiguity is to use @Qualifier. We will see that
in the latter part of this chapter.
@Autowired on properties
When the @Autowired annotation is used on properties or fields, values are
automatically assigned to the corresponding attributes.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
[ 20 ]
Chapter 9
@Autowired
private Employee employee;
@Override
public String toString() {
return "From employee class";
}
}
<bean id="employee"
class="org.packt.spring.chapter3.
annotation.onproperty.Employee">
</bean>
Here, we see that the @Autowired annotation is used for the type property without
any setter method.
@Autowired on constructors
The @Autowired annotation on a constructor specifies that that constructor should
be autowired when creating the Spring bean, even if no <constructor-arg>
elements are used in the configuration XML file while configuring the bean in it.
Let's consider an example. We have an Employee class annotated with @Component,
an EmployeeService class that has an Employee property, and a constructor that is
annotated with the @Autowired annotation and takes an argument of type Employee.
[ 21 ]
Inversion of Control in Spring – Using Annotation
import org.springframework.stereotype.Component;
@Component
public class Employee {
@Override
public String toString() {
return "From employee class";
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
EmployeeService(Employee employee) {
System.out.println("Inside Employee Service
Constructor");
this.employee = employee;
}
}
<context:component-scan base-
package="org.packt.spring.chapter3.annotation...onconstruction" />
[ 22 ]
Chapter 9
Let's run the application. If everything goes fine with your application, the code will
print the following message:
Inside Employee Service Constructor
From employee class
Sometimes, we need to make the property being wired an optional property that
accepts a null value. In that case, by setting the @Autowired annotation's required
attribute to false, we configure an optional autowiring.
Let's consider an example to understand this in more detail. We have the Employee
class annotated with the @Component annotation and an Address class. We have the
EmployeeService class annotated with the @Service annotation. This class has two
properties: Employee and Address.
import org.springframework.stereotype.Component;
@Component
public class Employee {
@Override
public String toString() {
return "From employee class";
}
}
[ 23 ]
Inversion of Control in Spring – Using Annotation
@Override
public String toString() {
return "From to address";
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
private Employee employee;
@Autowired(required = false)
public void setAddress(Address address) {
this.address = address;
}
[ 24 ]
Chapter 9
System.out.println(employeeService.getEmployee());
System.out.println(employeeService.getAddress());
Here, in bean.xml, we have not added a definition for Address. So the bean will
not be available to ApplicationContext.
@Qualifier
While using the @Autowired annotation, we observed some ambiguity. @Autowired
is run in a type-driven injection manner. When, in the same object type, you find
several beans, you use the @Qualifier annotation for more control over deciding
the target bean.
@Autowired
@Qualifier("qualifier_name")
[ 25 ]
Inversion of Control in Spring – Using Annotation
@Autowired
@Qualifier("employeeA")
private Employee employee;
// . . .
}
As you can see, I've used the @Qualifier annotation along with the
@Autowired annotation. Spring will first check for autowire by type after looking
at the configuration file for beans of that type. And, in this case, it will get multiple
beans of the same type, that is, Employee. Beans whose qualifier property value is
employeeA are injected as employee member variables. In EmployeeService.java,
I've used @Qualifier("employeeA"); it means we want to autowire the Employee
property of EmployeeService with the bean id="employeeService" in the XML
configuration file.
@Resource
The Spring Framework supports dependency injection using the JSR-250 @Resource
annotation on the bean property or the property setter methods. The @Resource
annotation is found in Java EE 5 and Java 6, which the Spring Framework supports
for Spring-managed objects as well.
[ 26 ]
Chapter 9
The @Resource annotation injects the dependency in the variables of the class. It
is from javax.annotation and isn't specific to the Spring Framework. @Resource
takes the name as attribute and Spring interprets the associated value as the bean
name to be injected.
@Resource has the name property. Due to this, a designated search name is used
by the name property to inject to the element defined by @Resource when the
Spring Container searches for the bean. If you do not specify the name attribute
in @Resource, then Spring will interpret the property name as the bean name to
be injected and will search for that bean in the configuration file.
@Override
public String toString() {
return "From employee class";
}
}
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Resource(name = "employeeA")
private Employee employee;
[ 27 ]
Inversion of Control in Spring – Using Annotation
<context:component-scan base-
package="org.packt.Spring.chapter3.annotation.resource" />
<bean id="employeeA"
class="org.packt.spring.chapter3.annotation.resource.Employee">
</bean>
<bean id="employeeB"
class="org.packt.spring.chapter3.annotation.resource.Employee">
</bean>
As you can see, two beans of the same type have been defined in beans.xml.
In the EmployeeService class, we have used @Resource(name="employeeA"),
which means we want to autowire the Employee property of EmployeeService
with the bean id="employeeA" defined in the XML configuration file.
[ 28 ]
Chapter 9
Let's take a scenario where the Properties file gets loaded as soon as a bean gets
initialized and the properties file gets cleared when the bean gets destroyed. If the
properties file gets loaded for first client request, it means it will take time on first
request. To overcome these issues, the properties file should get loaded on bean
initialization itself and get destroyed once the bean is destroyed.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@PostConstruct
public void initializeEmployeeService() {
System.out.println("Init of EmployeeService");
}
@PreDestroy
public void destroyEmployeeService() {
System.out.println("Destroy Of EmployeeService");
}
}
[ 29 ]
Inversion of Control in Spring – Using Annotation
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
<context:component-scan base-
package="org.packt.spring.chapter3.annotation...lifecycle" />
[ 30 ]
Chapter 9
@Configuration annotation
A class annotated with @Configuration is the central artifact of Java-based Spring
configuration. A class annotated with the @Configuration annotation can be used
by a Spring Container as a source of bean definitions. This class will contain one or
more Spring bean declarations. Let's see how to use the @Configuration annotation.
@Configuration
public class SpringConfig {
// bean declaration methods
}
In the preceding code snippet, we have annotated a class with the @Configuration
annotation:
• An application can use one or more class that has been annotated with
@Configuration.
• The @Configuration annotation is meta-annotated as a @Component
annotation.
• Classes annotated with @Configuration are candidates for component
scanning. These classes can also take advantage of @Autowired annotations
at the field and method levels, but not at the constructor level.
• Classes annotated with @Configuration must also have a
default constructor.
• The @Value annotation can be used to wire externalized values into
classes annotated with @Configuration.
[ 31 ]
Inversion of Control in Spring – Using Annotation
@Bean annotation
The @Bean annotation is a method-level annotation that is a direct analog of the XML
<bean/> element and is used to wire beans using Spring's Java-based configuration.
This annotation supports some of the attributes offered by the <bean/> tag in XML,
such as init-method, destroy-method, autowiring, and name. It can be used in a
class either annotated with @Configuration or @Component.
Declaring a bean
We can declare a bean by annotating a method with @Bean. This annotated method
is used to register a bean definition of the type specified as the method's return value
within an ApplicationContext.
The bean name, by default, will be taken from the method name. Let's understand how
to use the @Bean annotation to wire beans using Spring's Java-based configuration.
The object returned from this annotated method will be registered as a bean in the
Spring ApplicationContext:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public Employee employee() {
return new Employee();
}
}
[ 32 ]
Chapter 9
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean(name="employeeBean")
public Employee employee() {
return new Employee();
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.
AnnotationConfigApplication
Context;
[ 33 ]
Inversion of Control in Spring – Using Annotation
Injecting dependencies
Injecting dependencies using Java-based Spring configuration is as simple as having
one bean method call another:
@Configuration
public class SpringConfig {
@Bean
public EmployeeService employeeService() {
return new EmployeeDao(employeeDao());
}
@Bean
public EmployeeDao employeeDao() {
return new EmployeeDao();
}
}
@Import annotation
To load @Bean definitions from another configuration class, we can use the @Import
annotation.
@Bean
public EmployeeService employeeService() {
return new EmployeeService();
}
}
You can import the bean declaration from the ConfigA class to another configuration
class as shown here:
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
[ 34 ]
Chapter 9
ApplicationContext context =
new AnnotationConfigApplicationContext(ConfigB.class);
The initialization and destruction callback methods are supported by the @Bean
annotation, which is same as XML's init-method and destroy-method attributes
to the bean element:
public class EmployeeService {
@Configuration
public class SpringConfig {
@Bean(initMethodName = "init" , destroyMethod = "cleanup")
public EmployeeService employeeService() {
return new EmployeeService();
}
}
[ 35 ]
Inversion of Control in Spring – Using Annotation
@Scope annotation
The beans defined with the @Bean annotation is by default singleton, but you can
override this with the @Scope annotation as follows:
@Configuration
public class AppConfig {
@Bean
@Scope("prototype")
public EmployeeService employeeService() {
// ...
}
}
[ 36 ]
Chapter 9
Event Description
ContextRefreshedEvent When ApplicationContext is either initialized or
refreshed, ContextRefreshedEvent is published.
Here, initialized means when all beans are loaded into
the container and the ApplicationContext object is
ready for use. A refresh using the refresh() method
can be triggered multiple times as long as the context has
not been closed and the chosen ApplicationContext
actually supports refreshes. For example,
GenericApplicationContext does not support
refreshes whereas XmlWebApplicationContext does.
ContextStartedEvent This is published on starting ApplicationContext
using the start() method on the
ConfigurableApplicationContext interface. When
ApplicationContext starts, the life cycle of beans
receive an explicit start signal. This event can be used to
restart beans after an explicit stop. This event can also be
used to start components that have not been configured
for autostart.
ContextStoppedEvent When ApplicationContext is
stopped using the stop() method on the
ConfigurableApplicationContext interface, this
event is published and the life cycle of beans receive an
explicit stop signal.
ContextClosedEvent This is published when ApplicationContext
is closed using the close() method on the
ConfigurableApplicationContext interface. It
indicates that all singleton beans are destroyed and
cannot be refreshed or restarted as it reaches the end of
its life.
RequestHandledEvent This is an event specific to the Web, telling all beans that
an HTTP request has been serviced. After the request is
complete, this event is published. Only web applications
that use Spring's DispatcherServlet can apply this
event.
[ 37 ]
Inversion of Control in Spring – Using Annotation
Creating listeners
The first step to creating listeners is to create some beans that can listen to events.
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationEventListener implements
ApplicationListener<ContextStartedEvent> {
@Override
public void onApplicationEvent(ContextStartedEvent arg0) {
System.out.println("Context Started Event Received");
}
}
[ 38 ]
Chapter 9
Here, the start() method will propagate the start signal to component.
import org.springframework.context.ApplicationEvent;
[ 39 ]
Inversion of Control in Spring – Using Annotation
Publishing an event
To publish an event, a class has to implement the ApplicationEventPublisherAware
interface. The ApplicationEventPublisher interface notifies all registered listeners
of this application. A class that implements the ApplicationListener interface can
handle published events. Pass an instance of the event to the publishEvent() method.
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
@Component
public class LoginEventPublisher implements
ApplicationEventPublisherAware {
@Override
public void
setApplicationEventPublisher(ApplicationEventPublisher publisher)
{
this.publisher = publisher;
}
import org.springframework.context.ApplicationListener;
[ 40 ]
Chapter 9
import org.springframework.stereotype.Component;
@Component
public class LoginEventListener implements
ApplicationListener<LoginEvent> {
@Override
public void onApplicationEvent(LoginEvent event) {
if (event instanceof LoginEvent) {
System.out.println(event);
}
}
}
We need to filter the events that the listener needs to handle. Here, in the
LoginEventListener class, we use an instance of check to filter on the non-generic.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
LoginEventPublisher loginEventPublisher =
(LoginEventPublisher) context
.getBean("loginEventPublisher");
loginEventPublisher.publish();
}
[ 41 ]
Inversion of Control in Spring – Using Annotation
SpEL provides dynamic bean wiring at runtime. SpEL picks the right bean or value
to dependency-inject at runtime. We can also use SpEL to inject a bean or a bean
property in another bean, or even to invoke a bean method in another bean.
[ 42 ]
Chapter 9
XML-based configuration
The beans.xml file is shown in the following code snippet, which will define the
addressBean and customerBean beans, and then we will inject addressBean into
another customerBean:
<bean id="addressBean" class="Address">
<property name="id" value="12345"></property>
<property name="streetName" value="24th Main"></property>
<property name="country" value="India"></property>
</bean>
Annotation-based configuration
The Address.java is shown in the following code snippet, which will define the
addressBean bean using annotation:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("addressBean")
public class Address {
[ 43 ]
Inversion of Control in Spring – Using Annotation
@Value("12345")
private Long id;
@Value("24th Main")
private String streetName;
@Value("India")
private String country;
The Customer.java is shown in the following code snippet, which will define the
customerBean bean using annotation:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("customerBean")
public class Customer {
@Value("Ravi")
private String custName;
@Value("#{addressBean}")
private Address address;
@Value("#{addressBean.country}")
private String country;
[ 44 ]
Chapter 9
XML-based configuration
The beans.xml is shown in the following code snippet, which will use the
expression Language to execute a method in addressBean and inject the
result into customerBean:
<bean id="addressBean" class="Address">
<property name="id" value="12345"></property>
<property name="streetName" value="24th Main"></property>
<property name="country" value="India"></property>
</bean>
<bean id="customerBean" class="Customer">
Annotation-based configuration
The Address.java file is shown in the following code snippet, which will create
the addressBean bean using annotation:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("addressBean")
public class Address {
@Value("12345")
private Long id;
@Value("24th Main")
private String streetName;
@Value("India")
private String country;
[ 45 ]
Inversion of Control in Spring – Using Annotation
The Customer.java file is shown in the following code snippet, which will create
the customerBean bean with annotation:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("customerBean")
public class Customer {
@Value("Ravi")
private String custName;
@Value("#{addressBean.getFullAddress()}")
private String fullAddress;
[ 46 ]
Chapter 9
XML-based configuration
In XML, symbols like < are not supported. We must instead use the textual equivalents
shown in the table; for example, use lt instead of < and le instead of <=.
<!--------------------------------------->
<! --------- Logical Operator ----------->
<!--------------------------------------->
<!--------------------------------------->
<! -------- Mathematical Operator ------->
<!--------------------------------------->
[ 47 ]
Inversion of Control in Spring – Using Annotation
</bean>
Annotation-based configuration
The Number.java is shown in the following code snippet:
package org.packt.springframework.chapter3.SpEL.operator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("numberBean")
public class Number {
@Value("999")
private int no;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Calculator {
/* Relational operators */
[ 48 ]
Chapter 9
/* Mathematical operators */
[ 49 ]
Inversion of Control in Spring – Using Annotation
XML-based configuration
The beans.xml file is shown in the following code snippet:
<bean id="employeeBean"
class="org.packt.springframework.chapter3.SpEL.collection.
Employee">
</bean>
<property name="mapElement"
value="#{employeeBean.map['emp1']}"/>
<property name="listElement"
value="#{employeeBean.list[0]}"/>
</bean>
Annotation-based configuration
The Employee.java file is shown in the following code snippet:
package org.packt.springframework.chapter3.SpEL.collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Component;
@Component("employeeBean")
public class Employee {
Employee() {
[ 50 ]
Chapter 9
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class EmployeeService {
@Value("#{employeeBean.map['emp1']}")
private String mapElement;
@Value("#{employeeBean.list[0]}")
private String listElement;
// getter & Setter
}
Let's consider an example to check whether a string contains a valid e-mail address
using the matches operator.
[ 51 ]
Inversion of Control in Spring – Using Annotation
XML-based configuration
The beans.xml file is shown in the following code snippet:
<bean id="emailBean"
class="org.packt.springframework.chapter3.SpEL.regularexpression
.Email">
<property name="emailAddress" value="[email protected]"/>
</bean>
<bean id="clientBean" class="org.packt.springframework.chapter3.SpEL.
regularexpression
.Client">
<property name="validEmail"
value="#{emailBean.emailAddress matches '
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com' }" />
</bean>
Annotation-based configuration
The Email.java file is shown in the following code snippet:
package org.packt.springframework.chapter3.SpEL.regularexpression;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("emailBean")
public class Email {
@Value("[email protected]")
String emailAddress;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("clientBean")
[ 52 ]
Chapter 9
Spring provides support for text messages and internationalization. You can have
a file that consolidates all these key-value pairs and then you can specify the key
itself in your application and refer to the text that is assigned to the key in the
properties file.
Here, we will see how to implement support for messaging using Spring.
We will create a simple properties file, messages.properties, and add all the
key-value pairs to store all messages inside the properties file. Let's say we use
user.welcome=Hello, Welcome to Spring!, where user.welcome is the key
and Hello, Welcome to Spring! is the value. We will then use this key to print
the value associated with this key in our program.
[ 53 ]
Inversion of Control in Spring – Using Annotation
For the property named basename, we will provide a list of all the properties files
where we have stored all the messages. The list will have a value tag that will take
the properties filename without extension.
So, a messageSource bean knows the properties files to read, as the class will
look for the file with the extension .properties, that is, messages.properties
in the classpath.
The following are the different arguments covered in the previous line of code:
• code: This will take the key from the messages.properties file, that is,
user.welcome.
• args: This will take an array of objects in case the message takes some
parameter like dynamic value. Since we aren't passing any parameter now,
we will set it as null.
[ 54 ]
Chapter 9
• defaultMessage: This will be returned in case it does not find the message
we are looking for, that is, default message. So, when arg0 does not match
the key in the properties file, this default value will be printed.
• locale: This indicates the locale for which we need to get the message.
Here, we are passing null, as we have not defined any locale now.
We will looks at locales later in this chapter.
System.out.println(context.getMessage("user.welcome", null,
"Default Greeting", null));
If the code executes successfully, it will print the value from the properties file,
as shown here:
Hello, Welcome to Spring!
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
private MessageSource messageSource;
@Override
public String toString() {
[ 55 ]
Inversion of Control in Spring – Using Annotation
If you have multiple locales to supply messages to, let's say messages_en.properties
for English and messages_de.properties for Deutsch, we can pass the corresponding
locale to the last parameter of the method getMessage. And the corresponding
message picked up from the right properties file.
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
@Autowired
private MessageSource messageSource;
[ 56 ]
Chapter 9
Here, we have passed Locale.English, which will match with the key in the file
messages_en.properties. We have also passed Local.German, which will match
with the key in the file messages_de.properties.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext;
System.out.println("English: " +
employeeService.toEnglish());
System.out.println("German: " +
employeeService.toGernam());
}
}
When we run the preceding code, the output will printed as follows:
English: Hello, Welcome to Spring!
German: Hallo, Herzlich Willkommen Frühling!
[ 57 ]
Inversion of Control in Spring – Using Annotation
Exercise
Q1. What are Stereotype annotations?
Summary
In this chapter, we minimized the XML configurations in Spring. We configured
containers using annotations and compared XML configuration with annotation-based
configuration.
Then we created a custom event and published that event in Spring. We discussed
Spring Expression Language (SpEL) to dynamically evaluate properties and use
them as values configured in the IoC controller using XML and annotations.
Then we implemented text messaging and internationalization (i18n) in Spring.
In the next chapter, we will take a look at Aspect Oriented Programming in Spring.
We will define aspect using XML and annotations in Spring. We will also understand
proxies in Spring.
[ 58 ]