Google Guava 反射機(jī)制工具類

一 TypeToken

? ? ? ?Guava TypeToken類是用來(lái)幫我們解決java運(yùn)行時(shí)泛型類型被擦除的問(wèn)題的。

? ? ? ?這里用一個(gè)具體的實(shí)例來(lái)解釋下什么是類型檫除,特別是使用泛型的時(shí)候容易出現(xiàn)類型檫除眷细。

        ArrayList<String> stringList = Lists.newArrayList();
        ArrayList<Integer> intList = Lists.newArrayList();
        System.out.println("intList type is " + intList.getClass());
        System.out.println("stringList type is " + stringList.getClass());

? ? ? ?上述代碼雖然我們定義的是ArrayList<String>隶糕、ArrayList<Integer>類型的對(duì)象坝疼。但是兩者的打印都是java.util.ArrayList翠拣。沒(méi)辦法去獲取到String、Integer了虑灰。他們的類型被檫除了吨瞎,在想通過(guò)類型來(lái)判斷是哪個(gè)對(duì)象就做不到了。

? ? ? ?鑒于類似這樣的情況發(fā)生Guava給我們提供了TypeToken類穆咐。怎么用颤诀,

        // 認(rèn)為stringList和intList的類型是一樣的。這就是所謂的泛型類型擦除, 泛型String和Integer被檫除了对湃。
        System.out.println(stringList.getClass().isAssignableFrom(intList.getClass()));

        // 定義了一個(gè)空的匿名類
        TypeToken<ArrayList<String>> typeToken = new TypeToken<ArrayList<String>>() {
        };
        // TypeToken解析出了泛型參數(shù)的具體類型
        TypeToken<?> genericTypeToken = typeToken.resolveType(ArrayList.class.getTypeParameters()[0]);
        System.out.println(genericTypeToken.getType());

? ? ? ?通過(guò)TypeToken我們就可以獲取到ArrayList<String>里面的class java.lang.String崖叫。

? ? ? ?TypeToken常用方法如下:

方法 描述
getType() 獲得包裝的java.lang.reflect.Type.
getRawType() 返回大家熟知的運(yùn)行時(shí)類
getSubtype(Class<?>) 返回那些有特定原始類的子類型。舉個(gè)例子拍柒,如果這有一個(gè)Iterable并且參數(shù)是List.class心傀,那么返回將是List。
getSupertype(Class<?>) 產(chǎn)生這個(gè)類型的超類拆讯,這個(gè)超類是指定的原始類型脂男。舉個(gè)例子养叛,如果這是一個(gè)Set并且參數(shù)是Iterable.class,結(jié)果將會(huì)是Iterable宰翅。
isAssignableFrom(type) 如果這個(gè)類型是 assignable from 指定的類型弃甥,并且考慮泛型參數(shù),返回true堕油。List<? extends Number>是assignable from List潘飘,但List沒(méi)有.
getTypes() 返回一個(gè)Set,包含了這個(gè)所有接口掉缺,子類和類是這個(gè)類型的類。返回的Set同樣提供了classes()和interfaces()方法允許你只瀏覽超類和接口類戈擒。
isArray() 檢查某個(gè)類型是不是數(shù)組眶明,甚至是<? extends A[]>。
getComponentType() 返回組件類型數(shù)組筐高。

二 Invokable

? ? ? ?Guava的Invokable是對(duì)java.lang.reflect.Method和java.lang.reflect.Constructor的流式包裝搜囱。它簡(jiǎn)化了常見(jiàn)的反射代碼的使用。

