動(dòng)態(tài)代理

一、代理模式與靜態(tài)代理

代理模式

給某一個(gè)對象提供一個(gè)代理母债,并由代理對象控制對原對象的引用午磁。

代理模式包含如下角色:
Subject:抽象主題角色
Proxy:代理主題角色
RealSubject:真實(shí)主題角色

靜態(tài)代理

代理類在程序運(yùn)行前就已經(jīng)存在。通常情況下毡们,靜態(tài)代理中的代理類和委托類會實(shí)現(xiàn)同一接口或是派生自相同的父類迅皇。

靜態(tài)代理例子:

public class ProxyDemo {
    
    public static void main(String[] args) {
        consumer(new TargetObject());
        consumer(new SimpleProxy(new TargetObject()));
    }

    public static void consumer(Interface inter) {
        inter.doSomething();
        inter.somethingElse("Tomy");
    }

    interface Interface { //抽象主題角色
        void doSomething();
        void somethingElse(String arg);
    }

    static class TargetObject implements Interface { //真實(shí)主題角色
        public void doSomething() {
            System.out.println("target doSomething");
        }
        public void somethingElse(String arg) {
            System.out.println("target somethingElse " + arg);
        }
    }

    static class SimpleProxy implements Interface { //代理主題角色
        private Interface target;
        public SimpleProxy(Interface target) {
            this.target = target;
        }
        public void doSomething() {
            System.out.println("SimpleProxy doSomething");
            target.doSomething();
        }
        public void somethingElse(String arg) {
            System.out.println("SimpleProxy somethingElse " + arg);
            target.somethingElse(arg);
        }
    }
}

//輸出
target doSomething
target somethingElse Tomy
SimpleProxy doSomething
target doSomething
SimpleProxy somethingElse Tomy
target somethingElse Tomy

二、動(dòng)態(tài)代理

動(dòng)態(tài)代理概念

代理類在程序運(yùn)行時(shí)創(chuàng)建的方式被成為動(dòng)態(tài)代理衙熔。也就是說登颓,代理類并不是在Java代碼中定義的,而是在運(yùn)行時(shí)根據(jù)我們在Java代碼中的"指示"動(dòng)態(tài)生成的红氯。相比于靜態(tài)代理框咙,動(dòng)態(tài)代理的優(yōu)勢在于可以很方便的對代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類的函數(shù)痢甘。

動(dòng)態(tài)代理相關(guān)類和接口

java.lang.reflect.Proxy:
Java動(dòng)態(tài)代理機(jī)制的主類喇嘱,提供了一組靜態(tài)方法來為一組接口動(dòng)態(tài)地生成代理類及其實(shí)例。

Proxy的靜態(tài)方法:

//方法1: 該方法用于獲取指定動(dòng)態(tài)代理對象所關(guān)聯(lián)的調(diào)用處理器
static InvocationHandler getInvocationHandler(Object proxy)
 
//方法2:該方法用于獲取關(guān)聯(lián)于指定類裝載器和一組接口的動(dòng)態(tài)代理對象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
 
//方法3:該方法用于判斷指定類對象是否是一個(gè)動(dòng)態(tài)代理類
static boolean isProxyClass(Class cl)
 
//方法4:該方法用于為指定類裝載器塞栅、一組接口及調(diào)用處理器生成動(dòng)態(tài)代理對象
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

java.lang.reflect.InvocationHandler:
調(diào)用處理器接口者铜,它自定義了一個(gè)invoke方法题画,用于集中處理在動(dòng)態(tài)代理對象上的方法調(diào)用钝尸,通常在該方法中實(shí)現(xiàn)對委托類的代理訪問。每次生成動(dòng)態(tài)代理對象時(shí)都需要指定一個(gè)實(shí)現(xiàn)了該接口的調(diào)用處理器對象暇务。

InvocationHandler的核心方法:

//該方法負(fù)責(zé)集中處理動(dòng)態(tài)代理類上的所有方法調(diào)用砾医。
//第一個(gè)參數(shù)是代理對象拿撩,第二個(gè)參數(shù)是被調(diào)用的方法對象,第三個(gè)方法是調(diào)用參數(shù)藻烤。
//調(diào)用處理器根據(jù)這三個(gè)參數(shù)進(jìn)行預(yù)處理或分派到委托類實(shí)例上反射執(zhí)行绷雏。
Object invoke(Object proxy, Method method, Object[] args)

