spring AOP基礎(實現AOP兩種方法)
1.AOP的作用
在OOP中,正是這種分散在各處且與物件核心功能無關的程式碼(橫切程式碼)的存在,使得模組複用難度增加。AOP則將封裝好的物件剖開,找出其中對多個物件產生影響的公共行為,並將其封裝為一個可重用的模組,這個模組被命名為“切面”(Aspect),切面將那些與業務無關,卻被業務模組共同呼叫的邏輯提取並封裝起來,減少了系統中的重複程式碼,降低了模組間的耦合度,同時提高了系統的可維護性。
上面這段話可能不是那麼好理解,那麼AOP到底有什麼作用呢?我們通過下面的代買來慢慢解釋:
我們需要在計算出結果前後各輸出一句話,其中我們想更改輸出語句(橫向程式碼)那麼我們就需要逐個的更改每個方法中的輸出語句,那麼AOP作業就是將這些與核心程式碼無關的程式碼抽取出來進行單獨管理。public int add(int i, int j) { System.out.println("the method begin"); int result = i + j; System.out.println("the method end"); return result; } public int sub(int i, int j) { System.out.println("the method begin"); int result = i - j; System.out.println("the method end"); return result; }
2.基本概念:
1、橫切關注點
對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點
2、切面(aspect)
類是對物體特徵的抽象,切面就是對橫切關注點的抽象
3、連線點(joinpoint)
被攔截到的點,因為Spring只支援方法型別的連線點,所以在Spring中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器
4、切入點(pointcut)
對連線點進行攔截的定義
5、通知(advice)
所謂通知指的就是指攔截到連線點之後要執行的程式碼,通知分為前置、後置、異常、最終、環繞通知五類
6、目標物件
代理的目標物件
7、織入(weave)
將切面應用到目標物件並導致代理物件建立的過程
8、引入(introduction)
在不修改程式碼的前提下,引入可以在執行期為類動態地新增一些方法或欄位
3.使用註解配置AOP介面類:ArithmeticCalculator.java
介面實現類:ArithmeticCalculatorImpl.javapackage com.yuehailin.aop; /** * Created by yuehailin on 2018/1/31. */ public interface ArithmeticCalculator { int add(int i,int j); int sub(int i,int j); int mul(int i,int j); int div(int i,int j); }
package com.yuehailin.aop;
import org.springframework.stereotype.Component;
/**
* Created by yuehailin on 2018/1/31.
*/
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator{
@Override
public int add(int i, int j) {
System.out.println("the method begin");
int result = i + j;
System.out.println("the method end");
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("the method begin");
int result = i - j;
System.out.println("the method end");
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
LoggingAspect.java
package com.yuehailin.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* Created by yuehailin on 2018/1/31.
*/
@Order(2)
@Aspect
@Component
/**
* 定義一個方法,用於宣告切入點表示式該方法不需要添入其他的程式碼
*/
public class LoggingAspect {
@Pointcut("execution(public int com.yuehailin.aop.ArithmeticCalculator.*(..))")
public void declareJointPointExpression(){}
/**
* 在介面的每一個實現類的的方法開始之前執行一段程式碼
*/
@Before("declareJointPointExpression()")
public void beforeMethod(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" begins "+ Arrays.asList(args));
}
/**
* 在方法執行之後執行的程式碼,無論該方法是否有異常
* @param joinPoint
*/
@After("declareJointPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" end "+ Arrays.asList(args));
}
/**
* 在方法正常結束後執行的程式碼,叫做返回通知
* 返回通知是可以訪問到方法的返回值的
* @param joinPoint
*/
@AfterReturning(value = "declareJointPointExpression()",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" end "+ result);
}
/**
* 在方法出現異常時會執行的程式碼,而且可以訪問到異常物件
* 可以指定在出現特定異常時在執行
* @param joinPoint
* @param ex
*/
@AfterThrowing(value = "declareJointPointExpression()",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" occurs excepetion with "+ ex);
}
/**
* 環繞通知需要攜帶ProceedingJoinPoint的引數
* 環繞通知類似於動態代理的全過程,ProceedingJoinPoint這個型別的引數可以決定是否執行目標方法】
* 且必須返回值,即為目標方法的返回值
* @param pjd
*/
@Around(value = "execution(public int com.yuehailin.aop.ArithmeticCalculator.*(..))")
public Object aroundMethod(ProceedingJoinPoint pjd){
// 執行目標方法·
Object result =null;
String methodname = pjd.getSignature().getName();
try {
// 前置通知
System.out.println("the method "+ methodname+" begin with "+ Arrays.asList(pjd.getArgs()));
result=pjd.proceed();
// 後置通知
System.out.println("the method "+" end with "+result);
} catch (Throwable throwable) {
// 異常通知
System.out.println("異常通知"+throwable+methodname);
}
// 後置通知
System.out.println("the method end with " +methodname);
return result;
}
}
xml檔案
<?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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--配置自動掃描的包-->
<context:component-scan base-package="com.yuehailin.aop"></context:component-scan>
<!--配置自動為匹配aspectj 註解的java類生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
測試類:
package com.yuehailin.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by yuehailin on 2018/1/31.
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
int result = arithmeticCalculator.add(1,2);
System.out.println(result);
int result01 = arithmeticCalculator.div(1000,10);
System.out.println(result01);
}
}
4.基於XML配置的AOP
介面類:ArithmeticCalculator.java
package com.yuehailin.aop;
/**
* Created by yuehailin on 2018/1/31.
*/
public interface ArithmeticCalculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
介面實現類:ArithmeticCalculatorImpl.javapackage com.yuehailin.aop;
import org.springframework.stereotype.Component;
/**
* Created by yuehailin on 2018/1/31.
*/
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator{
@Override
public int add(int i, int j) {
System.out.println("the method begin");
int result = i + j;
System.out.println("the method end");
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("the method begin");
int result = i - j;
System.out.println("the method end");
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
LoggingAspect.javapackage com.yuehailin.aopxml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import java.util.Arrays;
/**
* Created by yuehailin on 2018/1/31.
*/
public class LoggingAspect {
public void beforeMethod(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" begins "+ Arrays.asList(args));
}
public void afterMethod(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" end "+ Arrays.asList(args));
}
public void afterReturning(JoinPoint joinPoint,Object result){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" end "+ result);
}
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodname = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("the method "+methodname+" occurs excepetion with "+ ex);
}
public Object aroundMethod(ProceedingJoinPoint pjd){
// 執行目標方法·
Object result =null;
String methodname = pjd.getSignature().getName();
try {
// 前置通知
System.out.println("the method "+ methodname+" begin with "+ Arrays.asList(pjd.getArgs()));
result=pjd.proceed();
// 後置通知
System.out.println("the method "+" end with "+result);
} catch (Throwable throwable) {
// 異常通知
System.out.println("異常通知"+throwable+methodname);
}
// 後置通知
System.out.println("the method end with " +methodname);
return result;
}
}
xml檔案
<?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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--配置bean-->
<bean id="arithmeticCalculator" class="com.yuehailin.aopxml.ArithmeticCalculatorImpl">
</bean>
<!--配置切面的bean-->
<bean id="loggingAspect" class="com.yuehailin.aopxml.LoggingAspect">
</bean>
<bean id="vlidationAspect" class="com.yuehailin.aopxml.VlidationAspect">
</bean>
<!--配置aop-->
<aop:config>
<!--配置切點表示式-->
<aop:pointcut id="pointcut" expression="execution(* com.yuehailin.aopxml.ArithmeticCalculator.*(int,int))"/>
<!--配置切面及通知-->
<aop:aspect ref="loggingAspect" order="2">
<!--<aop:before method="beforeMethod" pointcut-ref="pointcut"/>-->
<!--<aop:after method="afterMethod" pointcut-ref="pointcut"/>-->
<!--<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>-->
<!--<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>-->
<aop:around method="aroundMethod" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="vlidationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
測試類:
package com.yuehailin.aopxml;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by yuehailin on 2018/1/31.
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-xml.xml");
ArithmeticCalculator arithmeticCalculator = (com.yuehailin.aopxml.ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
int result = arithmeticCalculator.add(1,2);
System.out.println(result);
int result01 = arithmeticCalculator.div(1000,10);
System.out.println(result01);
}
}
說明:
①在使用aspectj相應的jar包的時候,有的時候程式碼沒有錯誤而是jar版本過老而導致錯誤。
②在使用註解的時候使用了AspectJ通知註解,需要匯入相應的jar包。
本人小白,如有錯誤,請指正。原始碼連線明天補上。