Spring註解(AOP)
底層動態代理
程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式
導入aop的相關模塊
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.6.RELEASE</version> </dependency>
動態感知業務類運行的狀態
通知: 前置 @Before 後置 @After 環繞 @Around 異常@AfterThrowing 返回 @AfterReturning
補充環繞通知: 動態代理,手動推進目標方法運行(joinPoint.proceed() )
步驟:
編寫切面類
在切面類裏面 把每個方法 何時何地切入都指定好
將切面類和業務邏輯類 都添加到容器中
告訴容器 哪個是切面類@Aspect
在 xml中 <aop: aspectj-autoproxy> </aop:aspectj-autoproxy> 開啟基於註解版的切面功能
註解中: 在當前的配置類加入 @EnableAspectJAutoProxy 啟用基於註解的aop模式
正常代碼:
@Component public class Mathcalculator { public int div(int i , int j) { System.out.println("Mathcalculator--div被調用"); return i/j; } }
切面類:
@EnableAspectJAutoProxy @Configuration publicclass AOPConfig { @Bean //業務邏輯類註冊到容器 public Mathcalculator mathcalculator() { return new Mathcalculator(); } @Bean // 切面類註冊到容器中 public LogAspects logAspects() { return new LogAspects(); } }
測試:
public class test { @Test public void test01(){ //使用無參構造器 創建applicationContext (詳情自己研究下有參構造器的方法) AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(AOPConfig.class); Mathcalculator bean = applicationContext.getBean(Mathcalculator.class); bean.div(1, 1); //設置需要激活的環境 applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以設置多個 //註冊主配置類 applicationContext.register(Profile.class); //啟動刷新容器 applicationContext.refresh(); } }
結果:
升級:
切面類
@Aspect public class LogAspects { //抽取公共的切入點表達式 本類的 如果是別的類的 寫全名就OK了 @Pointcut("execution(public int com.toov5.config.Mathcalculator .*(..))" ) public void pointCut() { } // @Before("public int com.toov5.config.Mathcalculator.div(int , int)") @Before( "pointCut()" ) public void logStart(JoinPoint joinpoint) { //獲取簽名 獲取方法 Object[] args = joinpoint.getArgs(); //目標方法 運行時候需要的參數表 System.out.println("除法運行@Before"+joinpoint.getSignature().getName()+"運行時參數表"+args ); } @After( "pointCut()" ) //運行異常與否 都要執行的 public void logEnd(JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()+"除法結束@After"); } @AfterReturning(value="pointCut()", returning="result") public void logReturn(JoinPoint joinpoint,Object result ) { //result 接受返回值 System.out.println(joinpoint.getSignature().getName()+"除法正常運行@AfterReturning,結果:"+result); } @AfterThrowing(value = "pointCut()", throwing="e") public void logException(JoinPoint joinpoint, Exception e) { System.out.println( joinpoint.getSignature().getName()+"除法異常@AfterThrowing"+e.getMessage()); } }
配置:
@EnableAspectJAutoProxy @Configuration public class AOPConfig { @Bean //業務邏輯類註冊到容器 public Mathcalculator mathcalculator() { return new Mathcalculator(); } @Bean // 切面類註冊到容器中 public LogAspects logAspects() { return new LogAspects(); } }
測試類:
public class test { @Test public void test01(){ //使用無參構造器 創建applicationContext (詳情自己研究下有參構造器的方法) AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(AOPConfig.class); Mathcalculator bean = applicationContext.getBean(Mathcalculator.class); bean.div(1, 1); //設置需要激活的環境 applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以設置多個 //註冊主配置類 applicationContext.register(Profile.class); //啟動刷新容器 applicationContext.refresh(); } }
結果:
JointPoint 要寫一定要寫在 參數的首位!
三步走:
1 將業務邏輯組件和切面類都加入到容器,告訴Spring哪個是切面類(@Aspect)
2 在切面類上的每一個通知方法上標註 通知註解,告訴Spring合適何地運行(切入點表達式)
3 開啟基於註解的aop模式 與config上
總結:
aop的原理
加入@EnableAspectJAutoProxy 才有AOP
繼續點開看
利用AspectJAutoProxyRegistrar 給自定義容器中註冊bean
給容器註冊一個AnnotationAwareAspectJAutoProxyCreator 自動代理創建器
可以一直追蹤其父類:
實現了 SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
後置處理器
關註後置處理器的工作 Bean初始化完成前後做的事情
BeanFactory 自動註入
AbstractAutoProxyCreator :
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
然後是與後置處理器有關的:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
有後置處理器的邏輯
Spring註解(AOP)