代理模式看着一篇就够了

栏目: Java · 发布时间: 5年前

内容简介:缺点:JDKcblib
public interface Person {
    String searchHouse();
}

复制代码
public class MasterProxy implements Person {

    private Person person;
    public MasterProxy(Person person) {
        this.person = person;
    }

    @Override
    public String searchHouse() {
        System.out.println("我是链家,我帮别人找房子..");
        //第一个参数是target,也就是被代理类的对象;第二个参数是方法中的参数
        String msg =  person.searchHouse();
        System.out.println("------------------------");
        System.out.println("|          |           |");
        System.out.println("|          |           |");
        System.out.println("|          |           |");
        System.out.println("|-------  -------  -----");
        System.out.println("                       |");
        System.out.println("|----------------------|");
        System.out.println("我是链家,已经找到了..");
        return msg;
    }
}
复制代码
public class ProxyTest {
    @Test
    public void testJDKObject() {

        Person person = new Master();

        MasterProxy masterProxy = new MasterProxy(person);
        String sb = masterProxy.searchHouse();
        System.out.println(sb);
    }
}

复制代码

缺点:

  1. 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。
  2. 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。增加了代码维护的复杂度。
  3. 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类

动态代理的两种方式

代理对象

public class Master implements Person{
    @Override
    public String searchHouse() {
        System.out.println("我需要找一个整租两室一厅的房子");
        return "done";
    }

    public static String pay() {
        System.out.println("我支付了");
        return "我支付了";
    }

    public final String sign() {
        System.out.println("我签约了");
        return "我签约了";
    }
}

复制代码

JDK

/**
 * 代理对象,不需要实现接口
 *
 * 代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
 * @param <T>
 */
public class HomeLineJDK<T> implements InvocationHandler {

    private Person target;
    public T createProxyInstance(Person target){
        this.target = target;
        Class clazz = target.getClass();
        //指定当前目标对象使用类加载器,获取加载器的方法是固定的
        //目标对象实现的接口的类型,使用泛型方式确认类型
        //事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
        T obj = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
      //  new ProxyClass().getClazz("jdkObject");
        return obj;
    }


    public T createProxyInstance(Class clazz){
        T obj = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        new ProxyClass().getClazz("jdkClass");
        return obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //System.out.println("我是链家,我帮别人找房子..");
        //第一个参数是target,也就是被代理类的对象;第二个参数是方法中的参数
        Object msg =  method.invoke(target, args);
        System.out.println("我是链家,已经找到了..");
        return msg;
    }
}
复制代码
  • 代理对象,不需要实现接口
  • 代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

cblib

/**
 * Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
 */
public class HomeLineCglib implements MethodInterceptor {
    private Object target;

    public <T> T createProxyInstance(T targetObject){
        this.target = targetObject;  //给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类 也就是cglib中的一个class generator
        enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        T o = (T)enhancer.create();
//        new ProxyClass().getCglibClazz(enhancer);
        return o;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是链家,我帮别人找房子..");
        //第一个参数是target,也就是被代理类的对象;第二个参数是方法中的参数
        Object msg =  methodProxy.invoke(this.target, objects);
        System.out.println("我是链家,已经找完了..");
        return msg;
    }
}

复制代码

测试:

public class InvacationTest {

    @Test
    public void testJDKObject() {
        Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
        String sb = person.searchHouse();
       // System.out.println(sb);
    }

    @Test
    public void testJDKCLass() {
        Person person1 = new HomeLineJDK<Person>().createProxyInstance(Master.class);
        String sb1 = person1.searchHouse();
        System.out.println(sb1);
    }



    @Test
    public void testCglib() {
        Master master = new Master();
        master = new HomeLineCglib().createProxyInstance(master);
        master.searchHouse();

    }

    @Test
    public void testStaticCglib() {
        Master master = new Master();
        master = new HomeLineCglib().createProxyInstance(master);
        master.pay();

    }

    @Test
    public void testFinalCglib() {
        Master master = new Master();
        master = new HomeLineCglib().createProxyInstance(master);
        master.sign();

    }
}
复制代码

获取代理对象

public class ProxyClass {

    public void getClazz(String fileName){
        String path = "D://"+fileName+".class";
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Master.class.getInterfaces());
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void getCglibClazz(Enhancer enhancer){
        String path = "D://cglib.class";
        byte[] classFile = new byte[0];
        try {
            classFile = enhancer.getStrategy().generate(enhancer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

复制代码

代理对象源码解析:

  • jdk对应的字节码对象
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import services.proxy.Person;

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String searchHouse() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("services.proxy.Person").getMethod("searchHouse");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
复制代码
  • cglib对应的字节码对象
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import services.proxy.Person;

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String searchHouse() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("services.proxy.Person").getMethod("searchHouse");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

复制代码

两种代理模式性能比较:

package services.proxy;

import org.junit.Test;

public class ProxyPerofrmanceTest {

    @Test
    public void testTime(){
        testCglibCreateTime(10000);
        testJdkCreateTime(10000);
       
        System.out.println("-------------------");
        testCglibExecuteTime(10);
        testCglibExecuteTime(100);
        testCglibExecuteTime(1000);
        testCglibExecuteTime(10000);
        testCglibExecuteTime(100000);
        testCglibExecuteTime(1000000);
        testCglibExecuteTime(10000000);
        System.out.println("-------------------");
        System.out.println("-------------------");
        testJdkExecuteTime(10);
        testJdkExecuteTime(100);
        testJdkExecuteTime(1000);
        testJdkExecuteTime(10000);
        testJdkExecuteTime(100000);
        testJdkExecuteTime(1000000);
        testJdkExecuteTime(10000000);
    }

   
    public void testJdkExecuteTime(int times){
        Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
        long jdks = System.currentTimeMillis();
        for (int i = 0;i<times;i++){
            person.searchHouse();
        }
        long jdke = System.currentTimeMillis();
        System.out.println("jdk"+times+"次执行方法处处理时间:"+(jdke-jdks));
    }
   
    public void testJdkCreateTime(int times){
        long jdks = System.currentTimeMillis();
        for (int i = 0;i<times;i++){
            Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
        }
        long jdke = System.currentTimeMillis();
        System.out.println("jkd创建代理对象"+times+"次处理时间:"+(jdke-jdks));
    }
}

复制代码

jdk和cglib第一次创建对象会将对象缓存,所以我们先创建一次去掉创建对象时间

jdk cglib
2 ms 228 ms

接下来我们看执行对应方法的耗时

次数 jdk cglib
10 0 17
100 1 0
1000 0 1
10000 2 4
100000 5 4
1000000 13 9
10000000 94 44

可以看到在创建对象并缓存到内存中的时候,cglib耗时比较jdk严重。但是在正直的执行过程中我们可以看到开始的时候jdk的性能优于cglib当达到一定调用量的时候cglib的性能较jdk要好。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

走进搜索引擎

走进搜索引擎

梁斌 / 电子工业出版社 / 2007-1 / 49.80元

《走进搜索引擎》由搜索引擎开发研究领域年轻而有活力的科学家精心编写,作者将自己对搜索引擎的深刻理解和实际应用巧妙地结合,使得从未接触过搜索引擎原理的读者也能够轻松地在搜索引擎的大厦中邀游一番。《走进搜索引擎》作为搜索引擎原理与技术的入门书籍,面向那些有志从事搜索引擎行业的青年学生、需要完整理解并优化搜索引擎的专业技术人员、搜索引擎的营销人员,以及网站的负责人等。《走进搜索引擎》是从事搜索引擎开发的......一起来看看 《走进搜索引擎》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具