2.1 Invokable常用方法

    /**
     * 根據(jù)指定的Method返回Invokable對(duì)象(MethodInvokable)
     */
    public static Invokable<?, Object> from(Method method);

    /**
     * 根據(jù)指定的Constructor返回Invokable對(duì)象(ConstructorInvokable)
     */
    public static <T> Invokable<T, T> from(Constructor<T> constructor) {
        return new ConstructorInvokable<T>(constructor);
    }

    /**
     * 判斷當(dāng)前方法是否可以重寫(xiě)的
     * Constructors, private, static or final methods, or methods declared by final classes
     * 都是不能被重寫(xiě)的
     */
    public abstract boolean isOverridable();

    /**
     * 當(dāng)前方法對(duì)應(yīng)的參數(shù)是否是可變的參數(shù)
     */
    public abstract boolean isVarArgs();

    /**
     * 執(zhí)行對(duì)應(yīng)的方法
     */
    // All subclasses are owned by us and we'll make sure to get the R type right.
    @SuppressWarnings("unchecked")
    @CanIgnoreReturnValue
    public final R invoke(@Nullable T receiver, Object... args)
            throws InvocationTargetException, IllegalAccessException {
        return (R) invokeInternal(receiver, checkNotNull(args));
    }

    /**
     * 獲取當(dāng)前方法的返回值
     */
    // All subclasses are owned by us and we'll make sure to get the R type right.
    @SuppressWarnings("unchecked")
    public final TypeToken<? extends R> getReturnType();

    /**
     * 獲取當(dāng)前方法的參數(shù)
     */
    public final ImmutableList<Parameter> getParameters();

    /**
     * 獲取當(dāng)前方法的異常類型
     */
    public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes();

    /**
     * 顯式指定此Invokable的返回類型.可以作為一個(gè)過(guò)濾作用處理
     *
     * 例如:
     *
     * Method factoryMethod = Person.class.getMethod("create");
     * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
     *
     */
    public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType);

    /**
     * 顯式指定此Invokable的返回類型
     */
    public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType);

    /**
     * 返回表示聲明由此Invokable對(duì)象表示的方法的類的Class對(duì)象柑土,父類中申明的就會(huì)返回父類class
     */
    @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
    @Override
    public final Class<? super T> getDeclaringClass();

    /**
     * 方法返回表示聲明由此Method對(duì)象表示的方法的類的Class對(duì)象蜀肘,Class包裝成了TypeToken而已
     */
    // Overridden in TypeToken#method() and TypeToken#constructor()
    @SuppressWarnings("unchecked") // The declaring class is T.
    @Override
    public TypeToken<T> getOwnerType();

    /**
     *  返回一個(gè)AnnotatedType對(duì)象,把該方法的返回類型包裝成了一個(gè)AnnotatedType類型
     */
    public abstract AnnotatedType getAnnotatedReturnType();

2.2 Invokable簡(jiǎn)單使用

public class InvokableTest {

    @Test
    public void invokableTest() {
        // 對(duì)象
        InvokableInstance object = new InvokableInstance(10);
        // 獲去對(duì)象對(duì)應(yīng)的類
        Class clazz = object.getClass();
        Method[] invokableSourceList = clazz.getMethods();
//        Constructor[] invokableSourceList =  clazz.getConstructors();
        if (invokableSourceList.length > 0) {
            for (Method item : invokableSourceList) {
                System.out.println("========================================");
                // 方法名字
                System.out.println("方法名字:" + item.getName());
                // 把Method包裝成Invokable
                Invokable methodInvokable = Invokable.from(item);
                // getDeclaringClass() 獲取定義該方法的類
                System.out.println("定義該方法的類:" + methodInvokable.getDeclaringClass());
                // getOwnerType() 獲取定義該方法的class的包裝對(duì)象Type
                System.out.println("定義該方法的類:" + methodInvokable.getOwnerType().getType());
                // isOverridable() 該方法是否可以重寫(xiě)
                System.out.println("是否可以重寫(xiě):" + methodInvokable.isOverridable());
                // isVarArgs() 該方法是否可變參數(shù)
                System.out.println("是否可變參數(shù):" + methodInvokable.isVarArgs());
                // getReturnType() 該方法返回值類型
                System.out.println("返回值類型:" + methodInvokable.getReturnType().getType());
                // getParameters() 獲取參數(shù)
                ImmutableList<Parameter> parameterList = methodInvokable.getParameters();
                for (int index = 0; index < parameterList.size(); index++) {
                    System.out.println("方法參數(shù)" + index + ": " + parameterList.get(index).getType());
                }
                // getExceptionTypes() 獲取異常類
                ImmutableList<TypeToken> exceptionList = methodInvokable.getExceptionTypes();
                for (int index = 0; index < exceptionList.size(); index++) {
                    System.out.println("異常類" + index + ": " + exceptionList.get(index).getType());
                }
                // getAnnotatedReturnType()
                AnnotatedType annotatedType = methodInvokable.getAnnotatedReturnType();
                System.out.println("annotatedType: " + annotatedType.getType());
            }
        }
    }

