首先,我们先讲一下为什么要用代理模式。举个例子,在我们的项目开发中,除了有业务模块,还有公共领域模块,比如权限校验、日志处理等。
如果我们在业务模块中想要实现添加用户的功能,而且还想知道是谁添加了用户,我们该怎么去实现我们的代码呢?直接在service层去修改代码吗?这样会导致公共模块与业务模块掺杂在一起了,如果以后我们不想要这部分公共模块了,我们还需要去业务模块中去修改代码,这不利于程序的升级维护。
那我们应该怎么做呢?这就需要用到代理模式了。
代理分为静态代理与动态代理。
静态代理
我们先来实现一个简单的静态代理,下面的代码是我们的业务模块,称之为真实角色,我们要为其添加一个代理角色。
public class TestService {
public void addUser() {
System.out.println("用户添加");
}
public void queryUser(String name,String adress) {
System.out.println("查询用户"+name+"地址"+adress);
}
}
代理角色的代码实现如下,logger方法可以理解为我们的公共模块,在这个类中我们维护了一个真实角色的对象,然后将公共模块添加进代理角色实现的方法中。我们应该保持真实角色与代理角色的方法名一致,这可以通过实现共同的接口来完成。
/*
* 静态代理类
*/
private TestService service = new TestService();
private void logger() {
System.out.println("某人执行了添加操作");
}
public void addUser() {
this.logger();
this.service.addUser();
}
public void queryUser(String name,String adress) {
// TODO Auto-generated method stub
this.service.queryUser(adress, adress);
}
既然静态代理就可以实现我们的功能了,为什么还会用动态代理呢?大家想一下,如果我们的真实角色非常多的话,即业务模块特别多,相应的代理角色也会增多,这使得我们编写代码特别麻烦,所以我们就需要通过动态代理来生成代理角色。
动态代理
动态代理会在运行过程中自动生成一个代理类,而不需要我们手动编写。
动态代理实现方法有两种。一是基于jdk的动态代理,面向接口来实现,二是基于cglib的动态代理,面向抽象类来实现。
实现动态代理需要两个类,Proxy与InvocationHandler。
Proxy提供了创建动态代理类(getProxyClass)和代理对象(newProxyInstance)的静态方法。
我们接下来简单实现一个基于jdk的动态代理。
public class ProxyFactory<T> {
public T getProxyObj(Object obj) {
//obj为要实现代理类的真实角色
Class clazz = obj.getClass();
ClassLoader loader = clazz.getClassLoader();
Class[] interfaces = clazz.getInterfaces();
T proxyObj = (T) Proxy.newProxyInstance(loader, interfaces, getHandler(obj));
return proxyObj;
}
public InvocationHandler getHandler(final Object obj) {
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("動態代理");
method.invoke(obj, args);
return null;
}
};
return handler;
}
}
CLassLoader指定生成动态代码类的类加载器。
interface用来指定要生成哪个接口的代理类。
InvocationHandler用来控制原始方法的执行,实现对原始方法的增强。
接口中定义的所有方法,一旦执行,就转换成InvocationHandler的invoke方法来执行。
在invoke中通过反射来调用原方法。