基於代理是一項非常經典的具有AOP思想的實現方法,從這也產生了代理模式。代理其實就是跟委託實現同一個的接口(這是弊端,想要代理就必須有接口),其實現方式有兩種,靜態代理和動態代理。在Java中,安全、日誌、事務都是AOP應用的實際方面。
靜態代理
靜態代理的實現是指通過自己手動的生成一個代理對象,並調用代理對象的方法,靜態代理思想也很好地體現了動態代理的思想精髓。下面是一個日誌的靜態代理。
首先聲明一個接口,這個接口是委託和代理都需要實現的
public interface IDao<T extends Serializable> {
/**
* 將obj保存到數據庫表
* @param obj,要保存到數據庫的實體對象
*/
public void doSave(T obj);
}
爲了更好地模擬ORM,我們需要定義簡單的實體類
實體類接口
public interface IEntity<T extends Serializable> extends Serializable {
public T getId();
}
實體類Book
public class Book implements IEntity<Integer>{
private Integer id;
public Integer getId() {
// TODO Auto-generated method stub
return id;
}
}
定義委託——BookDao
public class BookDao implements IDao<Book> {
public void doSave(Book obj) {
// TODO Auto-generated method stub
//將對象保存到數據庫表
}
}
定義代理
public class BookDaoProxy implements IDao<Book> {
/**
* 代理依賴於委託
*/
private BookDao dao;
public BookDao getDao() {
return dao;
}
/**
* 注入委託
* @param dao,需要注入的委託實例
*/
public void setDao(BookDao dao) {
this.dao = dao;
}
public void doSave(Book obj) {
// TODO Auto-generated method stub
System.out.println("開始記錄日誌");
dao.doSave(obj);
System.out.println("結束記錄日誌");
}
}
這樣子,在實際調用的時候,調用BookDaoProxy類的doSave方法,就不僅能完成委託類的保存實體到數據庫這以功能,還能夠實現日誌記錄功能。
動態代理
動態代理的實現,是要與Java官方提供的接口InvocationHandler相關聯。
這個接口裏面有一個方法:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
其中,proxy參數是代理的實例,不要誤當做是委託實例,而method是委託的方法實例,args是方法參數,學過java反射的都知道,通過反射來調用方法method.invoke(對象實例,參數),由於沒有找到委託實例,所以在實現這個接口的時候,我們要在實現類中注入一個委託實例。
public class BookDaoProxy implements InvocationHandler {
/**
* 將要注入的委託實例
*/
private Object target;
public Object bind(Object target)
{
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("開始記錄日誌");
Object result = method.invoke(target, args);
System.out.println("結束記錄日誌");
return result;
}
}
bind方法可以根據委託來得到一個代理實例,而接口中的Invoke方法內部的實現還是主要依賴於java的反射。
BookDao bookDao = new BookDao();
BookDaoProxy proxy = new BookDaoProxy();
bookDao = (BookDao) proxy.bind(bookDao);
bookDao.doSave(new Book());
這樣,就將代理掩飾成爲委託並調用,但實際上執行了代理的doSave方法。