澳门新浦京app下载Java反射机制详解(二)

澳门新浦京app下载 1

要想精晓Java动态代理,首先要打听哪些叫做代理,熟习设计情势的朋友一定知道在Gof计算的23种设计形式中,有一种名称叫代理(Proxy卡塔尔(قطر‎的对象构造型方式,动态代理中的代理,指的就是这种设计格局。

本篇随笔继续介绍Java反射机制,差别的是重视于介绍动态代理。动态代理是代理方式中的一种,是经过Java反射机制来促成的。由此本篇文章先介绍代理情势,然后介绍Java反射机制与动态代理。

参照链接:http://www.jianshu.com/p/3ad3fb560ca1

以小编之见所谓的代办形式,和23种设计情势中的“装饰形式”是多少个事物。23种设计情势上将它们作为二种格局,英特网也可以有个别文章讲这二种格局的异同,从细节来看,确实能够人工地区分那三种格局,不过抽象到一定中度后,笔者认为那三种格局是点点滴滴等同的。因而学会了代办情势,也就同不常控了装修格局。

一、代理形式

定义:给某些对象提供一个代理对象,并由代理对象说了算对于原对象的走访,即顾客不直接操控原对象,而是经过代理对象直接地操控原对象。

第一看调用格局:
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxyHandler(realSubject);
Subject subject =
(Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject
.getClass().getInterfaces(), handler);
通过Proxy的
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h);
函数中调用getProxyClass函数,动态变化三个RealSubject类相关的.Class类,newProxyInstance函数军长handler作为回调传递步向,里面调用Proxy类中的static的invoke回调出来也正是到RealSubject的invoke方法中,做一些外加的事情。

代办情势

代办方式差不离来讲,正是对多少个对象举行打包,包装后生成的对象具备和原对象相近的方法列表,但是各种方法都足以是棉被服装进过的。

1、代理格局的精通

代办方式应用代理对象达成客户诉求,屏蔽客商对真实对象的拜见。现实世界的代理人被授权执行当事人的局地事儿,没有必要当事人出面,从第三方的角度看,犹如当事人并荒诞不经,因为他只和代表通讯。而实质上代理人是要有当事人的授权,並且在核心难题上还索要报告请示当事人。
在软件设计中,使用代理形式的计划也超多,举例因为安全原因须要隐瞒客商端直接采访真正对象,也许在长途调用中需求利用代理类管理远程方法调用的本事细节,也说倒霉为了升高系统特性,对实在对象开展打包,进而达到延迟加载的指标。

// 代理对象是足以体系化
public class Proxy implements Serializable {
一、定义的变量:
1、private static final long serialVersionUID = -2222568056686623797L;
serialVersionUID的作用:
经过判别实体类的serialVersionUID来验证版本一致性的。在进行反类别化时,JVM会把传播的字节流中的serialVersionUID与本地相应实体类的serialVersionUID实行相比较,假诺相仿就觉着是平等的,能够进行反系列化,否则就能够并发类别化版本不平等的特别。
生成实体类的serialVersionUID方法:1、写上暗许的1L,比如:private static
final long serialVersionUID = 1L; 2、用idea自动生成。

静态代理

让我们先来看一段代码:

package common;

public class Test {
    static interface Subject{
        void sayHi();
        void sayHello();
    }

    static class SubjectImpl implements Subject{

        @Override
        public void sayHi() {
            System.out.println("hi");
        }

        @Override
        public void sayHello() {
            System.out.println("hello");
        }
    }

    static class SubjectImplProxy implements Subject{
        private Subject target;

        public SubjectImplProxy(Subject target) {
            this.target=target;
        }

        @Override
        public void sayHi() {
            System.out.print("say:");
            target.sayHi();
        }

        @Override
        public void sayHello() {
            System.out.print("say:");
            target.sayHello();
        }
    }

    public static void main(String[] args) {
        Subject subject=new SubjectImpl();
        Subject subjectProxy=new SubjectImplProxy(subject);
        subjectProxy.sayHi();
        subjectProxy.sayHello();
    }
}

这段代码中首先定义了二个Subject接口,接口中有七个方式。

然后定义了SubjectImpl类实现Subject接口并落实在那之中的四个艺术,到此处一定是没难题的。

今昔再定义叁个SubjuectImplProxy类,也兑现Subject接口。这一个SubjectImplProxy类的效用是包装SubjectImpl类的实例,它的当中定义三个变量target来保存三个SubjectImpl的实例。SubjectImplProxy也落到实处了接口规定的多少个措施,而且在它的落成版本中,都调用了SubjectImpl的贯彻,可是又加多了同心同德的管理逻辑。

信赖这段代码轻松掌握,它经过对SubjectImpl实行李包裹装,达到了给输出内容充分前缀的效应。这种代理格局叫做静态代理。

2、代理方式的加入者

代办格局的角色分两种:

澳门新浦京app下载 1

大旨接口: Subject
是寄托对象和代理对象都合作完成的接口,即代理类的所完成的行事接口。Request()是委托对象和代办对象协同享有的办法。
对象对象:ReaSubject 是原对象,也正是被代理的目的。
**代理对象: **Proxy 是代理对象,用来封装真是大旨类的代理类。
客户端 :动用代理类和大旨接口实现都部队分干活。

// maps class loaders to created classes by interface names
/** 将代理类 加载器放在Proxy的maps构造中缓存起来 */
2、private static final Map<ClassLoader, Map<String,
WeakReference<Class<?>>>> loaderCache = new
WeakHashMap<ClassLoader, Map<String,
WeakReference<Class<?>>>>();

动态代理

从上边的演示中大家简单看出静态代理的瑕玷:大家对SubjectImpl的多少个措施,是进展的一模一样的卷入,然则却要在SubjectImplProxy里把相近的包裹逻辑写四次,並且事后只要Subject接口再加多新的方式,SubjectImplProxy也务需要增加新的达成,固然SubjectImplProxy对全数办法的包裹或许都是平等的。

上边作者把下面例子的静态代理改成动态代理,大家来看一下区分:

package common;

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

public class Test {
    static interface Subject{
        void sayHi();
        void sayHello();
    }

    static class SubjectImpl implements Subject{

        @Override
        public void sayHi() {
            System.out.println("hi");
        }

        @Override
        public void sayHello() {
            System.out.println("hello");
        }
    }

    static class ProxyInvocationHandler implements InvocationHandler{
        private Subject target;
        public ProxyInvocationHandler(Subject target) {
            this.target=target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.print("say:");
            return method.invoke(target, args);
        }

    }

    public static void main(String[] args) {
        Subject subject=new SubjectImpl();
        Subject subjectProxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxyInvocationHandler(subject));
        subjectProxy.sayHi();
        subjectProxy.sayHello();

    }
}

只看main方法的话,独有第二行和事情发生前的静态代理分歧,同样是生成壹个subjectProxy代理对象,只是生成的代码差别了。静态代理是直接new
叁个SubjectImplProxy的实例,而动态代理则调用了java.lang.reflect.Proxy.newProxyInstance(卡塔尔(قطر‎方法,咱们来看一下那么些主意的源码:

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass(loader, interfaces);  //获取代理类的Class

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            Constructor cons = cl.getConstructor(constructorParams);  //constructorParams是写死的:{ InvocationHandler.class },上边返回的代理类Class一定是extends Proxy的,而Proxy有一个参数为InvocationHandler的构造函数
            return cons.newInstance(new Object[] { h });  //这里通过构造函数将我们自己定义的InvocationHandler的子类传到代理类的实例里,当我们调用代理类的任何方法时,实际上都会调用我们定义的InvocationHandler子类重写的invoke()函数
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        } catch (IllegalAccessException e) {
            throw new InternalError(e.toString());
        } catch (InstantiationException e) {
            throw new InternalError(e.toString());
        } catch (InvocationTargetException e) {
            throw new InternalError(e.toString());
        }
    }

上面的 Class<?> cl = getProxyClass(loader, interfaces);
 调用的getProxyClass方法:

public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
        throws IllegalArgumentException
    {
        if (interfaces.length > 65535) {  //因为在class文件中,一个类保存的接口数量是用2个字节来表示的,因此java中一个类最多可以实现65535个接口
            throw new IllegalArgumentException("interface limit exceeded");
        }

        Class<?> proxyClass = null;

        /* collect interface names to use as key for proxy class cache */
        String[] interfaceNames = new String[interfaces.length];

        // for detecting duplicates
        Set<Class<?>> interfaceSet = new HashSet<>();
     //验证interfaces里的接口是否能被类加载器加载,是否是接口,是否有重复的 
        for (int i = 0; i < interfaces.length; i++) {
            /*
             * Verify that the class loader resolves the name of this
             * interface to the same Class object.
             */
            String interfaceName = interfaces[i].getName();
            Class<?> interfaceClass = null;
            try {
                interfaceClass = Class.forName(interfaceName, false, loader);
            } catch (ClassNotFoundException e) {
            }
            if (interfaceClass != interfaces[i]) {
                throw new IllegalArgumentException(
                    interfaces[i] + " is not visible from class loader");
            }

            /*
             * Verify that the Class object actually represents an
             * interface.
             */
            if (!interfaceClass.isInterface()) {
                throw new IllegalArgumentException(
                    interfaceClass.getName() + " is not an interface");
            }

            /*
             * Verify that this interface is not a duplicate.
             */
            if (interfaceSet.contains(interfaceClass)) {
                throw new IllegalArgumentException(
                    "repeated interface: " + interfaceClass.getName());
            }
            interfaceSet.add(interfaceClass);

            interfaceNames[i] = interfaceName;
        }

        /*
         * Using string representations of the proxy interfaces as
         * keys in the proxy class cache (instead of their Class
         * objects) is sufficient because we require the proxy
         * interfaces to be resolvable by name through the supplied
         * class loader, and it has the advantage that using a string
         * representation of a class makes for an implicit weak
         * reference to the class.
         */
        List<String> key = Arrays.asList(interfaceNames);  //使用interfaces列表作为key缓存在cache里,也就是实现了相同interfaces的代理类只会创建加载一次

        /*
         * Find or create the proxy class cache for the class loader.
         */
        Map<List<String>, Object> cache;
        synchronized (loaderToCache) {
            cache = loaderToCache.get(loader);
            if (cache == null) {
                cache = new HashMap<>();
                loaderToCache.put(loader, cache);
            }
            /*
             * This mapping will remain valid for the duration of this
             * method, without further synchronization, because the mapping
             * will only be removed if the class loader becomes unreachable.
             */
        }

        /*
         * Look up the list of interfaces in the proxy class cache using
         * the key.  This lookup will result in one of three possible
         * kinds of values:
         *     null, if there is currently no proxy class for the list of
         *         interfaces in the class loader,
         *     the pendingGenerationMarker object, if a proxy class for the
         *         list of interfaces is currently being generated,
         *     or a weak reference to a Class object, if a proxy class for
         *         the list of interfaces has already been generated.
         */
     //看看缓存里有没有,如果有就直接取出来然后return,否则判断根据pendingGenerationMarker判断是否有其它线程正在生成当前的代理类,如果有则cache.wait()等待,如果没有则创建。
        synchronized (cache) {
            /*
             * Note that we need not worry about reaping the cache for
             * entries with cleared weak references because if a proxy class
             * has been garbage collected, its class loader will have been
             * garbage collected as well, so the entire cache will be reaped
             * from the loaderToCache map.
             */
            do {
                Object value = cache.get(key);
                if (value instanceof Reference) {
                    proxyClass = (Class<?>) ((Reference) value).get();
                }
                if (proxyClass != null) {
                    // proxy class already generated: return it
                    return proxyClass;
                } else if (value == pendingGenerationMarker) {
                    // proxy class being generated: wait for it
                    try {
                        cache.wait();
                    } catch (InterruptedException e) {
                        /*
                         * The class generation that we are waiting for should
                         * take a small, bounded time, so we can safely ignore
                         * thread interrupts here.
                         */
                    }
                    continue;
                } else {
                    /*
                     * No proxy class for this list of interfaces has been
                     * generated or is being generated, so we will go and
                     * generate it now.  Mark it as pending generation.
                     */
                    cache.put(key, pendingGenerationMarker);
                    break;
                }
            } while (true);
        }
     //确认要生成的代理类所属的包,如果interfaces里所有接口都是public的,代理类所属包就是默认包;如果有interface不是public,那么所有不是public的interface必须在一个包里否则报错。
        try {
            String proxyPkg = null;     // package to define proxy class in

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (int i = 0; i < interfaces.length; i++) {
                int flags = interfaces[i].getModifiers();
                if (!Modifier.isPublic(flags)) {
                    String name = interfaces[i].getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {     // if no non-public proxy interfaces,
                proxyPkg = "";          // use the unnamed package
            }

            {
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num;
                synchronized (nextUniqueNumberLock) {
                    num = nextUniqueNumber++;
                }
                String proxyName = proxyPkg + proxyClassNamePrefix + num;  //生成代理类的名字,proxyPkg是上面确定下来的代理类所在的包名,proxyClassNamePrefix是写死的字符串“$Proxy”,num是一个全局唯一的long型数字,从0开始累积,每次生成新的代理类就+1,从这里也能看出生成的动态代理类的数量不能超过Long.maxValue
                /*
                 * Verify that the class loader hasn't already
                 * defined a class with the chosen name.
                 */

                /*
                 * Generate the specified proxy class.
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces);  //生成一个以proxyName为类名的,实现了Interfaces里所有接口的类的字节码
                try {
                    proxyClass = defineClass0(loader, proxyName,
                        proxyClassFile, 0, proxyClassFile.length);  //加载生成的类
                } catch (ClassFormatError e) {
                    /*
                     * A ClassFormatError here means that (barring bugs in the
                     * proxy class generation code) there was some other
                     * invalid aspect of the arguments supplied to the proxy
                     * class creation (such as virtual machine limitations
                     * exceeded).
                     */
                    throw new IllegalArgumentException(e.toString());
                }
            }
            // add to set of all generated proxy classes, for isProxyClass
            proxyClasses.put(proxyClass, null);

        } finally {
            /*
             * We must clean up the "pending generation" state of the proxy
             * class cache entry somehow.  If a proxy class was successfully
             * generated, store it in the cache (with a weak reference);
             * otherwise, remove the reserved entry.  In all cases, notify
             * all waiters on reserved entries in this cache.
             */
       //创建成功,则将cache中该key的pendingGenerationMarker替换为实际的代理类的弱引用,否则也要清除pendingGenerationMarker标记;不管是否成功,都要执行cache.notifyAll(),让其它要创建相同代理类并且执行了cache.wait()的线程恢复执行。

            synchronized (cache) {
                if (proxyClass != null) {
                    cache.put(key, new WeakReference<Class<?>>(proxyClass));
                } else {
                    cache.remove(key);
                }
                cache.notifyAll();
            }
        }
        return proxyClass; //最后返回代理类Class
    }

到这里,大家已经把动态代理的java源代码都剖析完了,以后思路就很明显了:

Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h卡塔尔(قطر‎ 方法简便来讲试行了以下操作:

1.生成多个实现了参数interfaces里有着接口且一而再再而三了Proxy的代理类的字节码,然后用参数里的classLoader加载那几个代理类。

2.接纳代理类父类的布局函数 Proxy(InvocationHandler
h卡塔尔国来创设一个代理类的实例,将我们自定义的InvocationHandler的子类传入。

3.回到这几个代理类实例,因为大家组织的代理类完成了interfaces(也正是我们前后相继中传播的subject.getClass(卡塔尔.getInterfaces(State of Qatar)里的全数接口,由此回到的代理类能够强转成Subject类型来调用接口中定义的艺术。

现今大家通晓了用Proxy.newProxyInstance(卡塔尔重临的subjectProxy能够成功强转成Subject类型来调用接口中定义的办法了,那么在调用方法后,代理类实例怎么开展拍卖的吗,那就需求看一下代理类的源码了。可是代理类是程序动态生成字节码加载的,怎么看源码呢?无妨,能够在main方法中参加System.getProperties(卡塔尔(قطر‎.put(“sun.misc.ProxyGenerator.saveGeneratedFiles”,”true”卡塔尔(قطر‎,那样就能够把变化的代办类Class文件保留在本土磁盘上,然后再反编写翻译可以拿走代理类的源码:

package common;

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 Test.Subject
{
  private static Method m4;
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  static
  {
      try {
          m4 = Class.forName("Test$Subject").getMethod("sayHello", new Class[0]);
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m3 = Class.forName("Test$Subject").getMethod("sayHi", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
  }

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

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

  public final boolean equals(Object paramObject)
  {
    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 sayHi()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
        throw new UndeclaredThrowableException(localThrowable);
    }
  }

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

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

大家得以见到代理类内部得以达成比较简单,在调用每种代理类每一个方法的时候,都用反射去调h的invoke方法(也正是大家自定义的InvocationHandler的子类中重写的invoke方法State of Qatar,用参数传递了代理类实例、接口方法、调用参数列表,这样大家在重写的invoke方法中就能够兑现对持有办法的归拢包装了。

3、代理格局的分类

代理的达成分为:

静态代理:代理类是在编写翻译时就兑现好的。也正是说 Java
编写翻译完成后代理类是一个其实的 class 文件。
动态代理:代理类是在运行时生成的。也正是说 Java
编写翻译完之后并从未实际的 class
文件,而是在运行时动态变化的类字节码,并加载到JVM中。

/** 全体代理类的联谊,用于isProxyClass方法的兑现 */
3、private static final Map<Class<?>, String> proxyCache =
new WeakHashMap<Class<?>, String>();

总结

动态代理相对于静态代理在运用上的帮助和益处重若是力所能致对四个对象的具备办法开展统一包装,何况前期被代理的类增多方法的时候动态代理类没有必要改动。

弱点是讲求被代理的类必需贯彻了接口,因为动态代理类在得以完结的时候世袭了Proxy类,java不扶植多三回九转,因而动态代理类只好依据接口来定义方法。

终极动态代理之所以称为动态代理是因为java在促成动态代理的时候,动态代理类是在运行时动态变化和加载的,绝没错,静态代理类和任何普通类一下,在类加载阶段就加载了。

4、代理形式的贯彻思路

1.代理对象和指标对象均落实同二个作为接口。

2.代理类和指标类分别实际贯彻接口逻辑。

3.在代理类的构造函数中实例化三个对象对象。

4.在代理类中调用指标对象的一言一动接口。

5.顾客端想要调用目标对象的一颦一笑接口,只好通过代理类来操作。

4、private static int NextClassNameIndex = 0;///**
下一个用来转移独一代理类名字的数字 */

5、静态代理格局的大致完成
public class ProxyDemo {
    public static void main(String args[]){
        RealSubject subject = new RealSubject();
        Proxy p = new Proxy(subject);
        p.request();
    }
}

interface Subject{
    void request();
}

class RealSubject implements Subject{
    public void request(){
        System.out.println("request");
    }
}

class Proxy implements Subject{
    private Subject subject;
    public Proxy(Subject subject){
        this.subject = subject;
    }
    public void request(){
        System.out.println("PreProcess");
        subject.request();
        System.out.println("PostProcess");
    }
}

目的对象(RealSubject
State of Qatar以至代理对象(Proxy)都落到实处了主旨接口(Subject)。在代理对象(Proxy)中,通过布局函数字传送入指标对象(RealSubject
State of Qatar,然后重写主旨接口(Subject)的request(卡塔尔国方法,在该措施中调用指标对象(RealSubject
卡塔尔国的request(卡塔尔(قطر‎方法,并可以加上一些外加的处监护人业在对象对象(RealSubject
State of Qatar的request(卡塔尔方法的左右。

代理情势的益处:

假设有那样的必要,要在有些模块方法调用前后加上部分集结的光景管理操作,举个例子在加上购物车、改革订单等操作前后统魅族上登入验证与日志记录处理,该怎样贯彻?首先想到最简便易行的正是一直改过源码,在相应模块的关照措施前后增添操作。假如模块超级多,你会意识,校勘源码不唯有丰富麻烦、难以保证,何况会使代码显得拾贰分交汇。

那时候就轮到代理方式上台了,它能够在被调用方法前后加上自身的操作,而无需更改被调用类的源码,大大地回降了模块之间的耦合性,呈现了特大的优势。

静态代理比较容易,下边包车型地铁简易实例便是静态代理的选取措施,上边介绍本篇小说的宗旨:动态代理。

/**
 * The invocation handler on which the method calls are dispatched.
 * 代理实例的invocationHandler对象
 */

二、Java反射机制与动态代理

动态代理的思绪和上述思路一样,下边首要批注怎么样落成。

5、protected InvocationHandler h;

1、动态代理介绍

动态代理是指在运作时动态变化代理类。即,代理类的字节码就要运营时生成并载入当前代理的
ClassLoader。与静态管理类相比,动态类有好多实惠。

①不要求为(RealSubject
卡塔尔(قطر‎写三个试样上完全相通的封装类,要是主旨接口(Subject)中的方法超多,为每一个接口写二个代理方法也很麻烦。如若接口有转移,则目的对象和代理类都要更改,不方便人民群众系统爱戴;

②行使一些动态代理的浮动方法竟然能够在运作时制定代理类的试行逻辑,从而大大提高系统的油滑。

二:定义的措施:
效果与利益类实现了InvocationHandler接口的代理类,此中重大措施有:
private Proxy(卡塔尔 {} (“unused”卡塔尔 //防止实例化
protected Proxy(InvocationHandler h卡塔尔:构造方法,用于给当中的h赋值。

2、动态代理涉及的基本点类

重在涉嫌五个类,那三个类都是java.lang.reflect包下的类,内部主要通过反射来达成的。

**java.lang.reflect.Proxy: **那是变化代理类的主类,通过 Proxy
类生成的代理类都持续了 Proxy 类。
Proxy提供了客户创立动态代理类和代理对象的静态方法,它是具备动态代理类的父类。

**java.lang.reflect.InvocationHandler:
**这里称她为”调用途理器”,它是多个接口。当调用动态代理类中的方法时,将会一贯转接到推行自定义的InvocationHandler中的invoke(State of Qatar方法。即大家动态变化的代理类必要变成的具体内容供给本人定义二个类,而以此类必需完毕InvocationHandler 接口,通过重写invoke(卡塔尔方法来施行具体内容。

Proxy提供了如下三个艺术来创设动态代理类和动态代理实例。

static Class<?> getProxyClass(ClassLoader loader,
Class<?>… interfaces卡塔尔国重临代理类的java.lang.Class对象。第一个参数是类加载器对象(即哪个类加载器来加载那些代理类到
JVM
的方法区),第二个参数是接口(申明你那几个代理类须求落到实处怎么着接口),第1个参数是调用项理器类实例(钦命代理类中现实要怎么),该代理类将得以实现interfaces所钦定的全体接口,实施代理对象的每一种方法时都会被轮流实行InvocationHandler对象的invoke方法。

static Object newProxyInstance(ClassLoader loader, Class<?>[]
interfaces, InvocationHandler h卡塔尔国 再次来到代理类实例。参数与上述措施一致。

对应上述三种艺术成立动态代理对象的措施:

        //创建一个InvocationHandler对象
        InvocationHandler handler = new MyInvocationHandler(.args..);
        //使用Proxy生成一个动态代理类
        Class proxyClass = Proxy.getProxyClass(RealSubject.class.getClassLoader(),RealSubject.class.getInterfaces(), handler);
        //获取proxyClass类中一个带InvocationHandler参数的构造器
        Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
        //调用constructor的newInstance方法来创建动态实例
        RealSubject real = (RealSubject)constructor.newInstance(handler);

        //创建一个InvocationHandler对象
        InvocationHandler handler = new MyInvocationHandler(.args..);
        //使用Proxy直接生成一个动态代理对象
        RealSubject real =Proxy.newProxyInstance(RealSubject.class.getClassLoader(),RealSubject.class.getInterfaces(), handler);

newProxyInstance那些办法其实做了两件事:第一,创设了二个新的类【代理类】,这么些类完成了Class[]
interfaces中的全部接口,并经过你钦命的ClassLoader将转移的类的字节码加载到JVM中,成立Class对象;第二,以你传入的InvocationHandler作为参数创建二个代理类的实例并赶回。

Proxy 类还应该有部分静态方法,举例:

InvocationHandler getInvocationHandler(Object proxy):收获代理对象对应的调用途理器对象。

Class getProxyClass(ClassLoader loader, Class[] interfaces):基于类加载器和兑现的接口获得代理类。

InvocationHandler 接口中有方法:

invoke(Object proxy, Method method, Object[] args)
以此函数是在代理对象调用任何一个形式时都会调用的,方法分歧会招致第二个参数method分歧,第三个参数是代理对象(表示哪个代理对象调用了method方法),第二个参数是
Method 对象(表示哪个方法被调用了),第七个参数是钦赐调用方法的参数。

static Class getProxyClass(ClassLoader loader, Class[]
interfacesState of Qatar:取得一个动态代理类的Class对象。,个中loader是类装载器,interfaces是真实类所兼有的上上下下接口的数组。
从缓存中取,若无,则调用本地点法generateProxy(name, interfaces,
loader, methodsArray, exceptionsArray卡塔尔(قطر‎;注意个中的多少个参数。

3、动态代理格局的大致完成
public class DynamicProxyDemo {
    public static void main(String[] args) {
        //1.创建目标对象
        RealSubject realSubject = new RealSubject();    
        //2.创建调用处理器对象
        ProxyHandler handler = new ProxyHandler(realSubject);    
       //3.动态生成代理对象
        Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
                                                        RealSubject.class.getInterfaces(), handler);   
        //4.通过代理对象调用方法   
        proxySubject.request();    
    }
}

/**
 * 主题接口
 */
interface Subject{
    void request();
}

/**
 * 目标对象类
 */
class RealSubject implements Subject{
    public void request(){
        System.out.println("====RealSubject Request====");
    }
}
/**
 * 代理类的调用处理器
 */
class ProxyHandler implements InvocationHandler{
    private Subject subject;
    public ProxyHandler(Subject subject){
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //定义预处理的工作,当然你也可以根据 method 的不同进行不同的预处理工作
        System.out.println("====before====");
       //调用RealSubject中的方法
        Object result = method.invoke(subject, args);
        System.out.println("====after====");
        return result;
    }
}

可以看看,大家由此newProxyInstance就时有发生了二个Subject
的实例,即代理类的实例,然后就足以经过Subject
.request(卡塔尔国,就能调用InvocationHandler中的invoke(卡塔尔国方法,传入方法Method对象,以至调用方法的参数,通过Method.invoke调用RealSubject中的方法的request(卡塔尔(قطر‎方法。相同的时间能够在InvocationHandler中的invoke(卡塔尔方法出席别的施行逻辑。

如上就是代理形式及动态代理的开始和结果。下篇作品将介绍Java反射机制与泛型。

static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler
h卡塔尔国:再次回到代理类的二个实例,再次来到后的代理类能够视作被代理类使用。
InvocationHandler.invoke的首先个参数proxy值,是newProxyInstance重返的动态代理类的实例,不是被代理的实例(下方的demo输出的className表明了那点)。
动态代理类Proxy是组成java底层贯彻的,通过纯粹的java代码达成相比较困难。
亟待java动态生成类的支撑。

依靠class在Map 中寻找是还是不是是代理类
public static boolean isProxyClass(Class<?> cl) {}

回到内定代理实例的调用项理程序。
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException {

两个 native方法
native private static Class generateProxy(String name, Class[]
interfaces,ClassLoader loader);

在变化代理类时,VM克隆该方法的陈说符。未有兑现。
native private static void constructorPrototype(InvocationHandler h);

public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxyHandler(realSubject);
Subject subject =
(Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello(“world”);
}
subject.getClass(卡塔尔国.getName(卡塔尔国打印的值是:$Proxy0

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图