    /**
     * 一個(gè)測(cè)試用類
     */
    class InvokableInstance {

        /**
         * 構(gòu)造函數(shù)
         */
        public InvokableInstance(int a) {

        }

        /**
         * 僅僅是用來(lái)測(cè)試的一個(gè)方法
         */
        @CanIgnoreReturnValue
        public void sum(int a, int b) throws NullPointerException {
//            return a + b;
        }

    }

}

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

? ? ? ?Guava為了方便大家很好的處理動(dòng)態(tài)代理稽屏,給大家做了兩件事:簡(jiǎn)化生成代理對(duì)象的生成扮宠、提供了AbstractInvocationHandler了。

3.1 動(dòng)態(tài)代理對(duì)象的生成

? ? ? ?對(duì)于單一的接口類型需要被代理的時(shí)候狐榔。Guava簡(jiǎn)化了代理對(duì)象的生成坛增。我們用一個(gè)具體的實(shí)例來(lái)說(shuō)明

定義一個(gè)很簡(jiǎn)單的接口AddService

public interface AddService {

    int add(int a, int b);

}

實(shí)現(xiàn)AddService

public class AddServiceImpl implements AddService {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

? ? ? ?原來(lái)JDK生成代理對(duì)象是通過(guò)Proxy.newProxyInstance()方法生成,這個(gè)方法需要三個(gè)參數(shù):第一個(gè)參數(shù)指定產(chǎn)生代理對(duì)象的類加載器薄腻,需要將其指定為和目標(biāo)對(duì)象同一個(gè)類加載器收捣、第二個(gè)參數(shù)要實(shí)現(xiàn)和目標(biāo)對(duì)象一樣的接口,所以只需要拿到目標(biāo)對(duì)象的實(shí)現(xiàn)接口庵楷、第三個(gè)參數(shù)表明這些被攔截的方法在被攔截時(shí)需要執(zhí)行哪個(gè)InvocationHandler的invoke方法罢艾。我們還是直接用代碼來(lái)說(shuō)明問(wèn)題。

實(shí)現(xiàn)InvocationHandler接口(代理方法處理接口)尽纽。通過(guò)實(shí)現(xiàn)類里面的getProxy()
拿到代理對(duì)象咐蚯。

public class JdkInvocationHandlerImpl<T> implements InvocationHandler {

    /**
     * 目標(biāo)對(duì)象
     */
    private T targetObject;

    public JdkInvocationHandlerImpl(T target) {
        this.targetObject = target;
    }

    /**
     * 綁定關(guān)系,也就是關(guān)聯(lián)到哪個(gè)接口(與具體的實(shí)現(xiàn)類綁定)的哪些方法將被調(diào)用時(shí)蜓斧,執(zhí)行invoke方法仓蛆。
     */
    public AddService getProxy() {
        //該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動(dòng)態(tài)代理類實(shí)例
        //第一個(gè)參數(shù)指定產(chǎn)生代理對(duì)象的類加載器挎春,需要將其指定為和目標(biāo)對(duì)象同一個(gè)類加載器
        //第二個(gè)參數(shù)要實(shí)現(xiàn)和目標(biāo)對(duì)象一樣的接口看疙,所以只需要拿到目標(biāo)對(duì)象的實(shí)現(xiàn)接口
        //第三個(gè)參數(shù)表明這些被攔截的方法在被攔截時(shí)需要執(zhí)行哪個(gè)InvocationHandler的invoke方法
        //根據(jù)傳入的目標(biāo)返回一個(gè)代理對(duì)象
        return (AddService) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 打印參數(shù)信息列表
        for (Object arg : args) {
            System.out.println(arg);
        }
        Object ret;
        try {
            /*原對(duì)象方法調(diào)用前處理日志信息*/
            System.out.println("方法開(kāi)始執(zhí)行-->>");
            //調(diào)用目標(biāo)方法
            ret = method.invoke(targetObject, args);
            /*原對(duì)象方法調(diào)用后處理日志信息*/
            System.out.println("方法執(zhí)行成功-->>");
        } catch (Exception e) {
            // 執(zhí)行方法過(guò)程中出現(xiàn)異常
            e.printStackTrace();
            System.out.println("方法執(zhí)行失敗-->>");
            throw e;
        }
        return ret;
    }
}

使用

