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
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
Target Objects
Advice class
Proxy
Procedure
- define interface
- target bean class
- Advice class
- beans xml config
- config target bean
- config advice
- config proxy
Advice types
Advice type | Interface | Description |
---|---|---|
Around | org.aopalliance.intercept.MethodInterceptor | Intercept target method |
Before | org.springframework.aop.MethodBeforeAdvice | Call before target method |
After | org.springframework.aop.AfterReturningAdvice | Call after target method returns |
Throws | org.springframework.aop.ThrowsAdvice | Call when target method throws exception |
Function Filter by Name | org.springframework.aop.support.NameMatchMethodPointcutAdvisor | Apply only on function with the matched name |
Advice order:
- MethodBeforeAdvice
- MethodInterceptor
- target method
- MethodInterceptor
- 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
- define interface
public interface TestServiceInterface { public void sayHello(); } public interface TestServiceInterface2 { public void sayBye(); }
- 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); } }
- 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()); } }
- beans xml config
- config target bean
- config advice
- config proxy
<!-- 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>