java.lang.ClassLoader:
類裝載器,負(fù)責(zé)將類的字節(jié)碼裝載到Java虛擬機(jī)(JVM)中并為其定義類對象怖亭,然后該類才能被使用涎显。Proxy靜態(tài)方法生成代理類同樣需要通過類裝載器來進(jìn)行裝載才能使用,它與普通類的唯一區(qū)別就是其字節(jié)碼是由JVM在運(yùn)行時(shí)動(dòng)態(tài)生成的而非預(yù)存在于任何一個(gè).class文件中兴猩。每次生成動(dòng)態(tài)代理對象時(shí)都需要指定一個(gè)類裝載器對象期吓。

動(dòng)態(tài)代理實(shí)現(xiàn)方法

方法一:

  • 步驟1:通過實(shí)現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器;
  • 步驟2:通過為Proxy類指定ClassLoader對象和一組interface來創(chuàng)建動(dòng)態(tài)代理類;
  • 步驟3:通過反射機(jī)制獲得動(dòng)態(tài)代理類的構(gòu)造函數(shù)讨勤,其唯一參數(shù)類型是調(diào)用處理器接口類型箭跳;
  • 步驟4:通過構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理對象,構(gòu)造時(shí)調(diào)用處理器對象作為參數(shù)被傳入潭千。
//InvocationHandlerImpl實(shí)現(xiàn)了InvocationHandler接口谱姓,并能實(shí)現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā)
//其內(nèi)部通常包含指向委托類實(shí)例的引用,用于真正執(zhí)行分派轉(zhuǎn)發(fā)過來的方法調(diào)用
InvocationHandler handler = new InvocationHandlerImpl(...); 
 
//通過Proxy為包括Interface接口在內(nèi)的一組接口動(dòng)態(tài)創(chuàng)建代理類的類對象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
 
//通過反射從生成的類對象獲得構(gòu)造函數(shù)對象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
 
//通過構(gòu)造函數(shù)對象創(chuàng)建動(dòng)態(tài)代理對象
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

方法二:

  • 還有更簡便的動(dòng)態(tài)代理實(shí)現(xiàn)方法刨晴,Proxy的靜態(tài)方法newProxyInstance已經(jīng)為我們封裝了步驟2到步驟4的過程屉来。
//InvocationHandlerImpl實(shí)現(xiàn)了InvocationHandler接口,并能實(shí)現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā)
InvocationHandler handler = new InvocationHandlerImpl(...); 
 
//通過Proxy直接創(chuàng)建動(dòng)態(tài)代理對象
Interface proxy = (Interface)Proxy.newProxyInstance(classLoader, new Class[] { Interface.class }, handler );

動(dòng)態(tài)代理例子:

//測試代碼
public class DynamicProxy {
    
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //保存生成的動(dòng)態(tài)代理.class文件
        
        TargetObject target = new TargetObject();
        consumer(target);
        //Insert a proxy and call again:
        Interface proxy = (Interface)Proxy.newProxyInstance(
                Interface.class.getClassLoader(),
                new Class[]{ Interface.class },
                new DynamicProxyHandler(target));
        consumer(proxy);
    }

    public static  void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("Tomy");
    }


    interface Interface { //抽象主題角色
        void doSomething();
        void somethingElse(String arg);
    }

    static class TargetObject implements Interface { //真實(shí)主題角色
        public void doSomething() {
            System.out.println("target doSomething");
        }
        public void somethingElse(String arg) {
            System.out.println("target somethingElse " + arg);
        }
    }

    static class DynamicProxyHandler implements InvocationHandler { //動(dòng)態(tài)代理處理器
        private Object target;
        public DynamicProxyHandler(Object target) {
            this.target = target;
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("InvocationHandler: " + proxy.getClass() +
                    ", method: " + method + ", args: " + args);
            if(args != null) {
                for(Object arg : args) {
                    System.out.println("InvocationHandler args: " + arg);
                }
            }
            return method.invoke(target, args);
        }
    }

}

//輸出log
target doSomething
target somethingElse Tomy
InvocationHandler: class com.tomorrow.test.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$Interface.doSomething(), args: null
target doSomething
InvocationHandler: class com.tomorrow.test.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@16d3586
InvocationHandler args: Tomy
target somethingElse Tomy

生成的動(dòng)態(tài)代理類:

package com.tomorrow.test;

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

final class $Proxy0 extends Proxy
  implements DynamicProxy.Interface
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m4;
  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 doSomething()
    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 void somethingElse(String paramString)
    throws 
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { paramString });
      return;
    }
    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.tomorrow.test.DynamicProxy$Interface").getMethod("doSomething", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.tomorrow.test.DynamicProxy$Interface").getMethod("somethingElse", new Class[] { Class.forName("java.lang.String") });
      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());
    }
  }
}

