SpringAop

近期打算把Spring源碼系統(tǒng)性的刷一遍,話不多說,那就先從Aop開始吧~~~
一、動態(tài)代理:

1颅湘、cglib的動態(tài)代理


     UserService target =new UserService();

    // 通過cglib技術

    Enhancer enhancer =new Enhancer();

    enhancer.setSuperclass(UserService.class);

    // 定義額外邏輯,也就是代理邏輯

    enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {

    @Override

    public Objectintercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {

        System.out.println("before...");

        Object result = methodProxy.invoke(target, objects);

        System.out.println("after...");

        return result;

    }

}});

// 動態(tài)代理所創(chuàng)建出來的UserService對象

UserService userService = (UserService) enhancer.create();

//System.out.println(userService);

// 執(zhí)行這個userService的test方法時栗精,就會額外會執(zhí)行一些其他邏輯

userService.test();

上面是通過cglib來實現(xiàn)的代理對象的創(chuàng)建闯参,是基于父子類的,被代理類(UserService)是父類悲立,代理類是子類鹿寨,代理對象就是代理類的實例對象。

2薪夕、JDK的動態(tài)代理

        UserService target = new UserService();

        // UserInterface接口的代理對象
        Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before...");
                Object result = method.invoke(target, args);
                System.out.println("after...");
                return result;
            }
        });

        UserInterface userService = (UserInterface) proxy;
        userService.test();

jdk的動態(tài)代理必須依賴接口脚草,所以生產(chǎn)的代理對象和被代理對象是兄弟關系,再采用依賴注入時必須使用接口接收代理對象原献。

二馏慨、ProxyFactory
上面我們介紹了兩種動態(tài)代理技術埂淮,那么在Spring中進行了封裝,封裝出來的類叫做ProxyFactory写隶,表示是創(chuàng)建代理對象的一個工廠倔撞,使用起來會比上面的更加方便,比如:

        UserService target = new UserService();

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor(){

            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }

        });

        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();

通過ProxyFactory樟澜,我們可以不再關心到底是用cglib還是jdk動態(tài)代理了误窖,ProxyFactory會幫我們?nèi)ヅ袛啵绻鸘serService實現(xiàn)了接口秩贰,那么ProxyFactory底層就會用jdk動態(tài)代理霹俺,如果沒有實現(xiàn)接口,就會用cglib技術毒费,上面的代碼丙唧,就是由于UserService實現(xiàn)了UserInterface接口,所以最后產(chǎn)生的代理對象是UserInterface類型觅玻。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            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.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

同時我們也看一下Advice的接口定義

/**
 * Tag interface for Advice. Implementations can be any type
 * of advice, such as Interceptors.
 *
 * @author Rod Johnson
 * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
 */
public interface Advice {

}

三想际、Advisor
跟Advice類似的還有一個Advisor的概念,一個Advisor是有一個Pointcut和一個Advice組成的溪厘,通過Pointcut可以指定要需要被代理的邏輯胡本,比如一個UserService類中有兩個方法,按上面的例子畸悬,這兩個方法都會被代理侧甫,被增強,那么我們現(xiàn)在可以通過Advisor蹋宦,來控制到具體代理哪一個方法披粟,比如:

        UserService target = new UserService();

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(new PointcutAdvisor() {
            @Override
            public Pointcut getPointcut() {
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return method.getName().equals("test");
                    }
                };
            }

            @Override
            public Advice getAdvice() {
                return new MethodInterceptor() {
                    @Override
                    public Object invoke(MethodInvocation invocation) throws Throwable {
                        System.out.println("before...");
                        Object result = invocation.proceed();
                        System.out.println("after...");
                        return result;
                    }
                };
            }

            @Override
            public boolean isPerInstance() {
                return false;
            }
        });

        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();

四、Spring中創(chuàng)建代理對象的方式
下面我們來看一下Spring中創(chuàng)建代理對象的方式冷冗,首先來看ProxyFactoryBean:

    @Bean
    public ProxyFactoryBean userServiceProxy(){
        UserService userService = new UserService();

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        return proxyFactoryBean;
    }
    @Resource(name = "userServiceProxy")
    private UserInterface userInterface;

    @PostConstruct
    public void print(){
        userInterface.test();
    }

