1. 程式人生 > 實用技巧 >spring註解-aop

spring註解-aop

一、動態代理

  在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式

  • 匯入aop依賴(spring-aspects)
  • 業務邏輯元件和切面類生成的例項物件都必須是註冊在ioc容器中的(自己建立的物件是不會執行切面方法的);在定義的切面類上標註@Aspect、配置類上標註@EnableAspectJAutoProxy開啟基於註解的aop模式(等同於xml配置<aop:aspectj-autoproxy></aop:aspectj-autoproxy>)
  • 在切面類上的每一個(通知)方法上標註通知註解,並且在通知註解上定義切入點表示式(告訴Spring在哪些類、方法以及方法執行前、後執行通知方法)
    • 切入點表示式:程式執行到哪些類哪些方法時要進行切入;通過表示式進行定義
    • 執行時機:程式執行方法的時機;通過通知註解進行標註

程式碼實現

  定義日誌切面類(LogAspects):在程式執行到某個階段的時候能夠通過切面類裡的方法介入進去給切面類的目標方法標註何時何地執行(通知註解)

  • 前置通知(@Before):在目標方法執行之前執行
  • 後置通知(@After):在目標方法執行結束之後執行(無論方法正常結束還是異常結束)
  • 返回通知(@AfterReturning):在目標方法正常返回之後執行
  • 異常通知(@AfterThrowing):在目標方法出現異常以後執行
  • 環繞通知(@Around):動態代理,手動推進目標方法執行(joinPoint.procced())

/**
 * @Aspect: 告訴Spring當前類是一個切面類
 */
@Aspect
public class LogAspects {
    
    //抽取公共的切入點表示式
    @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
    public void pointCut(){};
    
    //本類引用(切入點表示式) @Before("public int com.atguigu.aop.MathCalculator.*(..)")
  @Before("pointCut()") 

  public void logStart(JoinPoint joinPoint){
      Object[] args = joinPoint.getArgs();
      System.out.println(""+joinPoint.getSignature().getName()+"執行。。。@Before:引數列表是:{"+Arrays.asList(args)+"}");
}

   //其他的切面引用 
  @After("com.atguigu.aop.LogAspects.pointCut()") public void logEnd(JoinPoint joinPoint){ System.out.println(""+joinPoint.getSignature().getName()+"結束。。。@After"); } //JoinPoint一定要出現在引數表的第一位 @AfterReturning(value="pointCut()",returning="result") public void logReturn(JoinPoint joinPoint,Object result){ System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:執行結果:{"+result+"}"); } @AfterThrowing(value="pointCut()",throwing="exception") public void logException(JoinPoint joinPoint,Exception exception){ System.out.println(""+joinPoint.getSignature().getName()+"異常。。。異常資訊:{"+exception+"}"); }

AOP原理

【看給容器中註冊了什麼元件,這個元件什麼時候工作,這個元件的功能是什麼?】

第一步:@EnableAspectJAutoProxy:這步的作用就是在容器中新增一個AnnotationAwareAspectJAutoProxyCreator的bean元件

  標註@EnableAspectJAutoProxy後 -》@Import(AspectJAutoProxyRegistrar.class),它實現了ImportBeanDefinitionRegistrar介面,registerBeanDefinitions()作用就是給容器中新增一個BeanDefinition

  registerBeanDefinitions()呼叫其他方法判斷BeanDefinitionRegistry是否有org.springframework.aop.config.internalAutoProxyCreator的beanName,如果沒有則通過傳入的AnnotationAwareAspectJAutoProxyCreator.class構建一個RootBeanDefinition物件,beanName就是org.springframework.aop.config.internalAutoProxyCreator

第二步:AnnotationAwareAspectJAutoProxyCreator.class

  AnnotationAwareAspectJAutoProxyCreator -》AnnotationAwareAspectJAutoProxyCreator -》AspectJAwareAdvisorAutoProxyCreator -》AbstractAdvisorAutoProxyCreator -》AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(一個是後置處理器,一個是自動裝配BeanFactory)

  AbstractAutoProxyCreator有setBeanFactory(),也有beanPostProcessor的後置處理器的邏輯

  AbstractAdvisorAutoProxyCreator重寫了setBeanFactory()並且該方法中還呼叫一個initBeanFactory(),沒有重寫父類beanPostProcessor的方法

  AnnotationAwareAspectJAutoProxyCreator重寫了initBeanFactory()