一、什么是代理
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
代理模式的关键点是:代理对象与目标对象,代理对象是对目标对象的扩展,并会调用目标对象
二、静态代理
简单看一个静态代理的例子
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
接口
public interface UserDao {
void save();
}
被代理对象
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存用户...");
}
}
代理对象
public class UserDaoProxy implements UserDao {
private UserDao userDao;
public UserDaoProxy(UserDao target) {
this.userDao = target;
}
@Override
public void save() {
System.out.println("保存之前的操作...");
userDao.save();
System.out.println("保存之后的操作...");
}
}
使用代理对象
/**
* @author chengxn
* @date 2019/3/28
* 静态代理优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
* 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
*/
public class StaticProxyMain {
public static void main(String[] arg){
//新建目标对象 传给代理对象 代理对象调用save(代理对象内部会调用目标对象的方法)
UserDaoProxy proxy = new UserDaoProxy(new UserDaoImpl());
proxy.save();
}
}
运行结果
三、动态代理
在动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class)
① InvocationHandler
该接口是proxy代理实例的调用处理程序实现的一个接口,
每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
我们需要实现调用处理程序的invoke方法,在方法中扩展原有方法做额外的操作(这里用到了Java反射机制)
每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用。
② Proxy
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法(返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序)。
下面看具体使用:
接口
public interface UserDao {
void save();
}
被代理对象
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存用户...");
}
}
调用处理程序
public class MyInvocationHandler implements InvocationHandler {
private Object object;
public MyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前");
method.invoke(object, args);
System.out.println("执行后");
return null;
}
}
创建代理对象并调用
public class DynamicProxyMain {
public static void main(String[] args){
UserDao userDao = new UserDaoImpl();
InvocationHandler invocationHandler = new MyInvocationHandler(userDao);
//创建代理对象
//参数详解:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
// InvocationHandler h)
//①loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
//②interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,
//如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可
//以调用接口中声明的所有方法。
//③h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个
//InvocationHandler对象上,并最终由其调用
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),invocationHandler);
proxy.save();
}
}
运行结果