ProxyFactoryBean實現(xiàn)了FactoryBean接口守屉。FactoryBean是Spring中一個比較重要的切入點,在bean的初始化過程中Spring會調(diào)用getObject()方法獲取到代理對象蒿辙,并放入bean容器拇泛,所以當我們通過@Resource(name = "userServiceProxy")注解拿到的其實是UserInterface的代理對象

         /**
     * Return a proxy. Invoked when clients obtain beans from this factory bean.
     * Create an instance of the AOP proxy to be returned by this factory.
     * The instance will be cached for a singleton, and create on each call to
     * {@code getObject()} for a proxy.
     * @return a fresh AOP proxy reflecting the current state of this factory
     */
    @Override
    @Nullable
    public Object getObject() throws BeansException {
        initializeAdvisorChain();
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }

ProxyFactoryBean得自己指定被代理的對象,那么我們可以通過BeanNameAutoProxyCreator來通過指定某個bean的名字思灌,來對該bean進行代理碰镜。

    @Bean
    public MethodInterceptor myAroundAdvise(){
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }

@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
   BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
   beanNameAutoProxyCreator.setBeanNames("userSe*");
   beanNameAutoProxyCreator.setInterceptorNames("myAroundAdvise");
   beanNameAutoProxyCreator.setProxyTargetClass(true);

    return beanNameAutoProxyCreator;
}

BeanNameAutoProxyCreator中實現(xiàn)了getAdvicesAndAdvisorsForBean()方法

protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

        if (this.beanNames != null) {
            for (String mappedName : this.beanNames) {
                if (FactoryBean.class.isAssignableFrom(beanClass)) {
                    if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
                        continue;
                    }
                    mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
                }
                if (isMatch(beanName, mappedName)) {
                    return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
                }
                BeanFactory beanFactory = getBeanFactory();
                if (beanFactory != null) {
                    String[] aliases = beanFactory.getAliases(beanName);
                    for (String alias : aliases) {
                        if (isMatch(alias, mappedName)) {
                            return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
                        }
                    }
                }
            }
        }
        return DO_NOT_PROXY;
    }

該方法就會根據(jù)beanName找到對應的Interceptors,而BeanNameAutoProxyCreator本身繼承于AbstractAutoProxyCreator习瑰,AbstractAutoProxyCreator作為BeanPostProcessor就會在bean初始化后postProcessAfterInitialization()方法中創(chuàng)建該bean的代理對象放入bean容器绪颖。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

細節(jié)在wrapIfNecessary中,此時就會調(diào)用BeanNameAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法

  protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }  

通過BeanNameAutoProxyCreator可以對批量的Bean進行AOP,并且指定了代理邏輯柠横,指定了一個InterceptorName窃款,也就是一個Advise,前提條件是這個Advise也得是一個Bean牍氛,這樣Spring才能找到的晨继,但是BeanNameAutoProxyCreator的缺點很明顯,它只能根據(jù)beanName來指定想要代理的Bean搬俊。
而通過DefaultAdvisorAutoProxyCreator會直接去找所有Advisor類型的Bean紊扬,根據(jù)Advisor中的PointCut和Advice信息,確定要代理的Bean以及代理邏輯唉擂。

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(){
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");

        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });

        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }

當使用DefaultAdvisorAutoProxyCreator時餐屎,AbstractAutoProxyCreator.wrapIfNecessary方法中,就會調(diào)用DefaultAdvisorAutoProxyCreator的父類AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法

protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

進入findEligibleAdvisors方法玩祟,我們就可以看到此時會先找到所有的Advisor bean腹缩,然后再去和beanClass匹配,最后得到滿足條件的Advisor空扎,并排序:

         /**
     * Find all eligible Advisors for auto-proxying this class.
     * @param beanClass the clazz to find advisors for
     * @param beanName the name of the currently proxied bean
     * @return the empty List, not {@code null},
     * if there are no pointcuts or interceptors
     * @see #findCandidateAdvisors
     * @see #sortAdvisors
     * @see #extendAdvisors
     */
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

五藏鹊、Spring中創(chuàng)建代理對象的細節(jié)
當我們進入AbstractAutoProxyCreator.wrapIfNecessary()方法,最后就會看到createAopProxy().getProxy(classLoader)方法转锈,getProxy方法分別對應JDK和cglib兩種實現(xiàn)盘寡,首先來看JDK的實現(xiàn),Spring中JdkDynamicAopProxy類封裝了JDK的實現(xiàn)細節(jié)撮慨,并且實現(xiàn)了InvocationHandler接口

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

在Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)時將當前JdkDynamicAopProxy對象傳入竿痰,這樣實際執(zhí)行的就是JdkDynamicAopProxy.invoke方法,這里使用了典型的策略模式

        public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

這里的關鍵邏輯就是拿到方法的攔截器鏈甫煞,List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);然后遞歸調(diào)用MethodInterceptor.invoke方法,invoke方法比較長冠绢,這里只截取關鍵的幾行:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              ...
                        // 根據(jù)代理對象和方法找到攔截器鏈
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            
            if (chain.isEmpty()) {
                    //如果chain為空抚吠,直接將target傳入,通過反射執(zhí)行被代理對象的方法
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                //構建MethodInvocation
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
        ...
    }

進入invocation.proceed()

public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
                //這里會判斷是否是動態(tài)方法匹配攔截器
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            //普通攔截器
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

通常我們定義的都是普通攔截器弟胀,進入((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)會發(fā)現(xiàn)有很多的實現(xiàn)楷力,我們以AfterReturningAdviceInterceptor為例,注意這里傳入了this

public Object invoke(MethodInvocation mi) throws Throwable {
        //這里其實仍然執(zhí)行的是ReflectiveMethodInvocation.proceed()
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

到這里其實就十分清晰了孵户,正是通過遞歸的方式來執(zhí)行多個MethodInterceptor
六萧朝、AnnotationAwareAspectJAutoProxyCreator
在我們實際使用中,很少直接創(chuàng)建AdvisorBean夏哭,更多是通過@Aspect來使用的检柬,并且通過引入@EnableAspectJAutoProxy來獲得Spring對注解@Aspect的支持,這里其實就用到了AnnotationAwareAspectJAutoProxyCreator

//通過@Import引入AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

進入AspectJAutoProxyRegistrar:

public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                //在此處注冊了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

AnnotationAwareAspectJAutoProxyCreator重寫了findCandidateAdvisors方法竖配,增加了對@Aspect解析:

protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }

七何址、SpringAop關鍵類的繼承關系


image.png

AnnotationAwareAspectJAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator里逆,重寫了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator只能找到所有Advisor類型的Bean對象用爪,但是AnnotationAwareAspectJAutoProxyCreator除開可以找到所有Advisor類型的Bean對象原押,還能把@Aspect注解所標注的Bean中的@Before等注解及方法進行解析,并生成對應的Advisor對象偎血。

八诸衔、最后我們來總結一下,SpringAop其實就是通過BeanPostProcessor結合JDK或者cglib的動態(tài)代理來實現(xiàn)對bean的增強颇玷,結合使用了工廠模式笨农、策略模式、責任鏈模式等亚隙,對使用者屏蔽掉了底層實現(xiàn)磁餐,可見設計者的深厚功力。所以說多刷源碼真的漲見識~~~

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阿弃,一起剝皮案震驚了整個濱河市诊霹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渣淳,老刑警劉巖脾还,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異入愧,居然都是意外死亡鄙漏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門棺蛛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怔蚌,“玉大人,你說我怎么就攤上這事旁赊¤胗唬” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵终畅,是天一觀的道長籍胯。 經(jīng)常有香客問我,道長离福,這世上最難降的妖魔是什么杖狼? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮妖爷,結果婚禮上蝶涩,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好子寓,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布暗挑。 她就那樣靜靜地躺著,像睡著了一般斜友。 火紅的嫁衣襯著肌膚如雪炸裆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天鲜屏,我揣著相機與錄音烹看,去河邊找鬼。 笑死洛史,一個胖子當著我的面吹牛惯殊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播也殖,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼土思,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了忆嗜?” 一聲冷哼從身側(cè)響起己儒,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捆毫,沒想到半個月后闪湾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡绩卤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年途样,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片濒憋。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡何暇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凛驮,到底是詐尸還是另有隱情裆站,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布辐烂,位于F島的核電站遏插,受9級特大地震影響捂贿,放射性物質(zhì)發(fā)生泄漏纠修。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一厂僧、第九天 我趴在偏房一處隱蔽的房頂上張望扣草。 院中可真熱鬧,春花似錦、人聲如沸辰妙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽密浑。三九已至蛙婴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尔破,已是汗流浹背街图。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懒构,地道東北人餐济。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像胆剧,于是被迫代替她去往敵國和親絮姆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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