重要概念:
1、Aspect
This is a module which has a set of APIs providing cross-cutting requirements. For example, a logging module would be called AOP aspect for logging. An application can have any number of aspects depending on the requirement.
2、Join point
This represents a point in your application where you can plug-in the AOP aspect. You can also say, it is the actual place in the application where an action will be taken using Spring AOP framework.
3、Advice
This is the actual action to be taken either before or after the method execution. This is an actual piece of code that is invoked during the program execution by Spring AOP framework.
4、Pointcut
This is a set of one or more join points where an advice should be executed. You can specify pointcuts using expressions or patterns as we will see in our AOP examples.
5、Introduction
An introduction allows you to add new methods or attributes to the existing classes.
6、Target object
The object being advised by one or more aspects. This object will always be a proxied object, also referred to as the advised object.
7、Weaving
Weaving is the process of linking aspects with other application types or objects to create an advised object. This can be done at compile time, load time, or at runtime.
通知类型(Types of Advice)
Spring aspects can work with five kinds of advice mentioned as follows −
before
Run advice before the a method execution.
after
Run advice after the method execution, regardless of its outcome.
after-returning
Run advice after the a method execution only if method completes successfully.
after-throwing
Run advice after the a method execution only if method exits by throwing an exception.
around
Run advice before and after the advised method is invoked.
织入(wave)
是把切面应用到目标对象并创建新的代理对象的过程。 切面在指定的连接点被织入到目标对象中。
examples
1. based Annotation
// Loggin.java file
package com.dft;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
@Component
@Aspect
public class Logging {
/** Following is the definition for a pointcut to select
* all the methods available. So advice will be called
* for all the methods.
*/
@Pointcut("execution(* com.dft.*.*(..))")
private void selectAll(){}
/**
* This is the method which I would like to execute
* before a selected method execution.
*/
@Before("selectAll()")
public void beforeAdvice(){
System.out.println("Going to setup student profile.");
}
/**
* This is the method which I would like to execute
* after a selected method execution.
*/
@After("selectAll()")
public void afterAdvice(){
System.out.println("Student profile has been setup.");
}
/**
* This is the method which I would like to execute
* when any method returns.
*/
@AfterReturning(pointcut = "selectAll()", returning = "retVal")
public void afterReturningAdvice(Object retVal){
System.out.println("Returning:" + retVal.toString() );
}
/**
* This is the method which I would like to execute
* if there is an exception raised by any method.
*/
@AfterThrowing(pointcut = "selectAll()", throwing = "ex")
public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception: " + ex.toString());
}
}
//Student.java file
package com.dft;
@Component
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
System.out.println("Age : " + age );
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
System.out.println("Name : " + name );
return name;
}
public void printThrowException(){
System.out.println("Exception raised");
throw new IllegalArgumentException();
}
}
//MainApp.java file
package com.dft;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
student.getName();
student.getAge();
student.printThrowException();
}
}
/*
output messages :
Going to setup student profile.
Name : Zara
Student profile has been setup.
Returning:Zara
Going to setup student profile.
Age : 11
Student profile has been setup.
Returning:11
Going to setup student profile.
Exception raised
Student profile has been setup.
There has been an exception: java.lang.IllegalArgumentException
.....
other exception content
**/
2. based xml
// Logging.java file. This is actually a sample of aspect module which defines the methods to be called at various points.
package com.dft;
public class Logging {
/**
* This is the method which I would like to execute
* before a selected method execution.
*/
public void beforeAdvice(){
System.out.println("Going to setup student profile.");
}
/**
* This is the method which I would like to execute
* after a selected method execution.
*/
public void afterAdvice(){
System.out.println("Student profile has been setup.");
}
/**
* This is the method which I would like to execute
* when any method returns.
*/
public void afterReturningAdvice(Object retVal) {
System.out.println("Returning:" + retVal.toString() );
}
/**
* This is the method which I would like to execute
* if there is an exception raised.
*/
public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception: " + ex.toString());
}
}
// Student.java file
package com.dft;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
System.out.println("Age : " + age );
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
System.out.println("Name : " + name );
return name;
}
public void printThrowException(){
System.out.println("Exception raised");
throw new IllegalArgumentException();
}
}
// MainApp.java file
package com.dft;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
student.getName();
student.getAge();
student.printThrowException();
}
}
// Beans.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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:config>
<aop:aspect id = "log" ref = "logging">
<aop:pointcut id = "selectAll"
expression = "execution(* com.dft.*.*(..))"/>
<aop:before pointcut-ref = "selectAll" method = "beforeAdvice"/>
<aop:after pointcut-ref = "selectAll" method = "afterAdvice"/>
<aop:after-returning pointcut-ref = "selectAll"
returning = "retVal" method = "afterReturningAdvice"/>
<aop:after-throwing pointcut-ref = "selectAll"
throwing = "ex" method = "AfterThrowingAdvice"/>
</aop:aspect>
</aop:config>
<!-- Definition for student bean -->
<bean id = "student" class = "com.dft.Student">
<property name = "name" value = "Zara" />
<property name = "age" value = "11"/>
</bean>
<!-- Definition for logging aspect -->
<bean id = "logging" class = "com.dfd.Logging"/>
</beans>
/*
output messages :
Going to setup student profile.
Name : Zara
Student profile has been setup.
Returning:Zara
Going to setup student profile.
Age : 11
Student profile has been setup.
Returning:11
Going to setup student profile.
Exception raised
Student profile has been setup.
There has been an exception: java.lang.IllegalArgumentException
.....
other exception content
**/
Understanding Dynamic Proxy : Spring AOP Basics
Proxy Pattern:
We can create a proxy of the object , which will take care of the cross cutting concern code.There are two kind of proxy patterns :
- Static Proxy :
Where we create a proxy object for every class. This is not feasible and practical
- Dynamic Proxy :
In this , proxies are created dynamically through reflection . This functionality is added from JDK 1.3 . dynamic Proxy form the basic building block of Spring AOP
package com.somaniab.blog.ex;
public interface Basicfunc{
public void method1();
}
package com.somaniab.blog.ex;
public class Example1 implements Basicfunc{
@Override
public void method1() {
System.out.println("executing method 1");
}
}
Now if we want to calculate execution time of method1 , we have to write that code in method itself , or we can create a proxy object. For creating proxy object , we create a Invocationhandler as following code.
In this invocation handler , we call the actual method as well as calculate the time taken.Now , in main class we create the proxy object by using Proxy class.
package com.somaniab.blog.ex;
import java.lang.reflect.Proxy;
public class MainClass {
public static void main(String[] args) {
Example1 ex = new Example1();
Basicfunc proxied =(Basicfunc)Proxy
.newProxyInstance(MainClass.class.getClassLoader(),
ex.getClass().getInterfaces() ,new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy executing");
long t1 = System.currentTimeMillis();
method.invoke(ex, args);
System.out.println(System.currentTimeMillis() - t1);
System.out.println("proxy executed");
return null;
}
});
proxied.method1();
}
}
For creating Proxy we pass classloader[mostly the same classloader as origin class],interfaces,and the invocationHandler (pass the original target object in the invocation handler ). The original class must implement a interface ,only those method declared in interface get proxied and then we cast the proxy to the interface type .
In CGLib Proxy , there is no necessity of declaring interface .
So , this is how we made sure that our Example class write code for only method1 and we kept execution time calculation code out of it.