Thursday, March 31, 2016

Spring AOP

AOP aspect oriented programming


Normally like security check, transaction, log, these commonly used functions are not related to business logic, we can use proxy to separate these code from business codes

Dynamic Proxy
AOP is done in theory of Dynamic Proxy
To understand how and why Dynamic Proxy works: 


Advice implements Aspect

Pointcut(add*): only apply on function name of add*


To see this Spring AOP with AspectJ with no Annotation Config(newer Version)
http://gvace.blogspot.com/2016/04/spring-aop-with-aspectj-no-annotation.html

To see Spring AOP with annotation(newer Version):
http://gvace.blogspot.com/2016/04/spring-aop-with-annotation.html

beans

Target Objects
Advice class
Proxy


Procedure
  1. define interface
  2. target bean class
  3. Advice class
  4. beans xml config
  5. config target bean
  6. config advice
  7. config proxy

Advice types
Advice typeInterfaceDescription
Aroundorg.aopalliance.intercept.MethodInterceptorIntercept target method
Beforeorg.springframework.aop.MethodBeforeAdviceCall before target method
Afterorg.springframework.aop.AfterReturningAdviceCall after target method returns
Throwsorg.springframework.aop.ThrowsAdviceCall when target method throws exception
Function Filter by Nameorg.springframework.aop.support.NameMatchMethodPointcutAdvisorApply only on function with the matched name



Advice order:
  1. MethodBeforeAdvice
  2. MethodInterceptor
  3. target method
  4. MethodInterceptor
  5. AfterReturningAdvice



ProxyFactoryBean:
Only need to setup, does not need code, use dynamic proxy instead
each ProxyFactoryBean only targets to one existed bean
  • proxyInterfaces: register interceptor on all functions of each interface
  • interceptorNames: register advice to run before/after all functions in proxyInterfaces
  • target: has to be only one existed bean


MethodInterceptor
Remember to get method return value, and return the value.

Example:
public class MyMethodInterceptor implements MethodInterceptor{
 
 /**
  * @methodInvocation
  * @return return what methodInvocation returns
  */
 @Override
 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  System.out.println("Before method invote "+methodInvocation.getMethod().getName());
  Object returnValue = methodInvocation.proceed();
  System.out.println("After method invote "+methodInvocation.getMethod().getName());
  return returnValue;
 }
 
}


ThrowsAdvice
Run when there is an error

ThrowsAdvice is just a flag, no function required to implement
Create either one of the following functions by yourself(See from example)
If created both, it always just run the one with multiple arguments


Example:
public class MyThrowsAdvice implements ThrowsAdvice{
 /*
  * ThrowsAdvice is just a flag, no function required to implement
  * Create either one of the following functions by yourself
  * 
  * If created both, it always just run the one with multiple arguments
  */
 public void afterThrowing(Throwable throwable){
  System.out.println("******Something WRONG!!!!!"+throwable.getMessage());
 }
 public void afterThrowing(Method m, Object[] os, Object target, Exception throwable){
  System.out.println("Something WRONG!!!!!"+throwable.getMessage());
 }
}



NameMatchMethodPointcutAdvisor
Like a Filter: apply only on function with the matched name(support regular expression)
Referenced on another Advice, and filter its function by matched name
So the referenced Advice does not need to register in the proxy, use this Filter instead
Just config, do not need implementation

Example:
<bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
 <property name="advice" ref="MyMethodBeforeAdvice" />
 <property name="mappedNames">
  <list>
   <value>sayBye</value>
  </list>
 </property>
</bean>



Whole Process Example

  1. define interface
    public interface TestServiceInterface {
     public void sayHello();
    }
    public interface TestServiceInterface2 {
     public void sayBye();
    }
    
  2. target bean class
    public class Test1Service implements TestServiceInterface, TestServiceInterface2{
     private String name;
     public String getName() {
      return name;
     }
     public void setName(String name) {
      this.name = name;
     }
     @Override
     public void sayHello() {
      System.out.println("Hello "+name);
     }
     @Override
     public void sayBye() {
      System.out.println("Bye "+name);
     }
    
    }
    
  3. Advice class
    public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
     /**
      * @method target method
      * @args parameters of target method
      * @target target object
      */
     @Override
     public void before(Method method, Object[] args, Object target) 
       throws Throwable {  //method.invoke(target, args);
      System.out.println("Log"+method.getName());
     }
     
     
    }
    
  4. beans xml config
  5. config target bean
  6. config advice
  7. config proxy
  8. <!-- target objects -->
    <bean id="test1Service" class="com.gvace.aop.Test1Service">
     <property name="name" value="service1"></property>
    </bean>
    
    <!-- Method Before Advice -->
    <bean id="MyMethodBeforeAdvice" class="com.gvace.aop.MyMethodBeforeAdvice"></bean>
    
    <!-- Proxy Object -->
    <bean id="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- config Target Object -->
     <property name="target" ref="test1Service" />
     <!-- Proxy Interface collection -->
     <property name="proxyInterfaces">
      <list>
       <value>com.gvace.aop.TestServiceInterface</value>
       <value>com.gvace.aop.TestServiceInterface2</value>
      </list>
     </property>
     <!-- Insert Advice into proxy object -->
     <property name="interceptorNames">
      <!-- link Advices with ProxyFactoryBean -->
      <list>
       <value>MyMethodBeforeAdvice</value>
      </list>
     </property>
    </bean>
    





























No comments:

Post a Comment