AOP面向切面編程之spring AOP

一、Spring AOP
1、Spring AOP的兩種實現方式

1.基於xml的Spring AOP開發
2.基於註解的Spring AOP開發

2.引入的jar包

spring-aop-4.3.3.RELEASE.jar,
aspectjweaver-1.8.5.jar
aspectjrt-1.8.5.jar

二、基於xml的Spring AOP開發

(1)創建applicationContext-xml-aop.xml,引入aop命名空間和xsd文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:aop="http://www.springframework.org/schema/aop"
         http://www.springframework.org/schema/aop
         https://www.springframework.org/schema/aop/spring-aop.xsd
 ">
</beans>

(2)在xml文件中將業務bean注入

<bean id="bankService" class="springboot.aop.xml.BankServiceImpl">
</bean>
<bean id="loggerAspect" class="springboot.aop.xml.LoggerAspect">
</bean>

(3)使用aop:aspect標籤配置代理信息

<aop:config>
  <!--execution(* springboot.aop.xml.*.*(..))解釋 第一個*代表匹配所有參數,第二個代表匹配springboot.aop.xml包下的所有類,第三個表示匹配到的類中的所有方法,(..)表示匹配所匹配到方法的所有參數-->
  <aop:pointcut expression="execution(* springboot.aop.xml.*.*(..))" id="loggerPointCut"/>
  <aop:aspect ref="loggerAspect">
   <!-- 前置通知,在被代理方法執行前執行LoggerAspect中的logerBefore()方法-->
   <aop:before method="logerBefore" pointcut-ref="loggerPointCut"/>
   <!-- 後置通知-->
   <aop:after method="logerAfter" pointcut-ref="loggerPointCut"/>
   <!-- 後置返回通知,屬性returning的值必須和方法logerAfterReturning返回值的參數名保持一致-->
   <aop:after-returning method="logerAfterReturning" pointcut-ref="loggerPointCut" returning="returnValue"/>
   <!-- 環繞通知-->
   <aop:around method="logerAround" pointcut-ref="loggerPointCut"/>
   <!-- 後置異常通知通知,拋出異常的時候執行-->
   <aop:after-throwing method="loggerAfterThrowing" pointcut-ref="loggerPointCut"  throwing="exception"/>
  </aop:aspect>
 </aop:config>

(4)LoggerAspect中的各種方法

 public void logerBefore(JoinPoint jp) {
  String methodName = jp.getSignature().getName();//可以獲取當前執行的方法名
  System.out.println("前置通知: " + methodName + "將要被執行!");
  Object[] args = jp.getArgs();//可以獲取參數
  for(Object arg : args) {
   System.out.println("參數爲:" + arg);
  }
  
 }
 
 
 public void logerAfter(JoinPoint jp) {
  String methodName = jp.getSignature().getName();
  System.out.println("後置通知: " + methodName + "已經被執行!");
  
  Object[] args = jp.getArgs();
  for(Object arg : args) {
   System.out.println("參數爲:" + arg);
  }
 }
 
 public void logerAfterReturning(JoinPoint jp, Object returnValue) {
  String methodName = jp.getSignature().getName();
  System.out.println("後置返回通知 " + methodName + "已經被執行!");
  System.out.println("後置返回通知  返回值:" + returnValue);
 }
 
 /**
  * 環繞通知 需要配置返回值,否則目標方法所有的返回值都爲null
  * @param pjp
  * @return
  */
 public Object logerAround(ProceedingJoinPoint pjp) {
  String methodName = pjp.getSignature().getName();
  System.out.println("環繞通知: " + methodName );
  Object[] args = pjp.getArgs();數
  args[0] = "改變參數";
  try {
   Object returnValue = pjp.proceed(args);
   
   System.out.println("環繞通知: " + methodName +“返回值:” + returnValue);
   return new BigDecimal("999999999999999");//可以改變參數的返回值
  } catch (Throwable e) {
   e.printStackTrace();
  }
  return null;
 }
 
 public void loggerAfterThrowing(JoinPoint jp, Exception exception) {
  System.out.println("後置異常通知:" + exception);
 }

(4)被代理類的代碼

public class BankServiceImpl implements BankService{

	public BigDecimal transfer( String source, String target,BigDecimal money) {
	  System.out.println(source + "向" + target + "轉賬:" + money);
	 // throw new RuntimeException("故意出的異常");
	  return new BigDecimal("12345678");
	}
}	

(5)Main類中方法調用

public class Main {
	public static void main(String[] args) {
	ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext-xml-aop.xml");
	BankService bs = ioc.getBean("bankService", BankService.class);
	bs.transfer("你", "我", new BigDecimal("100000000"))
	}
}

(6)分析
調用main方法時,首先創建了一個ioc容器,後面的參數(“applicationContext-xml-aop.xml”)代表的是該容器所對應的文件,然後通過ioc容器調用了getBean方法生成了一個bs對象,然後bs對象調用transfer方法。
執行過程中,因爲xml文件中註冊了LoggerAspect,所以transfer方法會被截住,執行一系列通知方法。其中後置返回通知方法能夠改變方法的參數以及返回值

三、基於註解的Spring AOP開發
1.開發過程
(1)引入aop命名空間和xsd文件(同xml)
(2)在xml中進行配置

 <!-- 自動掃描注入springboot.aop.anno包下的內容-->
<context:component-scan base-package="springboot.aop.anno"></context:component-scan>
 
 <!-- 開啓Spring AOP 自動代理 -->
 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(3)業務類BankServiceImpl加註解@Service(“bankService”),將其注入到IOC容器中
(4)在通知類LoggerAspect中編寫代碼

//@Aspect:作用是把當前類標識爲一個切面供容器讀取  
//@Order(0):當有多個通知類時決定優先級,數字越小優先級越高
//@Component:將該類注入到ioc容器
@Aspect
@Order(0)
@Component
public class TrancationAspect {

@Pointcut("execution(* springboot.aop.anno.*.*(..))")
public void logPointCut() {
}
//PointCut封裝,封裝之後在註解中execution(* springboot.aop.anno.*.*(..))等價於logPointCut()

//@Before("execution(* springboot.aop.anno.*.*(..))")因爲PointCut已經被封裝,所以本行跟下一行效果相同
@Before("logPointCut()")
public void logerBefore(JoinPoint jp) {
	//AspectJ使用org.aspectj.lang.JoinPoint接口表示目標類連接點對象
	String methodName = jp.getSignature().getName();
	System.out.println("TrancationAspect 事務前置通知:method: " + methodName + "將要被執行!");
	Object[] args = jp.getArgs();
	for(Object arg : args) {
		System.out.println("=============參數:>" + arg);
	}
}
}

(5)Main類中調用,代碼如下

public static void main(String[] args) {
	ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext-anno-aop.xml");
	BankService bs = ioc.getBean("bankService", BankService.class);
	bs.transfer("你", "我", new BigDecimal("100"));
}

2、分析
通過註解的方式進行Spring AOP開發,主要分三步
(1)將業務類以及通知類注入到IOC容器
(2)編寫業務類業務代碼,在通知類中編寫出發通知時的方法
(3)編寫主函數出發通知類的通知
(4)執行邏輯跟xml方式一樣,只不過是實現方式不同

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章