Spring aop解析(4)2018-08-14

上一節(jié)我們分析了Advisor的生成過(guò)程以及在Advisor中生成Advise的過(guò)程。接著上一節(jié)繼續(xù)我們看看挑出適用于目標(biāo)對(duì)象的Advisor:

private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
        //獲取Advisors集合
        List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
        //從中挑出適用于目標(biāo)對(duì)象的Advisor
        advisors = AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass());
        AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
        //對(duì)獲取到的Advisor進(jìn)行排序
        AnnotationAwareOrderComparator.sort(advisors);
        //將獲取到Advisor添加到advisors集合中
        addAdvisors(advisors);
    }
2.3.1:addAdvisorsFromAspectInstanceFactory方法:

a、挑出適用于目標(biāo)對(duì)象的Advisor: AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass());

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        //如果傳入的Advisor集合為空的話敬锐,直接返回這個(gè)空集合
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        //創(chuàng)建一個(gè)合適的Advisor的集合 eligible
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        //循環(huán)所有的Advisor
        for (Advisor candidate : candidateAdvisors) {
            //如果Advisor是IntroductionAdvisor  引介增強(qiáng) 可以為目標(biāo)類 通過(guò)AOP的方式添加一些接口實(shí)現(xiàn)
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        //是否有引介增強(qiáng)
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            //如果是IntroductionAdvisor類型的話 則直接跳過(guò)
            if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            //判斷此Advisor是否適用于target
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        //如果是IntroductionAdvisor的話泪喊,則調(diào)用IntroductionAdvisor類型的實(shí)例進(jìn)行類的過(guò)濾
        //這里是直接調(diào)用的ClassFilter的matches方法
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        //通常我們的Advisor都是PointcutAdvisor類型
        else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;
            //這里從Advisor中獲取Pointcut的實(shí)現(xiàn)類 這里是AspectJExpressionPointcut
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
            // It doesn't have a pointcut so we assume it applies.
            return true;
        }
    }

這里匹配的規(guī)則我們就不進(jìn)行深入了措译。

2.4:接著我們來(lái)看看代理對(duì)象的創(chuàng)建過(guò)程:
public class TestAop {
    public static void main(String[] args) {
        //手工創(chuàng)建一個(gè)實(shí)例(Target)
        ProxyService aspectJService = new ProxyServiceImpl();
        //使用AspectJ語(yǔ)法 自動(dòng)創(chuàng)建代理對(duì)象
        AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService);
        //添加切面和通知類
        aspectJProxyFactory.addAspect(AopAdviceConfig.class);
        //創(chuàng)建代理對(duì)象
        ProxyService proxyService = aspectJProxyFactory.getProxy();
        //進(jìn)行方法調(diào)用
        proxyService.testProxy();
    }
}

a吗浩、創(chuàng)建代理aspectJProxyFactory.getProxy():

 //通過(guò)調(diào)用createAopProxy()生成的對(duì)象調(diào)用getProxy()方法生成代理對(duì)象
 public <T> T getProxy() {
        return (T) createAopProxy().getProxy();
}

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        //這里會(huì)監(jiān)聽(tīng)調(diào)用AdvisedSupportListener實(shí)現(xiàn)類的activated方法
        activate();
    }
    //獲取AopProxyFactory
    //調(diào)用createAopProxy的時(shí)候傳入了this對(duì)象
    return getAopProxyFactory().createAopProxy(this);
}
//在SpringAOP中 AopProxyFactory只有一個(gè)實(shí)現(xiàn)類揩页,這個(gè)實(shí)現(xiàn)類就是DefaultAopProxyFactory
public AopProxyFactory getAopProxyFactory() {
    return this.aopProxyFactory;
}   

private void activate() {
        this.active = true;
        for (AdvisedSupportListener listener : this.listeners) {
            listener.activated(this);
        }
    }

b猖败、我們接著看:createAopProxy()方法:

ublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        //這段代碼用來(lái)判斷選擇哪種創(chuàng)建代理對(duì)象的方式
        //config.isOptimize()   是否對(duì)代理類的生成使用策略優(yōu)化 其作用是和isProxyTargetClass是一樣的 默認(rèn)為false
        //config.isProxyTargetClass() 是否使用Cglib的方式創(chuàng)建代理對(duì)象 默認(rèn)為false
        //hasNoUserSuppliedProxyInterfaces目標(biāo)類是否有接口存在 且只有一個(gè)接口的時(shí)候接口類型不是SpringProxy類型 
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            //從AdvisedSupport中獲取目標(biāo)類 類對(duì)象
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            //判斷目標(biāo)類是否是接口 如果目標(biāo)類是接口的話速缆,則還是使用JDK的方式生成代理對(duì)象
            //如果目標(biāo)類是Proxy類型 則還是使用JDK的方式生成代理對(duì)象
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            //使用JDK的提供的代理方式生成代理對(duì)象
            return new JdkDynamicAopProxy(config);
        }
    }

c、我們接著往下看看createAopProxy().getProxy()方法:

public <T> T getProxy(ClassLoader classLoader) {
       return (T) createAopProxy().getProxy(classLoader);
   }

public Object getProxy(ClassLoader classLoader) {
       if (logger.isDebugEnabled()) {
           logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
       }
       //獲取AdvisedSupport類型對(duì)象的所有接口
       Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
       //接口是否定義了 equals和hashcode方法 正常是沒(méi)有的恩闻,定義了生成的代理以定義的為準(zhǔn)
       findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
       //創(chuàng)建代理
       return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
   }

private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
       for (Class<?> proxiedInterface : proxiedInterfaces) {
           Method[] methods = proxiedInterface.getDeclaredMethods();
           for (Method method : methods) {
               if (AopUtils.isEqualsMethod(method)) {
                   this.equalsDefined = true;
               }
               if (AopUtils.isHashCodeMethod(method)) {
                   this.hashCodeDefined = true;
               }
               if (this.equalsDefined && this.hashCodeDefined) {
                   return;
               }
           }
       }
   }

e艺糜、我們知道創(chuàng)建代理需要額外功能類繼承InvocationHandler實(shí)現(xiàn)invoke方法添加額外功能,那么我們來(lái)看看JdkDynamicAopProxy中的invoke的實(shí)現(xiàn):

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
        //目標(biāo)對(duì)象
        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            //接口中沒(méi)有定義 equals方法,并且調(diào)用的方法是equals方法(即Object中定義的equals方法) 
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                //調(diào)用 JdkDynamicAopProxy 中寫(xiě)的equals方法
                return equals(args[0]);
            }else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                //和上面的分析一樣
                return hashCode();
            }else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
              //如果 方法所在的類是接口 并且是Advised的子類,則直接調(diào)用下面的方法
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;
            //是否對(duì)外暴露代理對(duì)象
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                //把創(chuàng)建的代理對(duì)象放到線程上下文中返回之前老的代理
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            //從TargetSource中獲取目標(biāo)對(duì)象
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            //從Advised中根據(jù)方法名和目標(biāo)類獲取 AOP攔截器執(zhí)行鏈 重點(diǎn)要分析的內(nèi)容
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            //如果這個(gè)執(zhí)行鏈為空的話
            if (chain.isEmpty()) {
                //直接進(jìn)行方法調(diào)用
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                //如果AOP攔截器執(zhí)行鏈不為空  說(shuō)明有AOP通知存在
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //開(kāi)始調(diào)用
                retVal = invocation.proceed();
            }
            //方法的返回值類型
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                //return this
                retVal = proxy;
            }
            //返回值類型錯(cuò)誤
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            //如果目標(biāo)對(duì)象不為空  且目標(biāo)對(duì)象是可變的 如prototype類型
            //通常我們的目標(biāo)對(duì)象都是單例的  即targetSource.isStatic為true
            if (target != null && !targetSource.isStatic()) {
                //釋放目標(biāo)對(duì)象
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                //線程上下文復(fù)位
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

從上面代碼不難看出這段代碼的重點(diǎn):從Advised中根據(jù)方法名和目標(biāo)類獲取 AOP攔截器執(zhí)行鏈(List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);)那么我們來(lái)看看獲取的代碼:

