問題1.什麼是AOP?
AOP:面向切面編程,聽這名字完全不明白他是幹什麼用的,我們知道OOP是面向對象編程,請看下面這個案例。
public interface StudentDAO {
void save();
void delete();
void update();
void select();
}
package com.ibuyi.free.Case_three;
public class StudentDAOImpl implements StudentDAO{
@Override
public void save() {
System.out.println("學生保存方法....");
}
@Override
public void delete() {
System.out.println("學生刪除方法....");
}
@Override
public void update() {
System.out.println("學生修改方法....");
}
@Override
public void select() {
System.out.println("學生查詢方法....");
}
}
package com.ibuyi.free.Case_three;
public class Person implements StudentDAO {
@Override
public void save() {
System.out.println("普通人的保存");
}
@Override
public void delete() {
System.out.println("普通人的刪除");
}
@Override
public void update() {
System.out.println("普通人的修改");
}
@Override
public void select() {
System.out.println("普通人的查找");
}
}
如果我們想要在save()方法執行之前,想要檢查一下執行該方法用戶是否具有權限,該怎麼做呢?
第一,我們可以在該類中直接寫一個權限檢驗的方法,然後再save()執行之前進行調用。
第二,我們可以寫一個頂層的父類,在父類中寫上權限檢驗的方法,這樣子類繼承父類以後就可以直接調用該方法了。
這兩個方法有幾個問題:試想一下,如果我們的項目有成千上百個方法在執行前需要檢驗權限,那麼我們不是要在每個方法執行前添加檢驗權限的方法?這是第一種方法的缺點,第二個方法雖然用繼承的方式減去一些不必要的重複代碼,但是我們依舊要在方法之前前調用。
這時候,就有厲害的人物提出了AOP,他是OOP的一個補充,那麼AOP到底能幹什麼呢?
問題2.AOP的作用?
AOP的底層原理是動態代理,請看下面代碼
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy implements InvocationHandler {
private StudentDAO studentDAO;
public MyProxy(StudentDAO studentDAO){
this.studentDAO=studentDAO;
}
public Object CreateProxy(){
Object proxy= Proxy.newProxyInstance(studentDAO.getClass().getClassLoader(),studentDAO.getClass().getInterfaces(),this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
//如果是保存方法
System.out.println("保存之前要校驗權限");
//執行完檢驗以後,繼續回到正常的邏輯
return method.invoke(studentDAO,args);
}
return method.invoke(studentDAO,args);
}
}
該類實現了InvocationHanlder,並重寫了Invoke的方法,該類的構造方法中,需要傳入一個對象,就是需要創建代理的對象,誰需要創建代理就傳入誰,CreateProxy中調用了JDK提供的創建動態代理的方法,invoke方法中,我們進行判斷,如果代理的方法名稱是save,我們就要執行權限校驗,然後返回正常的執行邏輯。
這樣做有什麼好處呢?
@Test
public void demo1(){
//傳統方法
StudentDAO studentdao=new StudentDAOImpl();
StudentDAO proxy= (StudentDAO) new MyProxy(studentdao).CreateProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
@Test
public void demo2(){
//這裏我們的普通人在執行保存之前也需要進行校驗,需要添加任何代碼嘛?
StudentDAO studentdao=new Person();
StudentDAO proxy= (StudentDAO)new MyProxy(studentdao).CreateProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
執行結果如下:
我們只是添加了一個代理,所有實現了StudentDAO接口的類,在執行save方法之前可以使用代理類進行權限檢驗。
這裏不得不提一下,對於不使用接口的業務類,JDK無法創建動態代理,那如果我們想要代理沒有實現接口的類該怎麼做呢?這就要看CGlib了!CGlib採用非常底層的字節碼技術,可以爲一個創建子類,解決無接口代理的問題,詳細使用請看下面
package com.ibuyi.free.Case_four;
public class Product {
public void save() {
System.out.println("商品的保存");
}
public void delete() {
System.out.println("商品的刪除");
}
public void update() {
System.out.println("商品的修改");
}
public void select() {
System.out.println("商品的查找");
}
}
public class MyCGProxy implements MethodInterceptor {
private Product product;
public MyCGProxy(Product product){
this.product=product;
}
public Object createProxy(){
//1.創建核心類
Enhancer enhancer=new Enhancer();
//2.設置
enhancer.setSuperclass(product.getClass());
//3.設置回調
enhancer.setCallback(this);
//4.創建代理
Object proxy=enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("save")){
System.out.println("商品保存前需要校驗權限");
return methodProxy.invokeSuper(o,objects);
}
return methodProxy.invokeSuper(o,objects);
}
}
@Test
public void demo1(){
Product product=new Product();
MyCGProxy myCGProxy=new MyCGProxy(product);
Product proxy= (Product) myCGProxy.createProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
就這樣,就算沒有接口的業務類也能實現代理!