Java中三种代理模式

代理模式

代理(Proxy)是一种设计模式,提供了间接对目标对象进行访问的方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能.

这就符合了设计模式的开闭原则,即在对既有代码不改动的情况下进行功能的扩展。

举个例子来说明代理的作用:明星与经纪人之间就是被代理和代理的关系,明星出演活动的时候,明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)

来解决.这就是代理思想在现实中的一个例子。

静态代理

在使用静态代理时,被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.

代码案例:

// 接口
    interface IStar {
        void sing();
    }

    // 真实对象
    class LDHStar implements IStar {
        @Override
        public void sing() {
            System.out.println("刘德华唱歌");
        }

    }

    // 代理类需要有真实对象的控制权 (引用)
    class ProxyManger implements IStar {

        // 真实对象的引用
        private IStar star;

        public ProxyManger() {
            super();
        }

        public ProxyManger(IStar star) {
            super();
            this.star = star;
        }

        @Override
        public void sing() {      System.out.println("唱歌前准备");        star.sing();       System.out.println("善后工作");        }
    }
class Test{
public static void main(String[] args) {
            // 创建明星对象
            IStar ldh = new LDHStar();
            ProxyManger proxy = new ProxyManger(ldh);
            proxy.sing();
        }
}

静态代理总结:
优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:

  因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

而动态代理方式可以解决上面的问题

动态代理

动态代理的主要特点就是能够在程序运行时JVM才为被代理对象生成代理对象。

常说的动态代理也叫做JDK代理也是一种接口代理,JDK中生成代理对象的代理类就是Proxy,所在包是java.lang.reflect

//目标类接口interface IDog{
    void run();
}
//目标类
class GunDog implements IDog{

    @Override
    public void run() {
        System.out.println("猎狗在跑");
    }
}
class DogUtils{
    public static void method1() {
        System.out.println("增强方式一");
    }

    public static void method2() {
        System.out.println("增强方式二");
    }
}
class MyInvocationHandle 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 {
            DogUtils.method1();
            method.invoke(target, args);
            DogUtils.method2();
            return null;
    }
}
    //生产代理对象的工厂
 class MyProxyFactory{
    public static Object getProxy(Object target) {
        MyInvocationHandle handle = new MyInvocationHandle();
        handle.setTarget(target);
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handle);
        return proxy;
    }
 }
public class ProxyDemo {
    public static void main(String[] args) {
      IDog dog = new GunDog();
      IDog proxy =(IDog) MyProxyFactory.getProxy(dog);
      proxy.run();
    }

}

总结:

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能使用动态代理,因此这也算是这种方式的缺陷。

Cglib代理

上面的静态代理和动态代理模式有个相同点就是都要求目标对象是实现一个接口的对象,然而并不是任何对象都会实现一个接口,也存在没有实现任何的接口的对象,

这时就可以使用继承目标类以目标对象子类的方式实现代理,这种方法就叫做:Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

使用JDK动态代理有一个限制,就是被代理的对象必须实现一个或多个接口,若想代理没有实现接口的类,就需要使用Cglib实现.

由于Cglib是第三方提供的所以使用的时候需要导入相关的jar包,有两个包如图:

代码案例:

public class CglibProxy {

