基于代理是一项非常经典的具有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方法。