Bean
Factory |
Application context |
Does not support annotation based
Dependency Injection. |
Support annotation based Dependency
Injection. |
Does not support enterprise services. |
Support enterprise services such as
validations, internationalization, etc. |
Configuration Metadata
XML configuration
bean creation :
bean id="reportService"
class="com.infosys.service.ReportService"/ |
reportService --> bean id
com.infosys.service.ReportService --> Fully
qualified class name
Access this from java code
"ReportService reportService =
(ReportService ) context.getBean("reportService");" |
"ReportService reportService =
context.getBean(ReportService.class);" |
"ReportService reportService =
context.getBean("reportService2", ReportService.class);" |
Constructor : constructor-arg tag This is
achieved when the container invokes parameterized constructor to initialize the
properties of a class
by name |
constructor arg
name="totalRecords" value="500" /, |
type |
constructor arg
value="200.00" type = "double"/, |
index |
constructor arg
value="500" index="1" / |
public ReportService(double recordsPerPage) { this.recordsPerPage
= recordsPerPage; } |
Non Primitive :
constructor-arg name="master" ref="pdfReportGenerator"/
bean id="pdfReportGenerator"
class="com.infosys.demo.PDFReportGenerator"/ |
public ReportService(ReportGenerator master,
int recordsPerPage) { this.master = master; this.recordsPerPage = recordsPerPage; } |
bean
id="reportService" class="com.infosys.demo.ReportService property
name="recordsPerPage" value="500" / /bean |
property name="master"
ref="htmlReportGenerator" / |
Setter Injection in Collections
public void setReports(List<ReportGenerator> reports) { this.reports= reports; } |
config.xml
property name = "reports" list ref bean = "PDFReportGenerator / ref bean = "HTMLReportGenerator / /list /property |
Constructor Injection |
Setter Injection |
Dependency Injection is through
parameterized constructor |
Dependency Injection is through setter
methods after invoking the default constructor |
Need parameterized constructor in the
POJO class |
Need default constructor and setter
methods in the POJO class |
constructor-arg tag is used in
configuration file |
property tag is used in configuration
file |
constructor-arg tag "ref"
attribute is used to provide dependency for Object type |
property tag "ref" attribute
is used to provide dependency for Object type |
Preferred
for
|
|
Mode |
Description |
byName |
|
byType |
|
constructor |
|
no |
Default mode which means no autowiring |
bean id="reportService"
class="com.infosys.demo.ReportService" autowire="no" property name="master"
ref="htmlGenerator"/ property name="recordsPerPage"
value="500"/ /bean bean id="htmlReportGenerator"class="com.infosys.demo.HTMLReportGenerator"
/ |
*bean id="reportService"
class="com.infosys.demo.ReportService" autowire="byName"* *property name="recordsPerPage"
value="500" /* */bean* *bean id="master"
class="com.infosys.demo.PDFReportGenerator" /* |
*bean id="reportService"
class="com.infosys.demo.ReportService" autowire="byType"* *property name="recordsPerPage"
value= "500"/* */bean* *bean id="htmlReportGenerator"
class="com.infosys.demo.HTMLReportGenerator" /* |
*bean id="reportService"
class="com.infosys.demo.ReportService"
autowire="constructor"* *constructor-arg
name="recordsPerPage" value= "500"/* */bean* *bean id="htmlReportGenerator"
class="com.infosys.demo.HTMLReportGenerator" /* |
Autowiring Mode |
Description |
byName |
Autowiring
based on bean name through setter injection |
byType |
Autowiring
based on bean type through setter injection |
constructor |
Autowiring
based on the bean type through parameterized constructor |
no |
No
Autowiring, required dependency has to be injected explicitly using property
or constructor-arg ref attribute in bean definition |
Bean Scope (Scope tag)
A bean can be in singleton or prototype scope.
bean id="reportService"
class="com.infosys.demo.ReportService" scope="singleton"/
This is the default mode, if not specified
explicitly in the bean definition
bean id="reportService"
class="com.infosys.demo.ReportService" scope="prototype"/
Annotation based configuration
context:annotation-config in xml configuration, no need of property or
constructor arg. but bean initilization is required.
@Autowired is by default wire the dependency based on type of bean == autowired byType
@Autowired On Property
@Autowired //
For initializing only object dependency private
ReportGenerator master; @Value("100")
// Annotation for initializing primitive types private int
recordsPerPage; |
@Autowired public ReportService(int
recordsPerPage,ReportGenerator master) { System.out.println("Parameterized
Constructor"); this.recordsPerPage = recordsPerPage; this.master = master; } |
@Autowired public void setMaster(ReportGenerator master)
{ System.out.println("Setter method of
master property"); this.master = master; } |
It is generally advisable to autowire beans of workflow classes such as controller, service or repository and not advisable to autowire domain objects as they represent data in a table.
@Qualifier Annotation
How do we make @Autowired to work by name to
allow the scenarios with more than one bean of same type in the configuration?
@Qualifier("beanId") annotation
@Autowired annotation wire the dependency based
on type of bean and in byType there has to be only one bean of specified type
in the configuraiton but in the specified scenario, there are two
beans(htmlReportGenerator and pdfReportGenerator) of type ReportGenerator and
hence there is an ambiguity on which bean to wire causing the application to
throw an exception.
so the application is throwing UnsatisfiedDependencyException
@Autowired @Qualifier("pdfReportGenerator") private
ReportGenerator master; |
Analysis
@Autowired @Qualifier("empRepo") private
EmployeeRepository employeeRepository; |
bean
id="employeeService"
class="com.infosys.service.EmployeeService"/ bean
id="employeeRepository"
class="com.infosys.repo.EmployeeRepoImpl"/ |
Can you analyze the exception stack and say why application is throwing unSatisfiedDependencyException?
This is because, Spring failed to autowire EmployeeRepository bean in the service class as there is no bean in the container with name "empRepo". By default @Autowired is enabled to check the dependent bean and if the dependent bean does not exist then Spring throws unSatisfiedDependencyException exception and prevent the Spring container from launching successfully.
We can disable default behavior of
@Autowired dependency check in certain scenarios to avoid run time exception
even though the required bean does not exist in the container.
@Autowired(required=false) @Qualifier("empRepo") private
EmployeeRepository employeeRepository; |
Introduction to Auto Scanning
Auto scanning helps to remove
explicit bean definition using bean tag from the XML file.
Use @Component annotation at POJO class level
context:component
scan base package = "packageName"/ |
Spring scans specified "com.mypack" package and all its sub-packages to detect @Component annotated classes and create beans of these classes with default bean name same as the class name after making its first letter lowercase.
@Component: It indicates the class(POJO class) as a Spring
component.
@Controller: It indicates Controller class(POJO class in
Spring MVC) in the presentation layer.
@Repository: It indicates Repository class(POJO class in
Spring DATA) in the persistence layer.
@Service: It indicates Service class(POJO class) in the
business layer.
//default
bean id "employeeRepositoryImpl" has to be used to access this bean @Repository public class
EmployeeRepositoryImpl extends BaseRepository implements EmployeeRepository { -------------- } //default
bean id "loanRepositoryImpl" has to be used to access this bean @Repository public class
LoanRepositoryImpl extends BaseRepository implements LoanRepository { ----------------- } // Explicit
bean id "employeeService" is specified and hence we should use
"employeeService" to access the bean of this class @Service("employeeService") public class
EmployeeServiceImpl implements EmployeeService { ----------------------- } // Explicit
bean id "loanService" is specified @Service("loanService") public class
LoanServiceImpl implements LoanService { ---------------------- } |
Spring Java Based Configuration
We can eliminate the need for a XML file completely and
provide the same configurations in a Java class file. Configurations in a XML
file and the configurations in a Java class can co-exist as well.
@Configuration
It indicates Spring container that the class contains the
bean definitions.
This is a pure Java approach to configure Spring container.
@Bean
@Bean is used for defining a bean in Java based
configuration.
In @Configuration annotated Java class, methods annotated
with @Bean provides the bean definition.
@Configuration public class AppConfig {
@Bean // htmlReportGenerator bean definition with bean definition public ReportGenerator htmlReportGenerator(){ return
new HTMLReportGenerator(); }
@Bean // pdfReportGenerator bean definition with bean
definition public ReportGenerator pdfReportGenerator(){ return
new PDFReportGenerator(); }
@Bean // reportService bean definition with bean
dependencies through constructor injection public ReportService reportService1(){ ReportService
reportService=new ReportService(pdfReportGenerator(), 150); return
reportService; } @Bean // reportService bean definition with
bean dependencies through setter injection public ReportService reportService2(){ ReportService
reportService=new ReportService(); reportService.setMaster(htmlReportGenerator()); reportService.setRecordsPerPage("150"); return
reportService; }
|
public class EmployeeClient {
/** The ApplicationContext instantiation */ ApplicationContext context = new
AnnotationConfigApplicationContext(AppConfig.class);
------------------------- }} |
@Configuration |
Terminologies |
Definition |
Aspects |
These are the cross-cutting
concerns that cut across multiple classes. Example: Logging, transition,
security, etc. |
Join point |
The possible program execution
points where the Aspects are applied. In Spring it is always the method
invocation |
Advice |
This represents code to be
executed at the selected Joinpoint(s). |
Pointcut |
This identifies on what Joinpoints
that advice needs to be applied. AspectJ Pointcut Expression
Language(EL) is used for this identification |
Target Object, AOP Proxy and
Weaving |
At runtime, proxies are created
for the business objects(called target objects) with the Aspects linked
using JDk Dynamic/CGLIB proxy. This process is
called Weaving. The object created is called AOP Proxy. |
Required jars
Enable AspectJ annotation support
XML based configuration: Include aop:aspectj-autoproxy/
tag in configuration file
Java Based Configuration: Annotate configuration class with @EnableAspectJAutoProxy
@AspectJ annotation
package
mypack; import
org.aspectj.lang.annotation.Aspect; @Aspect public class
LoggingAspect { ..... ..... } |
bean
id="loggingAspect" class="mypack.LoggingAspect" / |
@Configuration
@EnableAspectJAutoProxy // To enable AspectJ
annotation support for AOP implementation
@ComponentScan("com.infosys.demo")
// To enable auto creation of
aspect bean and other application beans
public class AppConfig {
}
|
// pointcut expression says
that apply log advice to a generateReport() method
// which can take any number of
arguments and can return any value, belongs to ReportService class from the
package com.infosys.demo
@After("execution(*
com.infosys.demo.ReportService.generateReport(..))")
|
// pointcut expression says
that apply log advice to a generateReport() method
// which can take any number of
arguments and can return any value, belongs to ReportService class from the
package com.infosys.demo
@before("execution(*
com.infosys.demo.ReportService.generateReport(..))")
|
// Now the given advice gets
applied only when generateReport() method executes successfully otherwise
advice will not be applied.
@AfterReturning("execution(*
com.infosys.demo.ReportService.generateReport(..))")
|
@AfterReturning(pointcut="execution(* com.infosys.service.EmployeeServiceImpl.createEmployee(..))" , returning="result")
public void logDetails(JoinPoint
joinPoint,int result) { // JoinPoint must
be the first in the list of arguments
//Log joinpoint signature
details
System.out.println("Joinpoint
Signature:"+ joinPoint.getSignature());
System.out.println(result)
|
@AfterThrowing(pointcut="execution(*
com.infosys.demo.ReportService.generateReport(..))", throwing="ex")
public void logAfterAdvice(JoinPoint
joinPoint, Exception ex){
System.out.println("After
throwing Advice: " + ex.getMessage());
//Log Joinpoint signature
details
System.out.println("Joinpoint
signature :" + joinPoint.getSignature());
|
@Around("execution(*
com.infosys.demo.ReportService.generateReport(..))")
public Object logAdvice(ProceedingJoinPoint
jp){
System.out.println("Before:
In around advice");
long start = System.currentTimeMillis();
Object retVal = null;
try {
retVal = jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("After:
In around advice");
System.out.println("Report
generation took:" + (end-start)+ " milliseconds");
retVal = "Value returned
from advice : " + retVal; // modifying the return value from
Joinpoint
System.out.println(retVal);
return (retVal); //
returning the modified value to client
}
}
|
List: Link tgs Dropdown