1. 程式人生 > 實用技巧 >Spring基礎,AOP面向切面,AOP的三種實現方式

Spring基礎,AOP面向切面,AOP的三種實現方式

1.什麼是AOP?

  為Aspect Oriented Programming的縮寫,意為:面向切面程式設計,通過預編譯方式和執行期間動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。

  

2.使用Spring API介面實現AOP  

  2.1【重點】使用AOP織入,需要匯入一個依賴包!

            <!--AOP織入包-->
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> <scope>runtime</scope> </dependency>

介面,(抽象角色),就是真實角色和代理角色都想做的事

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}

  

真實角色(介面實現類),底層

public class UserServiceImpl implements UserService{

    public void add() {
        System.out.println("增加了一個使用者");
    }

    public void delete() {
        System.out.println(
"刪除一個使用者"); } public void update() { System.out.println("修改一個使用者"); } public void select() { System.out.println("查詢一個使用者"); } }

實現AOP方式一,使用spring的API介面

代理角色,(負責代理真實角色),也在基於真實角色的前提下增加額外的操作,如需求,日誌等

如:1,前置日誌(動態代理的工具類)

public class Log implements MethodBeforeAdvice {

    //method:要執行的目標物件的方法
    //args:引數
    //target:目標物件
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName());

    }
}

  2,後置日誌(動態代理的工具類)

public class AfterLog implements AfterReturningAdvice {

    //returnValue,返回值
    public void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwable {
        System.out.println("執行了"+method.getName()+"方法,返回結果為:"+returnValue);
        System.out.println("牛逼");

    }
}

註冊機,(主要是呼叫Spring的API去實現)

   <!--方式一,通過Spring的原生API介面,-->
    <!--配置AOP,需要匯入aop的約束-->
    <aop:config>
        <!--切入點,expression:表示式,execution(要執行的位置! * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.king.service.UserServiceImpl.*(..))"/>

        <!--執行環繞增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>

    </aop:config>

單元測試

public class MyTest {
    @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //動態代理,代理的是介面
        //代理類和被代理類目的都是實現介面的,所有兩者是同級關係,不能互相強轉,只能向上轉,介面
        UserService userService = context.getBean("userService", UserService.class);
        userService.delete();
        userService.add();
    }
}

小結:動態代理,代理的是介面

   代理類和被代理類目的都是實現介面的,所有兩者是同級關係,不能互相強轉,只能向上轉,介面

擴充套件:Execution表示式,

  eg:execution(* com.king.service.UserServiceImpl.*(..)),第一個 * 代表返回型別,類後的(Impl)的 *(..)代表這個類的所有方法

    也可以寫成:execution(* com.king.service.*.*(..)),就代表 service這個包下的所有類的所有方法

AOP實現方式二,使用自定義類【主要是切面定義】

動態代理工具類

public class DiyPointCut {

    public void before(){
        System.out.println("========方法執行前=======");
    }

    public void after(){
        System.out.println("========方法執行後=======");
    }

}

註冊機配置

   <!--方式二,使用自定義類-->
    <bean id="diy" class="com.king.diy.DiyPointCut"/>

    <aop:config>
        <!--自定有切面,ref 要引用的類-->
        <aop:aspect ref="diy">
            <!--切入點-->
            <aop:pointcut id="point" expression="execution(* com.king.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config> 

方式三,註解實現AOP

動態代理工具類

//使用註解實現AOP
@Aspect //標註這個類是一個切面
public class AnnotationPointCut {

    @Before("execution(* com.king.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("==========方法執行前============");
    }

    @After("execution(* com.king.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("==========方法執行後============");
    }
}

註冊機(xml)配置

    <!--方式三,註解實現AOP-->
    <bean id="ann" class="com.king.diy.AnnotationPointCut"/>
    <!--開啟註解支援-->
    <aop:aspectj-autoproxy/>

擴充套件:JDK 和 cglib 的區別

   JDK是基於介面實現的 ,cglib是基於類的

   一般Spriong的AOP操作預設都是JDK方式,只有當把proxy-target-class="false",設定成true才能走cglib(在這個<aop:aspectj-autoproxy/>標籤下)