Spring基礎----AOP(1),JDK/CGLIB動態代理

Spring AOP(面向切面編程)

根據個人理解,AOP就是對指定的目標方法綁定各種攔截程序
如:A框架代碼是所有程序必須的 , B程序想運行,運行前A框架初始化代碼必須先運行 , B程序運行完後還需要執行A框架銷燬代碼;
如果有100個程序呢 , 那每個程序都需要寫入A 框架的初始化和銷燬程序 , 這顯然不明智
AOP出現就解決了這個問題
如下圖所示,
切面: 對目標類進行攔截後運行的程序
目標類的目標方法 : 切入點, 被切面攔截的程序
代理攔截器 : 將所有的切面和目標類引入 (所以的東西代理進來),通過構造器賦值,填充代理方法 ,
最後目標類可以通過代理攔截器產生具有切面攔截的代理對象!!!

在這裏插入圖片描述


實現代理攔截器

JDK 代理 或者CGLIB代理 動態代理實現代理攔截器
一、原理區別:

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。

而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。

1、如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP

3、如果目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

4、jdk代理 : 代理對象和目標對象實現了共同的接口
cglib代理 : 代理對象是目標對象的子類

JDK代理 - 實現動態代理攔截器

目標類

public class SalaryMainImp implements SalaryMain {
    @Override
    public void showSalary() {
        System.out.println("查看工資");
    }
}

切面攔截類

//切面
public class Logger {
    public void logger(){
        System.out.println("啓動日誌~~~~~");
    }
}

***************************************************

//切面
public class Security {
    public void security() {

        System.out.println("啓動安全框架~~~~~");
    }
}

代理攔截器

/*  代理攔截器  實現 InvocationHandler
 * 將所有的切面和目標類引入 (所以的東西代理進來)
 * 通過構造器賦值
 * 填充invoke方法
 *
 * */
public class SalaryInterceptor implements InvocationHandler {

    private Object target;  //目標類
    
    private Logger logger;  //日誌類切面
    private Security security; //安全框架類切面

    public SalaryInterceptor(Object target, Logger logger, Security security, Privilege privilege) {
        this.target = target;
        this.logger = logger;
        this.security = security;
        this.privilege = privilege;

    }

    @Override
    //整合所需切面和目標類的程序!!!
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        this.logger.logger();     //啓動日誌
        this.security.security();  //啓動安全框架
        
        method.invoke(this.target, args);  //代理目標類的方法
        
        return null;
    }
}

*************************************************************************************
*************************************************************************************

        @Test
        Logger logger = new Logger();   //創建日誌對象
        Security security = new Security();     //創建安全框架對象
      
        Object target = new SalaryMainImp(); //目標類

        //創建代理攔截器
        SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, logger, security);

        //傳入目標類裝載器,目標類接口,指定攔截器 ,生成代理對象 ,JDK代理只能用目標類接口生產代理對象!所以目標類必須是繼承一個接口!
        SalaryMain salaryMain = (SalaryMain) Proxy.newProxyInstance(target.getClass().getClassLoader(),
        
        target.getClass().getInterfaces(), salaryInterceptor);

        salaryMain.showSalary();

總結: 此爲JDK動態代理,由於目標類類型爲Object ,所以可以傳入任何目標類都能生成代理接口


CGLIB代理 - 實現動態代理攔截器

與JDK代理類似,如果切面攔截過多,可以使用集合構造

目標類

public class SalaryMainImp implements SalaryMain {
    @Override
    public void showSalary() {
        System.out.println("查看工資");
    }
}

切面攔截類

//實現 攔截器 切面總接口
public class Logger  implements Interceptor {
    @Override
    public void interceptor() {
        System.out.println("啓動日誌~~~~~");
    }
}

**********************************************

//實現 攔截器 切面總接口
public class Security implements Interceptor {
    @Override
    public void interceptor() {
        System.out.println("啓動安全框架~~~~~");

    }
}

代理攔截器

public class SalaryInterceptor implements MethodInterceptor {

    private Object target;  //目標類
    private List<Interceptor> interceptorList;  //切面集合

    public SalaryInterceptor(Object target, List<Interceptor> interceptorList) {
        this.target = target;
        this.interceptorList = interceptorList;
    }

    /*
     *產生代理對象
     * @return
     * */
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());  //設置代理對象的父類
        enhancer.setCallback(this);  //設置攔截器
        return enhancer.create();
    }


    //整合所需切面和目標類
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        //遍歷切面集合,調用每個切面的攔截方法
        for (Interceptor interceptor : interceptorList) {
            interceptor.interceptor();
        }
        method.invoke(this.target, objects);   //代理目標類的方法

        return null;
    }
}

*************************************************************************
*************************************************************************

@Test

        Logger logger = new Logger();
        Security security = new Security();
        Privilege privilege = new Privilege();
        Object target = new SalaryMainImp(); //目標類

        //將所需切面存入集合中
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(logger);
        interceptors.add(security);
        interceptors.add(privilege);

        //傳入 目標類, 切面攔截集合 ,返回代理攔截器
        SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, interceptors);


        //通過代理攔截器,創建代理對象
        SalaryMainImp salaryMain = (SalaryMainImp) salaryInterceptor.createProxy();

//        Enhancer enhancer=new Enhancer();
//        enhancer.setSuperclass(target.getClass());
//        enhancer.setCallback(salaryInterceptor);
//        SalaryMain salaryMain=(SalaryMain)enhancer.create();  這個步驟可存到代理攔截器中

        salaryMain.showSalary();
        
        /*
        在調用 show () 之前,需要啓動某些程序,框架
        這時就可以用該思想,講切面 和目標類 都進行代理 整合到一起
        * */
    }

總結 : AOP簡單來說就是代碼的增強, 給指定的程序增加功能!!! ,通過代碼攔截器對指定類的方法增加功能!

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