不直接访问某个对象,而是通过代理类来提供某个对象的访问。相当于一个中介。
静态代理代理类和委托类在运行前就写死了,就是静态代理。
模拟一个静态代理,需要以下几步:
-
抽象角色,一般为接口或者抽象类。
// 租房 public interface Rent { void rent(); }
-
真实角色,具体被代理的角色
public class Host implements Rent{ @Override public void rent() { System.out.println("房东卖房"); } }
-
代理角色,代理真实角色,在代理前后我们会对其做一些处理
public class Proxy implements Rent { Rent rent; // 默认代理自己 public Proxy() { this.rent = new Proxy(); } public Proxy(Rent rent) { this.rent = rent; } @Override public void rent() { seeHouse(); rent.rent(); hetong(); } public void seeHouse() { System.out.println("中介带你看房"); } public void hetong() { System.out.println("中介和你签合同"); } }
-
客户端访问
public class Client { public static void main(String[] args) { Rent host = new Host(); Proxy proxy = new Proxy(host); proxy.rent(); } }
整个过程我们没有接触到房东,一直都是和中介接触。
动态代理就比刚刚的静态代理牛逼多了,静态代理只能写死了代理一个接口,而动态代理的代理类是动态生成的,可以代理一切。
我们可以根据不同的接口,生成不同的代理类。运用Java的反射机制,我们可以做到这一点:
-
抽象角色,被代理的接口,只能是接口。
还是先用刚刚的例子
// 租房 public interface Rent { void rent(); }
-
被代理的真实类
public class Host implements Rent { @Override public void rent() { System.out.println("房东卖房"); } }
-
代理类我们动态生成,如何根据不同的接口生成不同的代理类?
可以通过java.lang.reflect.Proxy类下的
方法来生成代理类。
ClassLoader loader:类加载器,用来加载被代理的类。
Class>[] interfaces:被代理对象的所有接口,即要生成的代理类需要实现的接口。
InvocationHandler h:调用的策略,需要传入一个实现了InvocationHandler接口的类,设置代理类调用方法的策略。
假如我要代理房东,那么房东的代理类这样生成:
Rent host = new Host(); Proxy.newProxyInstance(host.getClass().getClassLoader(),host.getClass().getInterfaces(), 策略??);
我们倒是知道了要用rent的类加载器来加载被代理的类,也知道代理类要实现Rent接口,但调用策略如何创建?
public class ProxyInvocationHandler implements InvocationHandler{ private Object target; public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } }
Object proxy:刚刚生成的代理类。
Method method:调用的方法。
Object[] args:调用的方法的参数。
target:被代理的对象。
于是:
Rent host = new Host(); ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); proxyInvocationHandler.setTarget(host); // 有了策略过后 Rent proxy = Proxy.newProxyInstance(rent.getClass().getClassLoader(),rent.getClass().getInterfaces(), proxyInvocationHandler); //就获得了代理类
-
把获得代理类方法和调用策略类合并成一个工具类(完整代码):
public class ProxyInvocationHandler implements InvocationHandler { // 被代理的类 private Object target; // 动态设置被代理的类 public void setTarget(Object target) { this.target = target; } // 动态生成代理类 public Object getProxy() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // 调用策略 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log(method.getName()); Object result = method.invoke(target, args); return result; } // 添加一个自制日志 public void log(String s) { System.out.println("调用:" + s + " 方法。"); } }
-
客户端访问
public class Client { public static void main(String[] args) { Rent host = new Host(); ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(host); Rent proxy = (Rent) pih.getProxy(); proxy.rent(); } }
结果:
-
被代理的接口
public interface UserService { // 增 int addUser(); // 删 int delete(); // 改 int update(); // 查 List<User> select(); }
-
被代理的真实类
public class UserServiceImpl implements UserService{ @Override public int addUser() { System.out.println("增"); return 0; } @Override public int delete() { System.out.println("删"); return 0; } @Override public int update() { System.out.println("改"); return 0; } @Override public List<User> select() { System.out.println("查"); return null; } }
-
工具类不变,还是刚才那个
-
客户端访问
public class Client { public static void main(String[] args) { UserService userService = new UserServiceImpl(); ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); proxyInvocationHandler.setTarget(userService); UserService proxy = (UserService) proxyInvocationHandler.getProxy(); proxy.addUser(); proxy.delete(); proxy.update(); proxy.select(); } }
结果:
有了代理模式的基础,走向AOP就容易的多。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)