    @Test
    public void jdkNewProxyTest() {
        AddServiceImpl service = new AddServiceImpl();
        JdkInvocationHandlerImpl<AddService> addServiceHandler = new JdkInvocationHandlerImpl<>(service);
        AddService proxy = addServiceHandler.getProxy();
        Assert.assertEquals(3, proxy.add(1, 2));
    }

? ? ? ?Guava生成代理對(duì)象豆拨。直接調(diào)用Reflection.newProxy()函數(shù),這個(gè)函數(shù)也是需要兩個(gè)參數(shù):第一個(gè)參數(shù)接口能庆,要實(shí)現(xiàn)和目標(biāo)對(duì)象的某一樣的接口(那個(gè)接口里面的方法需要代理)施禾、第二個(gè)參數(shù)表明這些被攔截的方法在被攔截時(shí)需要執(zhí)行哪個(gè)InvocationHandler的invoke方法。具體使用實(shí)例如下:

實(shí)現(xiàn)InvocationHandler接口(代理方法處理接口)搁胆。通過(guò)實(shí)現(xiàn)類里面的Reflection.newProxy()拿到代理對(duì)象弥搞。

public class GuavaInvocationHandlerImpl<T> implements InvocationHandler {

    /**
     * 目標(biāo)對(duì)象對(duì)應(yīng)的接口(因?yàn)橐粋€(gè)對(duì)象可以實(shí)現(xiàn)多個(gè)接口,我們不知道是那個(gè)接口渠旁,所以傳遞進(jìn)來(lái))
     */
    private Class<T> targetInterface;
    /**
     * 目標(biāo)對(duì)象
     */
    private T targetObject;


    public GuavaInvocationHandlerImpl(Class<T> targetInterface, T targetObject) {
        /*參數(shù)判斷*/
        // targetInterfaced一定要是一個(gè)接口
        checkArgument(targetInterface.isInterface(), "%s 不是一個(gè)接口類", targetInterface);
        // targetObject一定是targetInterface接口的實(shí)現(xiàn)類攀例。
        boolean valid = false;
        Class<?>[] targetInterfaceList = targetObject.getClass().getInterfaces();
        if (targetInterfaceList != null && targetInterfaceList.length > 0) {
            for (Class<?> item : targetInterfaceList) {
                if (targetInterface.getName().equals(item.getName())) {
                    valid = true;
                    break;
                }
            }
        }
        checkArgument(valid, "%s 必須實(shí)現(xiàn) %s", targetObject.getClass().getName(), targetInterface.getName());
        this.targetInterface = targetInterface;
        this.targetObject = targetObject;
    }

    /**
     * 獲取都代理對(duì)象
     */
    public T getProxy() {
        // guava里面Reflection幫助類提供的 Reflection.newProxy() 實(shí)現(xiàn)
        // 第一個(gè)參數(shù)接口,要實(shí)現(xiàn)和目標(biāo)對(duì)象的某一樣的接口(那個(gè)接口里面的方法需要代理)
        // 第二個(gè)參數(shù)表明這些被攔截的方法在被攔截時(shí)需要執(zhí)行哪個(gè)InvocationHandler的invoke方法
        return Reflection.newProxy(targetInterface, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 打印參數(shù)信息列表
        for (Object arg : args) {
            System.out.println(arg);
        }
        Object ret;
        try {
            /*原對(duì)象方法調(diào)用前處理日志信息*/
            System.out.println("方法開(kāi)始執(zhí)行-->>");
            //調(diào)用目標(biāo)方法
            ret = method.invoke(targetObject, args);
            /*原對(duì)象方法調(diào)用后處理日志信息*/
            System.out.println("方法執(zhí)行成功-->>");
        } catch (Exception e) {
            // 執(zhí)行方法過(guò)程中出現(xiàn)異常
            e.printStackTrace();
            System.out.println("方法執(zhí)行失敗-->>");
            throw e;
        }
        return ret;
    }
}

使用