    public static void main(String[] args) {

        int[] arr = new int[100000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 1000);
        }
        //实例化一个增强器,也就是cglib中的一个class generator
        Enhancer enhancer = new Enhancer();
        //设置目标类
        enhancer.setSuperclass(ArraySort2.class);
        //设置拦截对象,这里直接使用匿名内部类写法
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object object , Method method, Object[] args, MethodProxy proxy) throws Throwable {
                String sortName = method.getName();
                switch (sortName) {
                case "bubbleSort":
                    sortName = "冒泡排序";
                    break;
                case "selectSort":
                    sortName = "选择排序";
                    break;
                case "quickSort":
                    sortName = "快速排序";
                    break;
                default:
                    break;
                }
                long start = System.currentTimeMillis();
                //此处一定要使用proxy的invokeSuper方法来调用目标类的方法
                proxy.invokeSuper(object, args);
                long end = System.currentTimeMillis();
                System.out.println("本次" + sortName + "的执行时间为: " + (end -start) + "ms");
                return null;
            }

        });
        //生成代理类并返回一个实例
        ArraySort2 arraySort = (ArraySort2) enhancer.create();
        arraySort.bubbleSort(arr);
        arraySort.selectSort(arr);
        arraySort.quickSort(arr);
    }

}
class ArraySort2{
    public void quickSort(int[] arr) {
        Arrays.sort(arr);
    }
    public void selectSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = i+1; j < arr.length; j++) {
                if (arr[i] > arr[j]) {
                    int temp = 0;
                    temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
    public void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = 0;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

总结:

在Spring的AOP编程中:

如果加入容器的目标对象有实现接口,用JDK代理

如果目标对象没有实现接口,用Cglib代理。

原文地址:https://www.cnblogs.com/jie-y/p/10732347.html

时间: 2024-10-07 21:21:56

Java中三种代理模式的相关文章

Java的三种代理模式简述

本文着重讲述三种代理模式在java代码中如何写出,为保证文章的针对性,暂且不讨论底层实现原理,具体的原理将在下一篇博文中讲述. 代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展. 比如有个歌手对象叫Singer,这个对象有一个唱歌方法叫sing(). 1 public class Singer{ 2 public void sing(){ 3 System.out.println("唱一首歌"); 4 } 5 } 假如你希望,通过你的某种

Java的三种代理模式

1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法 举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理

虚拟主机中三种网络模式介绍

cocos2d-x升级到3.0后变化不小,除了API的变化(主要是函数和类名称变化,以及使用了C++11的不少特性,function/bind, lamda, std::thread-),创建和编译工程也做了一些简化调整.本文主要讨论一下cocos2d-x3.0 在android平台开发的环境设置及工程创建编译流程. 1.   初始设置 除了2.x所需要的python,jdk, android sdk和ndk之外,还需要部署apache-ant. 1)      在path中设置好java环境变

详解 Java 中的三种代理模式

代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.      这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法.      举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎

详解 Java 中的三种代理模式!

作者:岑宇 https://www.cnblogs.com/cenyu/p/6289209.html 代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法. 举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的

java中三种方式获得类的字节码文件对象

package get_class_method; public class ReflectDemo { /** * @param args */ public static void main(String[] args) { getClassObject1(); getClassObject2(); getClassObject3(); } public static void getClassObject1(){ Person p = new Person(); System.out.pr

KEIL中三种编译模式以及对变量空间的影响

三条编译模式控制命令:SMALL,COMPACT,LARGE,它们对变量存储器空间的影响如下. SMALL:所有变量都被定义在8051单片机的片内RAM中,对这种变量的访问速度最快.另外,堆栈也必须位于片内RAM中,而堆栈的长度是很重要的,实际栈长取决与不同函数的嵌套深度.采用SMALL编译模式与定义变量时指定data存储器类型具有相同效果. COMPACT:所有变量被定义在分页寻址的片外XRAM中,每一页片外XRAM的长度为256字节:即所有变量存储在片外XRAM的某一页中.这时对变量的访问是

【计算机网络】关于三种网络通信模式以及java中三种通信方式的实现介绍

当前的网络中有三种通讯模式:单播.广播.组播(多播),其中的组播出现时间最晚但同时具备单播和广播的优点,最具有发展前景. 一.单播: 主机之间"一对一"的通讯模式,网络中的交换机和路由器对数据只进行转发不进行复制.如果10个客户机需要相同的数据,则服务器需要逐一传送,重复10次相同的工作.但由于其能够针对每个客户的及时响应,所以现在的网页浏览全部都是采用IP单播协议.网络中的路由器和交换机根据其目标地址选择传输路径,将IP单播数据传送到其指定的目的地. 单播的优点: 1.  服务器及时

JAVA中三种URL连接方法

Java的网络类可以让你通过网络或者远程连接来实现应用.而且,这个平台现在已经可以对国际互联网以及URL资源进行访问了.Java的URL类可以让访问网络资源就像是访问你本地的文件夹一样方便快捷.我们通过使用Java的URL类就可以经由URL完成读取和修改数据的操作.现在,我们来看一看,如何才能发挥出URL类的效力. 通过URL进行工作 通过一个URL连接,我们就可以确定资源的位置,比如网络文件.网络页面以及网络应用程序等.其中包含了许多的语法元素.举个例子来说,请看下面这个URL连接: http