转载

代理模式看着一篇就够了

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要好。

原文  https://juejin.im/post/5bea7173e51d450b291bf71b
正文到此结束
Loading...