f倦踢、this.advised.getInterceptorsAndDynamicInterceptionAdvice:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        //創(chuàng)建一個(gè)method的緩存對(duì)象在MethodCacheKey中實(shí)現(xiàn)了equals和hashcode方法同時(shí)還實(shí)現(xiàn)了compareTo方法
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        //先從緩存中獲取 如果緩存中獲取不到則再調(diào)用方法獲取,獲取之后放入到緩存中
        if (cached == null) {
            //調(diào)用的是advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }


public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {
        //創(chuàng)建一個(gè)初始大小為之前獲取到的 通知個(gè)數(shù)的 集合
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        //如果目標(biāo)類為null的話送滞,則從方法簽名中獲取目標(biāo)類
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        //判斷目標(biāo)類是否存在引介增強(qiáng)通常為false
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        //這里用了一個(gè)單例模式獲取DefaultAdvisorAdapterRegistry實(shí)例
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //循環(huán)目標(biāo)方法匹配的通知
        for (Advisor advisor : config.getAdvisors()) {
            //如果是PointcutAdvisor類型的實(shí)例  我們大多數(shù)的Advisor都是PointcutAdvisor類型的
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                //如果提前進(jìn)行過(guò) 切點(diǎn)的匹配了或者當(dāng)前的Advisor適用于目標(biāo)類
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    //將Advisor適配為MethodInterceptor
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    //檢測(cè)Advisor是否適用于此目標(biāo)方法
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        //MethodMatcher中的切點(diǎn)分為兩種 一個(gè)是靜態(tài)的 一種是動(dòng)態(tài)的
                        //如果isRuntime返回true 則是動(dòng)態(tài)的切入點(diǎn)每次方法的調(diào)用都要去進(jìn)行匹配
                        //而靜態(tài)切入點(diǎn)則回緩存之前的匹配結(jié)果值 
                        if (mm.isRuntime()) {
                            //動(dòng)態(tài)切入點(diǎn) 則會(huì)創(chuàng)建一個(gè)InterceptorAndDynamicMethodMatcher對(duì)象
                            //這個(gè)對(duì)象包含MethodInterceptor和MethodMatcher 的實(shí)例
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            //添加到列表中
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            //如果是引介增強(qiáng)
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    //將Advisor轉(zhuǎn)換為Interceptor
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            //以上兩種都不是
            else {
                //將Advisor轉(zhuǎn)換為Interceptor
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        return interceptorList;
    }

從上面代碼可以總結(jié)下流程:
1、循環(huán)目標(biāo)方法的所有Advisor
2辱挥、判斷Advisor的類型
? a犁嗅、如果是PointcutAdvisor的類型,則判斷此Advisor是否適用于此目標(biāo)方法
?b晤碘、如果是IntroductionAdvisor引介增強(qiáng)類型褂微,則判斷此Advisor是否適用于此目標(biāo)方法
?c、如果以上都不是园爷,則直接轉(zhuǎn)換為Interceptor類型宠蚂。

不管是Advisor哪一類型最終都會(huì)registry.getInterceptors(advisor);進(jìn)行轉(zhuǎn)換,那么我們來(lái)看看這個(gè)方法:

g童社、registry.getInterceptors(advisor):
我們來(lái)先看看registry的獲取代碼:

 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
=========
public abstract class GlobalAdvisorAdapterRegistry {
    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();

    
    public static AdvisorAdapterRegistry getInstance() {
        return instance;
    }
=========
public DefaultAdvisorAdapterRegistry() {
        //前置通知適配器
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        //后置返回通知適配器
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        //后置異常通知適配器
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

接著我們來(lái)看看:registry.getInterceptors的代碼:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        //從Advisor中獲取 Advice
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                //轉(zhuǎn)換為對(duì)應(yīng)的 MethodInterceptor類型
                //AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor  ThrowsAdviceInterceptor
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }

l求厕、攔截器連的調(diào)用過(guò)程:
invoke方法中的:

//如果AOP攔截器執(zhí)行鏈不為空  說(shuō)明有AOP通知存在
 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//開(kāi)始調(diào)用
 retVal = invocation.proceed();

那么我們來(lái)看看這個(gè)方法:

public Object proceed() throws Throwable {
        // 如果執(zhí)行到鏈條的末尾則直接調(diào)用連接點(diǎn)方法即直接調(diào)用目標(biāo)方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //調(diào)用目標(biāo)方法
            return invokeJoinpoint();
        }
        //獲取集合中的 MethodInterceptor
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果是InterceptorAndDynamicMethodMatcher類型
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            //這里每一次都去匹配是否適用于這個(gè)目標(biāo)方法
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                //如果匹配則直接調(diào)用 MethodInterceptor的invoke方法
                return dm.interceptor.invoke(this);
            }
            else {
                //如果不適用于此目標(biāo)方法 則繼續(xù)執(zhí)行下一個(gè)鏈條 遞歸調(diào)用
                return proceed();
            }
        }
        else {
            //直接調(diào)用 MethodInterceptor的invoke方法 
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

看下invokeJoinpoint方法(直接掉用目標(biāo)類的方法):

protected Object invokeJoinpoint() throws Throwable {
        //this.target 目標(biāo)對(duì)象
        //this.method 目標(biāo)方法
        this.arguments 目標(biāo)方法參數(shù)信息
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {

        // Use reflection to invoke the method.
        try {
            //設(shè)置方法可見(jiàn)性
            ReflectionUtils.makeAccessible(method);
            //反射調(diào)用  最終是通過(guò)反射去調(diào)用目標(biāo)方法
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            throw ex.getTargetException();
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                    method + "] on target [" + target + "]", ex);
        }
        catch (IllegalAccessException ex) {
            throw new AopInvocationException("Could not access method [" + method + "]", ex);
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扰楼,隨后出現(xiàn)的幾起案子呀癣,更是在濱河造成了極大的恐慌,老刑警劉巖弦赖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件项栏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蹬竖,警方通過(guò)查閱死者的電腦和手機(jī)沼沈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)币厕,“玉大人列另,你說(shuō)我怎么就攤上這事〉┳埃” “怎么了访递?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)同辣。 經(jīng)常有香客問(wèn)我拷姿,道長(zhǎng),這世上最難降的妖魔是什么旱函? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任响巢,我火速辦了婚禮,結(jié)果婚禮上棒妨,老公的妹妹穿的比我還像新娘踪古。我一直安慰自己含长,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布伏穆。 她就那樣靜靜地躺著拘泞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枕扫。 梳的紋絲不亂的頭發(fā)上陪腌,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音烟瞧,去河邊找鬼诗鸭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛参滴,可吹牛的內(nèi)容都是我干的强岸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼砾赔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蝌箍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起暴心,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤妓盲,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后酷勺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體本橙,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扳躬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年脆诉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贷币。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击胜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出役纹,到底是詐尸還是另有隱情偶摔,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布促脉,位于F島的核電站辰斋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘸味。R本人自食惡果不足惜宫仗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旁仿。 院中可真熱鬧藕夫,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至滩褥,卻和暖如春病蛉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铸题。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工铡恕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丢间。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓探熔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親烘挫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诀艰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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

  • AOP概述 AOP定義概念這里寫(xiě)圖片描述這里我們只要關(guān)注三個(gè)重點(diǎn)的概念:1)基礎(chǔ)(base):目標(biāo)對(duì)象2)切面(a...
    鐵甲依然在_978f閱讀 311評(píng)論 0 0
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)饮六,斷路器其垄,智...
    卡卡羅2017閱讀 134,664評(píng)論 18 139
  • 【今日話題】 迄今為止,除了父母之外卤橄,誰(shuí)對(duì)你的影響最大绿满?ta教會(huì)了你什么? 對(duì)我影響最大的那應(yīng)該是我的老公吧窟扑,他...
    娜天同意閱讀 267評(píng)論 2 1
  • (2017-10-29-周日 16:30:54) 在窗口中部,左端
    菜五閱讀 98評(píng)論 0 0
  • “會(huì)” 和“懂”真的是相差甚遠(yuǎn)殖属,就拿打羽毛球來(lái)說(shuō)姐叁,很多人都會(huì)打,但是很多人不一定懂洗显。真正懂的人不僅知道打羽毛...
    呼呼海爸閱讀 890評(píng)論 0 0