java中的代理模式

作者: 篱开罗 | 来源:发表于2017-01-25 22:08 被阅读201次

代理模式

在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能。

静态代理

所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则是在程序运行时自动生成代理类。

描述起来太过抽象,看一下代码就明白是怎么回事了

  • 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动态代理

代理模式

相关文章

  • java代理模式的那些事

    java代理模式-登场 什么是代理模式? 代理模式是java中的一种设计模式,它其实就是设置一个中间环节来代理你要...

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • java设计模式之代理模式(静态代理)

      今天给大家分享的是java设计模式之代理模式中的静态代理模式,动态代理模式将在后面文章中给出。如有不足,敬请指...

  • Kotlin-强大的委托

    委托也叫代理,是一种可以以代理方式控制目标对象的访问,设计模式中成为-代理模式。 Java中,我们实现一个代理模式...

  • 代理模式——远程代理(Java RMI)

    代理模式——远程代理(Java RMI) @(设计模式) 一、远程代理——大使 在日常开发中,我们经常会有本地服务...

  • 连工厂模式都不知道,别说你会设计模式

    设计模式文章陆续更新 java单例模式java代理模式java状态模式 在Java面向对象编程中,我们通常会new...

  • Java代理模式之JDK动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 JDK动态代理是java.lang.reflect...

  • 静态/动态代理模式

    代理, 顾名思义就是让别人替你完成或处理事情。 在Java设计模式中,代理模式又可分为静态代理和动态代理模式。静态...

  • Spring AOP详解

    AOP AOP的实现一般都是基于 代理模式 ,在JAVA中采用JDK动态代理模式,但是我们都知道,JDK动态代理模...

  • java之代理技术

    java之代理模式 直接聊技术! 描述 代理模式是常用的java设计模式,代理类主要负责为委托类预处理消息、过滤消...

网友评论

    本文标题:java中的代理模式

    本文链接:https://www.haomeiwen.com/subject/rhhxittx.html