    @Test
    public void guavaNewProxyTest() {
        AddServiceImpl service = new AddServiceImpl();
        GuavaInvocationHandlerImpl<AddService> addServiceHandler = new GuavaInvocationHandlerImpl<>(AddService.class, service);
        AddService proxy = addServiceHandler.getProxy();
        Assert.assertEquals(3, proxy.add(1, 2));
    }

3.2 AbstractInvocationHandler

? ? ? ?有時(shí)候你可能想動(dòng)態(tài)代理能夠更直觀的支持equals()顾腊,hashCode()和toString()粤铭。AbstractInvocationHandler能幫我們做到三件事:

  • 一個(gè)代理實(shí)例equal另外一個(gè)代理實(shí)例,只要他們有同樣的接口類型和equal的invocation handlers杂靶。
  • 一個(gè)代理實(shí)例的toString()會(huì)被代理到invocation handler的toString()梆惯,這樣更容易自定義toString()。
  • AbstractInvocationHandler確保傳遞給handleInvocation(Object, Method, Object[]))的參數(shù)數(shù)組永遠(yuǎn)不會(huì)空吗垮,從而減少了空指針異常的機(jī)會(huì)垛吗。

如果對(duì)上面講的幾點(diǎn)不是很明白的話,強(qiáng)烈建議大家看下AbstractInvocationHandler的源碼部分烁登。

public class GuavaAbstractInvocationHandlerImpl<T> extends AbstractInvocationHandler {

    /**
     * 目標(biāo)對(duì)象對(duì)應(yīng)的接口(因?yàn)橐粋€(gè)對(duì)象可以實(shí)現(xiàn)多個(gè)接口怯屉,我們不知道是那個(gè)接口,所以傳遞進(jìn)來(lái))
     */
    private Class<T> targetInterface;
    /**
     * 目標(biāo)對(duì)象
     */
    private T targetObject;


    public GuavaAbstractInvocationHandlerImpl(Class<T> targetInterface, T targetObject) {
        /*參數(shù)判斷*/
        // targetInterfaced一定要是一個(gè)接口
        checkArgument(targetInterface.isInterface(), "%s 不是一個(gè)接口類", targetInterface);
        // targetObject一定是targetInterface接口的實(shí)現(xiàn)類防泵。
        boolean valid = false;
        Class<?>[] targetInterfaceList = targetObject.getClass().getInterfaces();
        if (targetInterfaceList != null && targetInterfaceList.length > 0) {
            for (Class<?> item : targetInterfaceList) {
                if (targetInterface.getName().equals(item.getName())) {
                    valid = true;
                    break;
                }
            }
        }
        checkArgument(valid, "%s 必須實(shí)現(xiàn) %s", targetObject.getClass().getName(), targetInterface.getName());
        this.targetInterface = targetInterface;
        this.targetObject = targetObject;
    }

    /**
     * 獲取都代理對(duì)象
     */
    public T getProxy() {
        // guava里面Reflection幫助類提供的 Reflection.newProxy() 實(shí)現(xiàn)
        return Reflection.newProxy(targetInterface, this);
    }

    @Override
    protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
        // 打印參數(shù)信息列表
        for (Object arg : args) {
            System.out.println(arg);
        }
        Object ret;
        try {
            /*原對(duì)象方法調(diào)用前處理日志信息*/
            System.out.println("方法開(kāi)始執(zhí)行-->>");
            //調(diào)用目標(biāo)方法
            ret = method.invoke(targetObject, args);
            /*原對(duì)象方法調(diào)用后處理日志信息*/
            System.out.println("方法執(zhí)行成功-->>");
        } catch (Exception e) {
            // 執(zhí)行方法過(guò)程中出現(xiàn)異常
            e.printStackTrace();
            System.out.println("方法執(zhí)行失敗-->>");
            throw e;
        }
        return ret;
    }
}

四 ClassPath

? ? ? ?嚴(yán)格來(lái)講蚀之,Java沒(méi)有平臺(tái)無(wú)關(guān)的方式來(lái)瀏覽類和類資源。不過(guò)一定的包或者工程下捷泞,還是能夠?qū)崿F(xiàn)的足删,比方說(shuō),去檢查某個(gè)特定的工程的慣例或者某種一直遵從的約束锁右。

? ? ? ?ClassPath是一種實(shí)用工具失受,它提供盡最大努力的類路徑掃描。

