1. 程式人生 > >AOP的概述(7)

AOP的概述(7)

AOP

什麽是AOP?
  • AOP Aspect Oriented Programing 面向切面編程
  • AOP采取橫向抽取機制,取代了傳統縱向繼承體系重復性代碼(性能監視、事務管理、安全檢查、緩存)
  • Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期通過代理方式向目標類織入增強代碼
  • AspecJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入

AOP底層原理

就是代理機制:

  • 動態代理:(JDK中使用)
    • JDK的動態代理,對實現了接口的類生成代理.

Spring的AOP代理

  • JDK動態代理:對實現了接口的類生成代理
  • CGLib代理機制:對類生成代理

AOP的術語

  • Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點.
  • Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義.
  • Advice(通知/增強):所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
  • Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期為類動態地添加一些方法或Field.
  • Target(目標對象):代理的目標對象
  • Weaving(織入):是指把增強應用到目標對象來創建新的代理對象的過程.
  • spring采用動態代理織入,而AspectJ采用編譯期織入和類裝在期織入
  • Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類
  • Aspect(切面): 是切入點和通知(引介)的結合
解釋以上名詞:
  • joinpoit:連接點,指的是那些方法【可以】被攔截

  • pointcut:切入點,對哪些joinpoint進行攔截

  • advice:通知,指的是 【要 】增強的代碼,(方法級別的增強)

  • introduction:引介,指的是一種特殊方式的advice(類級別的增強,在原有類上添加一個屬性或者方法)

  • target:目標對象,唄增強的對象。
  • weaving(織入):是指增強(advice)應用到目標對象(targe)來創建新的代理對象的過程。
  • proxy:代理對象
  • Aspect(切面):是切入點和通知(引介)的結合(允許有多個切點和多個通知的結合)

以下是底層實現demo演示

AOP的底層實現

  • JDK動態代理(對實現接口的類進行代理):

接口類:

package cn.spring3.demo1;
/**
 * @author NOP
 * DAO接口
 */
public interface UserDao {
    public void add();
    public void update();
}

實現類:

package cn.spring3.demo1;
public class UserDaoImpl implements UserDao {
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("添加用戶");
    }
    public void update() {
        // TODO Auto-generated method stub
        System.out.println("修改用戶");
    }
}

傳統方式調用:

package cn.spring3.demo1;
import org.junit.Test;
public class SpringTest1 {
    @Test
    public void demo1() {
        UserDao userDao = new UserDaoImpl();
        userDao.add();
        userDao.update();
    }
}

如果增強add方法,怎麽做呢?
方法一:

package cn.spring3.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author NOP JDK動態類裏的機制
 * 直接實現Handler,所以JDKProxy自身就是Handler
 */
public class JDKProxy implements InvocationHandler {
    private UserDao userDao;
    public JDKProxy(UserDao userDao) {
        super();
        this.userDao = userDao;
    }
    public UserDao createProxy() {
        /**
         * invocationHandler兩種方式,一種匿名內部類的方式見JDKProxy1.java
         */
        UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass()
                .getClassLoader(), userDao.getClass().getInterfaces(), this);
        return proxy;
    }
    //調用目標對象的任何一個方法都相當於調用invoke();
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        if("add".equals(method.getName())){
            System.out.println("===日誌記錄===");
            Object result = method.invoke(userDao, args);
            return result;
        }
        return method.invoke(userDao, args);
    }
}

方法二:

package cn.spring3.demo1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author NOP JDK動態類裏的機制
 */
public class JDKProxy1 {
    private UserDao userDao;

    public JDKProxy1(UserDao userDao) {
        super();
        this.userDao = userDao;
    }

    public UserDao createProxy() {
        /**
         * invocationHandler兩種方式
         */
        UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass()
                .getClassLoader(), userDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        // TODO Auto-generated method stub
                        if (method.getName().equals("add")) {
                            System.out.println("===匿名內部類方式記錄logs日誌====");
                            Object result = method.invoke(userDao, args);
                            return result;
                        }
                        return method.invoke(userDao, args);
                    }
                });
        return proxy;
    }
}

編寫測試類
對應JDKProxy.java

@Test
    public void demo2() {
        //被代理對象
        UserDao userDao = new UserDaoImpl();
        //創建代理對象的時候傳入被代理對象
        UserDao proxy = new JDKProxy(userDao).createProxy();
        proxy.add();
        proxy.update();
    }
    測試結果:
===日誌記錄===
添加用戶
修改用戶

對應JDKProxy1.java

@Test
    public void demo3() {
        UserDao userDao = new UserDaoImpl();
        UserDao proxy = new JDKProxy1(userDao).createProxy();
        proxy.add();
        proxy.update();
    }
    測試結果:
===匿名內部類方式記錄logs日誌====
添加用戶
修改用戶

AOP的概述(7)