Java中的代理模式详解及实例代码
java 代理模式详解
前言:
在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能。
静态代理
所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则是在程序运行时自动生成代理类。
描述起来太过抽象,看一下代码就明白是怎么回事了
main
public class main { public static void main(string[] args) { water water = new water(); waterproxy waterproxy = new waterproxy(water); waterproxy.drink(); } }
接口
//代理类与被代理类共同实现的接口 public interface drink { void drink(); }
被代理类
//被代理的类 public class water implements drink { @override public void drink() { system.out.println("drink water"); } }
代理类
//代理类 //与被代理类实现同一个接口 public class drinkproxy implements drink { private drink drinkimpl; //通过构造函数传入water对象 public drinkproxy(drink drinkimpl) { this.drinkimpl = drinkimpl; } @override public void drink() { //在执行被代理对象的方法前做一些事情 system.out.println("before drink"); //执行被代理对象的方法 drinkimpl.drink(); //在执行被代理对象的方法后做一些事 system.out.println("after drink"); } }
执行结果
before drink drink water after drink
动态代理
有时候我们只想改变代理类所代理的类,但是代理对象执行实际对象的方法前后所做的事情是一样的,正所谓铁打的代理类,流水的被代理类。而采用静态代理就只能代理实现了同一接口的类,如果要代理任意类则必须写很多重复的代理类。此时我们可以采用动态代理,java已经为实现动态代理提供了一套比较方便的工具。
java.lang.reflect.proxy类中可以动态生成代理对象的方法
/** *返回实现了指定接口的对象,调用代理对象的方法会调用 *invocationhandler的invoke方法 * * @param loader 获取代理类所使用的类加载器 * @param interfaces 代理类所要实现的接口 * @param h 实现了invocationhandler接口的对象 * @return 代理对象 */ public static object newproxyinstance(classloader loader,class<?>[] interfaces, invocationhandler h)
invocationhandler接口
/** *每个代理类都有一个关联的invocationhandler *当代理对象执行一个方法的时候会直接执行invoke方法 */ public interface invocationhandler { /** * @param 调用该方法的代理对象 * @param method 代理对象所调用的方法 * @param args 调用的方法的参数 * @return 调用的方法的返回值 */ public object invoke(object proxy, method method, object[] args) }
描述总是比较抽象,还是看实际例子比较好理解
例子
invocationhandler接口的实现类
public class commoninvocationhandler implements invocationhandler { //被代理的对象 private object proxied; public commoninvocationhandler(object proxied) { this.proxied = proxied; } @override public object invoke(object proxy, method method, object[] args) throws throwable { //在调用被代理对象的方法前做一些事情 system.out.println("before doing something"); //调用被代理对象的方法 object result = method.invoke(proxied, args); //在调用被代理对象的方法后做一些事情 system.out.println("after doing something");; return result; } }
main
public class main { public static void main(string[] args) { //被代理的对象 water water = new water(); //动态获取代理对象 drink waterproxy = (drink) proxy.newproxyinstance(water.getclass().getclassloader(), water.getclass().getinterfaces(), new commoninvocationhandler(water)); //通过代理对象调用方法 waterproxy.drink(); } }
输出结果
before doing something drink water after doing something
也可以不要具体的被代理对象,但是必须有相应的接口(没有实现接口的类可以使用cglib实现动态代理)才可以动态获取代理对象。像最近比较火的retrofit就直接通过声明好的接口使用动态代理进行网络请求。
例子
简单的模拟一下retrofit
post注解
//post请求注解 @target(elementtype.method) @retention(retentionpolicy.runtime) public @interface post { string value() default ""; }
query注解
//post请求注解 @target(elementtype.method) @retention(retentionpolicy.runtime) public @interface post { string value() default ""; }
service接口
public interface service { //用post注解声明请求的方式和相对路径 @post("/login") //@query注解声明请求的参数名 void login(@query("username")string username, @query("password")string password); }
main
public class main { public static void main(string[] args) { // 动态获取service接口的代理 service service = (service) proxy.newproxyinstance(service.class.getclassloader(), new class[] { service.class }, new invocationhandler() { @override public object invoke(object proxy, method method, object[] args) throws throwable { // 通过注解获取请求的相对路径 string retativepath = ((post) method.getannotations()[0]).value(); system.out.println("relative path: " + retativepath); // 获取参数的注解 annotation[][] parameterannotations = method.getparameterannotations(); // 通过参数的注解获取请求参数 for (int i = 0; i < parameterannotations.length; i++) { if (parameterannotations[i].length != 0) { for (int j = 0; j < parameterannotations[i].length; j++) { query query = (query) parameterannotations[i][j]; system.out.println(query.value() + ": " + args[i].tostring()); } } } return null; } }); // 调用代理对象的方法 service.login("hello", "world"); } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
下一篇: java shiro实现退出登陆清空缓存