1. 程式人生 > >spring AOP的XML開發

spring AOP的XML開發

一.什麼是AOP?

面向切面程式設計,通過預編譯方式和執行期動態代理實現程式功能的統一維護的技術

AOP是OOP的延續,是軟體開發中的熱點,也是spring框架中的重要內容,是函數語言程式設計的一種衍生範型

利用AOP可以對業務各個部分進行隔離,從而使業務各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率

AOP是OOP的擴充套件和延伸,解決OOP開發遇到的問題

可以通過預編譯和執行期動態代理實現不修改原始碼情況下給程式新增功能

二.AOP和OOP的區別

OOP面向名詞領域,AOP面向動詞領域

OOP針對業務處理過程的實體及其屬性和行為進行抽象封裝,以獲得更加高效清晰的邏輯單元劃分]

而AOP是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,降低各部分耦合度

三.為什麼學習AOP?

對程式進行增強,在不修改原始碼情況下,AOP可以進行許可權校驗,日誌記錄,效能監控,事務控制

四.AOP的由來

1.AOP最早是由AOP聯盟提出的,制定了一套規範,spring將AOP思想引入框架中,必須遵守AOP聯盟的規範

spring的AOP有自己的實現方式(非常繁瑣)

AspectJ是一個AOP的框架,spring引入AspectJ作為自身的AOP開發

2.spring的兩套AOP開發

(1)spring傳統方式(棄用)

(2)spring基於AspectJ的AOP的開發(使用)

五.AOP底層實現

動態代理

1.JDK動態代理

只能對實現介面的類進行代理

(1)介面

public interface UserDao {
    void add();
    void delete();
    void update();
    void find();
}

(2)介面實現類

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("add...");
    }

    @Override
    public void delete() {
        System.out.println("delete...");
    }

    @Override
    public void update() {
        System.out.println("update...");
    }

    @Override
    public void find() {
        System.out.println("find...");
    }
}

(3)進行動態代理

對delete()方法進行動態代理

public class JdkProxy implements InvocationHandler {

    //被代理類
    private UserDao userDao;

    public JdkProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    //返回代理物件
    public UserDao createProxy(){
        UserDao proxy = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //代理物件   正在執行的方法    引數
        //要代理的方法
        if("delete".equals(method.getName())){
            System.out.println("代理...");
            return method.invoke(userDao,args);
        }
        return method.invoke(userDao,args);
    }
}

(4)測試

 public static void main(String[]args){
        //jdk動態代理
        UserDao userDao=new UserDaoImpl();
        UserDao proxy=new JdkProxy(userDao).createProxy();
        proxy.delete();
    }

2.Cglib動態代理

可以對沒有實現介面的類進行動態代理

spring AOP 內部會自動判斷有沒有實現介面,進而選擇JDK動態代理或是Cglib動態代理自動實現動態代理

六.AOP開發中的相關術語

七.AOP入門示例

(1)編寫目標類

public interface ProductDao {
    void add();
    void delete();
    void update();
    void find();
}

(2)編寫實現類

public class ProductImpl implements ProductDao{
    @Override
    public void add() {
        System.out.println("add..商品");
    }

    @Override
    public void delete() {
        System.out.println("delete..商品");
    }

    @Override
    public void update() {
        System.out.println("update..商品");
    }

    @Override
    public void find() {
        System.out.println("find..商品");
    }
}

(3)在xml中配置目標物件

   <!--配置目標物件,將要增強的類交給spring管理-->
  <bean id="ProductDao" class="org.qingyu.dao.ProductImpl"></bean>

  <!--將切面類交給spring管理-->
  <bean id="MyAspect" class="org.westos.service.MyAspect"></bean>

  <!--通過AOP的配置完成對目標類產生代理-->

  <aop:config>
    <!--表示式配置哪些類的那些方法需要增強-->
    <aop:pointcut id="pointcut1" expression="execution(* org.qingyu.dao.ProductImpl.add(..))"></aop:pointcut>

    <!--配置切面-->
    <aop:aspect ref="MyAspect">
      <aop:before method="checkPri" pointcut-ref="pointcut1"></aop:before>
    </aop:aspect>

  </aop:config>


</beans>

(4)編寫測試類

public static void main(String[]args){

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        ProductDao productDao = (ProductDao) applicationContext.getBean("ProductDao");
        productDao.add();
    }

八.spring中通知型別

1.前置通知

在目標方法之前執行

可以獲得切入點的資訊

<aop:aspect ref="MyAspect">
      <aop:before method="checkPri" pointcut-ref="pointcut1"></aop:before>
    </aop:aspect>
//切面類
public class MyAspect {
    public void checkPri(JoinPoint joinPoint){
        System.out.println("許可權校驗--------"+joinPoint);
    }
}

輸出結果如下:

許可權校驗--------execution(void org.westos.dao.ProductDao.add()) add..商品

2.後置通知

在目標方法之後執行

可以獲得方法的返回值

注意:returning的值要和方法中Object  result名一致

<!--後置通知-->
     <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"></aop:after-returning>
 public void writeLog(Object result){
        System.out.println("日誌.."+result);
    }

輸出結果如下:

delete..商品 日誌..hahahaha  

3.環繞通知

在目標方法之前和之後執行

<!--環繞通知-->
      <aop:around method="around" pointcut-ref="pointcut3"></aop:around>

切面類

public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞前通知");
        Object obj = proceedingJoinPoint.proceed();//相當於執行目標程式
        System.out.println("環繞後通知");
        return obj;
    }

輸出結果如下:

環繞前通知 find..商品 環繞後通知

4.異常丟擲通知

程式中出現異常時進行的操作

5.最終通知

無論方法是否有異常,最終都會被執行

6.引介通知

九.切入點表示式語法

基於execution函式完成的

語法:[訪問修飾符] 方法返回值  包名.類名.方法名(引數)

public  void  org.qingyu.dao.UserDao.add(..)

 * *.*.*.dao.add(..)                                         所有dao裡面的add()都可以被增強

*org.qingyu.dao.UserDao+.add(..)               當前類及其子類裡面的add()都可以被增強

*org.qingu.dao..*.*(..)                                   當前包下的所有類的所有方法都可以被增強