jdk之深入了解动态代理

1.概念

1.如何理解代理,比如我们租房子,买房子的时候会找房屋中介人,帮忙联系;
   找对象的时候,会找媒婆或者婚介网站寻找合适的对象;
2.这里中介,媒婆等,我们可以理解为 客户提供租房|婚恋等服务,通过中介和媒婆实现客户的一些需求;
3.专业点讲,代理[代理模式]主要是为其他对象提供一种代理,以控制对其他对象相关方法的访问

2.目的

2.1.保护目标对象

2.2.增强目标对象

1.比如我们可以通过代理,统一打印请求日志等等

3.动态代理案例

3.1.案例说明

1.本案例通过以女生通过婚介中心找男生对象为例说明jdk的动态代理;

3.2.定义找对象的接口

package com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy;

public interface Person {
    void findLove();
}

3.3.Boy对象具体实现

package com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy;

import java.security.acl.Permission;

public class Boy implements Person {

    @Override
    public void findLove() {
        System.out.println("肤白");
        System.out.println("貌美");
        System.out.println("大长腿");
    }
}

3.4.创建婚介代理对象JdkHunjie

1.这里注意,jdk的代理对象,必须实现InvocationHandler类
2.before()方法和after()方法是为了增强被代理的对象,更好说明业务内容
package com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy;

import org.omg.CORBA.portable.InvokeHandler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Jdk动态代理模拟:jdk婚介所
 */
public class JdkHunjie implements InvocationHandler {

    private Object target;


    public Object getInstance(Object person){
        this.target=person;
        Class<?> clazz= person.getClass();
        //返回的是一个Class对应的实例对象即:new Person()的对象
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.before();
        Object object=method.invoke(this.target,args);
        this.after();
        return object;
    }

    private void before(){
        System.out.println("你好,我这边是珍爱网婚恋网站的客服,花花,已经拿到你得需求");
        System.out.println("开始帮你物色");
    }
    private void after(){
        System.out.println("如果合适的话,准备安排你们二人见面");
    }
}

3.5.测试

    @Test
    public  void findLoveTest(){
        Person person= (Person) new JdkHunjie().getInstance(new Boy());
        person.findLove();

       /*
       运行结果:
        你好,我这边是珍爱网婚恋网站的客服,花花,已经拿到你得需求
        开始帮你物色
        肤白
        貌美
        大长腿
        如果合适的话,准备安排你们二人见面

       */
    }

4.动态代理分析

在这里插入图片描述

1.上面这段可以看出,Person是一个代理的对象,
	会先调用JdkHunjie的invoke方法
	然后调用Boy对象的findLove方法
 @Test
    public  void sourceTest() throws IOException {
        Person person= (Person) new JdkHunjie().getInstance(new Boy());
        person.findLove();

        byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
        //在JdkHunjieTest 同级目录下面有一个文件$Proxy0 即是我们反编译后的代码
        FileOutputStream os = new FileOutputStream("/Users/gaoxinfu/Desktop/$Proxy0.class");
        os.write(bytes);
        os.close();
    }
其实在调用过程中,真正执行的对象不是person,而是生成了一个proxy对象,
这个person对象实质是通过字节码增强技术产生的一个proxy对象,具体如下:
import com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;


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

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

  public final boolean equals(Object paramObject)
    throws
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void findLove()
    throws
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String toString()
    throws
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final int hashCode()
    throws
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy.Person").getMethod("findLove", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
    }
    throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
}
1.$Proxy0 继承了 Proxy 类,同时还实现了我们的 Person 接口,而且重写了findLove()等方法。
  public final class $Proxy0 extends Proxy implements Person
2.而且在静态块中用反射查找到了目标对象的所有方法,而且保存了所有方法的引用,在重写的方法用反射调用目标对象的方法。
 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
 m3 = Class.forName("com.gaoxinfu.demo.jdk.rt.java.lang.reflect.example01jdkDynamicProxy.Person").getMethod("findLove", new Class[0]);
 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);

整体编译过程

1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口。
3、动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)。
4、编译新生成的 Java 代码.class。
5、再重新加载到 JVM 中运行。
发布了261 篇原创文章 · 获赞 37 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/u014636209/article/details/102627711
今日推荐