動(dòng)態(tài)代理類的繼承關(guān)系

動(dòng)態(tài)代理類的繼承關(guān)系

動(dòng)態(tài)代理對象的特點(diǎn)

  • 每個(gè)動(dòng)態(tài)代理對象都會關(guān)聯(lián)一個(gè)調(diào)用處理器對象狈癞,可以通過Proxy提供的靜態(tài)方法getInvocationHandler獲得動(dòng)態(tài)代理對象關(guān)聯(lián)的調(diào)用處理器對象茄靠。
  • 在動(dòng)態(tài)代理對象上調(diào)用其代理的接口中所聲明的方法時(shí),這些方法最終都會執(zhí)行調(diào)用處理器的invoke方法蝶桶。
  • 動(dòng)態(tài)代理類的根類java.lang.Object中有三個(gè)方法同樣會被分派到調(diào)用處理器的invoke方法中執(zhí)行慨绳,它們是hashCode、equals和toString真竖。
    可能的原因有:
    (1)因?yàn)檫@些方法為public且非final類型脐雪,能夠被代理類覆寫;
    (2)因?yàn)檫@些方法往往呈現(xiàn)出一個(gè)類的某種特征屬性恢共,具有一定的區(qū)分度喂江,所以為了保證代理類與委托類對外的一致性,這三個(gè)方法也應(yīng)該被分派到委托類執(zhí)行旁振。

動(dòng)態(tài)代理一組接口

當(dāng)動(dòng)態(tài)代理的一組接口有重復(fù)聲明的方法且該方法被調(diào)用時(shí)获询,動(dòng)態(tài)代理類總是從排在最前面的接口中獲取方法對象并分派給調(diào)用處理器,而無論動(dòng)態(tài)代理對象是否正在以該接口(或繼承于該接口的某個(gè)子接口)的形式被外部引用拐袜,因?yàn)樵趧?dòng)態(tài)代理類內(nèi)部無法區(qū)分其當(dāng)前的被引用類型吉嚣。

例子:

//測試代碼
public class DynamicProxy {
    
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //保存生成的動(dòng)態(tài)代理.class文件
        
