AOP bean 準備
1 AOP sample
1.1 創建切面
package com.gientech.aop.xml.util;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import java.util.Arrays;
public class LogUtil {
public void myPointCut(){}
public void myPointCut1(){}
private int start(JoinPoint joinPoint){
// 獲取方法簽名
Signature signature = joinPoint.getSignature();
// 獲取參數信息
Object[] args = joinPoint.getArgs();
System.out.println("log----" + signature.getName() + " start execute");
return 100;
}
public static void stop(JoinPoint joinPoint, Object result){
Signature signature = joinPoint.getSignature();
System.out.println("log----" + signature.getName() + " execute stop" + result);
}
public static void logException(JoinPoint joinPoint, Exception e){
Signature signature = joinPoint.getSignature();
System.out.println("log----" + signature.getName() + "throw new excepttion " + e.getMessage());
}
public static void logFinally(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
System.out.println("log----" + signature.getName() + " execute over");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Signature signature = pjp.getSignature();
Object[] args = pjp.getArgs();
Object result = null;
try {
System.out.println("log----環繞通知 start: " + signature.getName() + " method start execute, parameter is " + Arrays.asList(args));
//通過反射的方式調用目標的方法,相當於執行method.invoke(),可以自己修改結果值
result = pjp.proceed(args);
System.out.println("log----環繞通知 stop: " + signature.getName() + " method execute over ");
}catch (Throwable throwable){
System.out.println("log----環繞異常通知 stop: " + signature.getName() + " 出現異常 ");
throw throwable;
}finally {
System.out.println("log----環繞返回通知 stop: " + signature.getName() + " 方法返回結果是: " + result);
}
return result;
}
}
1.2 創建業務類
package com.gientech.aop.xml.service;
import org.springframework.stereotype.Service;
public class MyCalculator /* implements Calculator */{
public Integer add(Integer i, Integer j) throws NoSuchMethodException{
Integer result = i + j;
return result;
}
public Integer sub(Integer i, Integer j) throws NoSuchMethodException{
Integer result = i - j;
return result;
}
public Integer mul(Integer i, Integer j) throws NoSuchMethodException{
Integer result = i * j;
return result;
}
public Integer div(Integer i, Integer j) throws NoSuchMethodException{
Integer result = i / j;
return result;
}
public Integer show(Integer i){
System.out.println("show ......");
return i;
}
}
1.3 創建配置文件
<?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.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="logUtil" class="com.gientech.aop.xml.util.LogUtil"></bean>
<bean id="myCalculator" class="com.gientech.aop.xml.service.MyCalculator"></bean>
<aop:config>
<aop:aspect ref="logUtil">
<aop:pointcut id="myPoint"
expression="execution(Integer com.gientech.aop.xml.service.MyCalculator.* (..))"/>
<aop:around method="around" pointcut-ref="myPoint"></aop:around>
<aop:around method="start" pointcut-ref="myPoint"></aop:around>
<aop:before method="start" pointcut-ref="myPoint"></aop:before>
<aop:after method="logFinally" pointcut-ref="myPoint"></aop:after>
<aop:after-returning method="stop" pointcut-ref="myPoint" returning="result"></aop:after-returning>
<aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
1.4 創建啓動類
package com.gientech.aop.xml;
import com.gientech.aop.xml.service.MyCalculator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
public static void main(String[] args) throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml");
MyCalculator bean = ac.getBean(MyCalculator.class);
Integer result = bean.add(1,2);
System.out.println(result);
}
}
解析過程中註冊 AspectJAwareAdvisorAutoProxyCreator。
在registerBeanPostProcessors方法中創建 AnnotationAwareAspectJAutoProxyCreator(自動代理創建器)對象。
logutil是切面對象,切面對象不需要被代理,所以logutil不需要被代理。
運行結果如下:
2 AOP BeanDefinition加載過程
當使用spring的aop的時候,需要進行N多個對象的創建,但是在創建過程中需要做很多判斷,判斷當前對象是否需要被代理,而代理之前,需要的advisor對象必須要提前創建好,才能進行後續的判斷。
Aop 標籤對應的類如下:
- AspectJMethodBeforeAdvice.java: aop:before 標籤對應類
- AspectJAfterAdvice.java: aop:after 標籤對應類
- AspectJAfterReturningAdvice.java: after-returning 標籤對應類
- AspectJAfterThrowingAdvice.java:after-throwing 標籤對應類
- AspectJAroundAdvice.java: aop:around 標籤對應類
- AspectJExpressionPointcut.java: 表達式對應的類對象,eg:"execution(Integer com.gientech.aop.xml.service.MyCalculator.* (..))"
AOP BeanDefinition加載過程如圖,
- 1 創建AspectJPointAdvisor#0-4,先使用器帶參的構造函數進行對象的創建,但是需要將參數對象準備好,因此要創建內置包含的對象AspectJAroundAdvice
- 2 創建AspectJAroundAdvice,也需要使用帶參的構造函數進行創建,也需要提前準備好具體的參數對象,包含3個參數對象,分別是MethodLocatingFactoryBean, AspectJExpressionPointcut, SimpleBeanFactoryAwareAspectInstanceFactory。
- 3 分別創建上述3個對象,上述3個對象的創建過程都是調用無參的構造函數,直接反射生成即可。
自動代理創建器
切面對象不需要被代理
MyCalculator是被代理對象
某個對象需要被動態代理,此對象對應的普通實例對象也是需要被創建的,只是在後續過程中普通實例對象會被替換。