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簡單來說就是代碼的增強, 給指定的程序增加功能!!! ,通過代碼攔截器對指定類的方法增加功能!