        try {
            TargetObject object = new TargetObject();
            InvocationHandler handler = new DynamicProxyHandler(object);
            Class<?> clazz = Proxy.getProxyClass(
                    TargetObject.class.getClassLoader(),
                    new Class[] {InterfaceB.class, InterfaceA.class}); //注意:這里先寫接口B,然后寫接口A
            Constructor<?> constructor = clazz.getConstructor(new Class[] {InvocationHandler.class});
            InterfaceA proxy_a = (InterfaceA) constructor.newInstance(new Object[] {handler});
            InterfaceB proxy_b = (InterfaceB) constructor.newInstance(new Object[] {handler});
            
            proxy_a.doSomething();
            proxy_a.doA();
            proxy_b.doSomething();
            proxy_b.doB();
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

    public interface InterfaceA {
        void doSomething();
        void doA();
    }

    public interface InterfaceB {
        void doSomething();
        void doB();
    }

    static class TargetObject implements InterfaceA, InterfaceB {
        public void doSomething() {
            System.out.println("target doSomething");
        }
        public void doA() {
            System.out.println("target doA");
        }
        public void doB() {
            System.out.println("target doB");
        }
    }

    static class DynamicProxyHandler implements InvocationHandler { //動(dòng)態(tài)代理處理器
        private Object target;
        public DynamicProxyHandler(Object target) {
            this.target = target;
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("InvocationHandler: " + proxy.getClass() +
                    ", method: " + method + ", args: " + args);
            if(args != null) {
                for(Object arg : args) {
                    System.out.println("InvocationHandler args: " + arg);
                }
            }
            return method.invoke(target, args);
        }
    }

}

//輸出log
InvocationHandler: class com.sun.proxy.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$InterfaceB.doSomething(), args: null
==> 雖然動(dòng)態(tài)代理對象proxy_a正以接口InterfaceA的形式被外部引用蹬铺,但獲取的方法對象是在getProxyClass方法排前面的InterfaceB中的尝哆。
target doSomething
InvocationHandler: class com.sun.proxy.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$InterfaceA.doA(), args: null
target doA
InvocationHandler: class com.sun.proxy.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$InterfaceB.doSomething(), args: null
target doSomething
InvocationHandler: class com.sun.proxy.$Proxy0, method: public abstract void com.tomorrow.test.DynamicProxy$InterfaceB.doB(), args: null
target doB

生成的動(dòng)態(tài)代理類:

package com.sun.proxy;

import com.tomorrow.test.DynamicProxy.InterfaceA;
import com.tomorrow.test.DynamicProxy.InterfaceB;
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 DynamicProxy.InterfaceB, DynamicProxy.InterfaceA
{
  private static Method m1;
  private static Method m3;
  private static Method m5;
  private static Method m2;
  private static Method m4;
  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 doSomething()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void doA()
    throws 
  {
    try
    {
      this.h.invoke(this, m5, 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 void doB()
    throws 
  {
    try
    {
      this.h.invoke(this, m4, null);
      return;
    }
    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.tomorrow.test.DynamicProxy$InterfaceB").getMethod("doSomething", new Class[0]); //注意:獲取的是排在前面的InterfaceB的doSomething方法
      m5 = Class.forName("com.tomorrow.test.DynamicProxy$InterfaceA").getMethod("doA", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.tomorrow.test.DynamicProxy$InterfaceB").getMethod("doB", 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());
    }
  }
}

被動(dòng)態(tài)代理的一組接口的特點(diǎn)

  • 要注意不能有重復(fù)的接口,以避免動(dòng)態(tài)代理類代碼生成時(shí)出現(xiàn)編譯錯(cuò)誤甜攀。
  • 這些接口對于類裝載器必須可見秋泄,否則類裝載器無法鏈接它們,將會導(dǎo)致動(dòng)態(tài)代理類定義失敗规阀。
  • 需要被代理的所有非public的接口必須在同一個(gè)包中恒序,否則動(dòng)態(tài)代理類代碼生成也會失敗。
  • 接口的數(shù)目不能超過65535谁撼,這是JVM設(shè)定的限制歧胁。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子喊巍,更是在濱河造成了極大的恐慌屠缭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崭参,死亡現(xiàn)場離奇詭異呵曹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)何暮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門逢并,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人郭卫,你說我怎么就攤上這事”臣冢” “怎么了贰军?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蟹肘。 經(jīng)常有香客問我词疼,道長,這世上最難降的妖魔是什么帘腹? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任贰盗,我火速辦了婚禮,結(jié)果婚禮上阳欲,老公的妹妹穿的比我還像新娘舵盈。我一直安慰自己,他們只是感情好球化,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布秽晚。 她就那樣靜靜地躺著,像睡著了一般筒愚。 火紅的嫁衣襯著肌膚如雪赴蝇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天巢掺,我揣著相機(jī)與錄音句伶,去河邊找鬼。 笑死陆淀,一個(gè)胖子當(dāng)著我的面吹牛考余,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播轧苫,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼秃殉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钾军,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤鳄袍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吏恭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拗小,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年樱哼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哀九。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡搅幅,死狀恐怖阅束,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茄唐,我是刑警寧澤息裸,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站沪编,受9級特大地震影響呼盆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚁廓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一访圃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧相嵌,春花似錦腿时、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捏雌,卻和暖如春跃赚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背性湿。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工纬傲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肤频。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓叹括,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宵荒。 傳聞我的和親對象是個(gè)殘疾皇子汁雷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 1净嘀、代理概念 為某個(gè)對象提供一個(gè)代理,以控制對這個(gè)對象的訪問侠讯。 代理類和委托類有共同的父類或父接口挖藏,這樣在任何使用...
    孔垂云閱讀 7,690評論 4 54
  • 一、代理概念 為某個(gè)對象提供一個(gè)代理厢漩,以控制對這個(gè)對象的訪問膜眠。 代理類和委托類有共同的父類或父接口,這樣在任何使用...
    wyatt_plus閱讀 792評論 0 5
  • Java動(dòng)態(tài)代理 引言 最近在看AOP代碼溜嗜,其中利用到了Java動(dòng)態(tài)代理機(jī)制來實(shí)現(xiàn)AOP織入宵膨。所以好好地把Java...
    草捏子閱讀 1,538評論 0 18
  • 一、基本概念 1.什么是代理炸宵? 在闡述JDK動(dòng)態(tài)代理之前辟躏,我們很有必要先來弄明白代理的概念。代理這個(gè)詞本身并不是計(jì)...
    小李彈花閱讀 16,443評論 2 40
  • 11/21 徐芳香 溫州【每日一結(jié)構(gòu)】結(jié)構(gòu)思考力21天思維改善訓(xùn)練營 G:【認(rèn)知不協(xié)調(diào)對我們的很多決策與判斷都具有...
    靜靜的葉子閱讀 338評論 0 0