? ? ? ?值得注意的是咏瑟,ClassPath是一個(gè)盡力而為的工具拂到。它只掃描jar文件中或者某個(gè)文件目錄下的class文件。也不能掃描非URLClassLoader的自定義class loader管理的class码泞,所以不要將它用于關(guān)鍵任務(wù)生產(chǎn)任務(wù)兄旬。

4.1 ClassPath常用方法

    /**
     * 創(chuàng)建一個(gè)ClassPath對(duì)象
     */
    public static ClassPath from(ClassLoader classloader) throws IOException;

    /**
     * 返回從當(dāng)前類路徑可加載的所有資源,包括所有可加載類的類文件,但不包括“META-INF / MANIFEST.MF”文件
     */
    public ImmutableSet<ResourceInfo> getResources();

    /**
     * 返回可加載的所有類
     */
    public ImmutableSet<ClassInfo> getAllClasses();

    /**
     * 返回所有的頂級(jí)類(不包括內(nèi)部類)
     */
    public ImmutableSet<ClassInfo> getTopLevelClasses();
    
    /**
     * 返回指定package下的所有頂級(jí)類
     */
    public ImmutableSet<ClassInfo> getTopLevelClasses(String packageName);

    /**
     * 返回所有指定package已經(jīng)子package下所有的頂級(jí)類
     */
    public ImmutableSet<ClassInfo> getTopLevelClassesRecursive(String packageName);

4.2 ClassPath簡(jiǎn)單使用

    @Test
    public void classPathTest() {
        try {
            ClassPath classpath = ClassPath.from(ClassPathBase.class.getClassLoader());
            // getTopLevelClassesRecursive
            ImmutableSet<ClassPath.ClassInfo> topClassList =  classpath.getTopLevelClassesRecursive("com.tuacy.guava.study");
            if (topClassList != null && !topClassList.isEmpty()) {
                for (ClassPath.ClassInfo classInfoItem : topClassList) {
                    System.out.println(classInfoItem.toString());
                }
            }
            // getResources
            ImmutableSet<ClassPath.ResourceInfo> resourceList =  classpath.getResources();
            if (resourceList != null && !resourceList.isEmpty()) {
                for (ClassPath.ResourceInfo resourceItem : resourceList) {
                    System.out.println(resourceItem.url().toString());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class ClassPathBase {

    }

? ? ? ?關(guān)于Guava反射機(jī)制工具類我們就暫時(shí)先提這些领铐,上文中涉及到的代碼可以在https://github.com/tuacy/google-guava-study里面找到(在單元測(cè)試代碼里面)悯森。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绪撵,隨后出現(xiàn)的幾起案子瓢姻,更是在濱河造成了極大的恐慌,老刑警劉巖音诈,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幻碱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡细溅,警方通過(guò)查閱死者的電腦和手機(jī)褥傍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喇聊,“玉大人摔桦,你說(shuō)我怎么就攤上這事〕衅#” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鸥咖,是天一觀的道長(zhǎng)燕鸽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)啼辣,這世上最難降的妖魔是什么啊研? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鸥拧,結(jié)果婚禮上党远,老公的妹妹穿的比我還像新娘。我一直安慰自己富弦,他們只是感情好沟娱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著腕柜,像睡著了一般济似。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盏缤,一...
    開(kāi)封第一講書(shū)人閱讀 51,274評(píng)論 1 300
  • 那天砰蠢,我揣著相機(jī)與錄音,去河邊找鬼唉铜。 笑死台舱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潭流。 我是一名探鬼主播竞惋,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼柜去,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了碰声?” 一聲冷哼從身側(cè)響起诡蜓,我...
    開(kāi)封第一講書(shū)人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胰挑,沒(méi)想到半個(gè)月后蔓罚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞻颂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年豺谈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贡这。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茬末,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盖矫,到底是詐尸還是另有隱情丽惭,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布辈双,位于F島的核電站责掏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏湃望。R本人自食惡果不足惜换衬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望证芭。 院中可真熱鬧瞳浦,春花似錦、人聲如沸废士。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)湃密。三九已至诅挑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泛源,已是汗流浹背拔妥。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留达箍,地道東北人没龙。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親硬纤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子解滓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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