Java 中的代理模式详解及实例代码
这里有新鲜出炉的 Java 函数式编程, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要介绍了 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");
- }
- }
来源: http://www.phperz.com/article/18/0206/358611.html