spring源码系列-aop源码刨析

上一篇文章spring源码系列-从@Autowired与@Resource异同中看依赖注入中,我们着重分析了依赖注入的实现。我们都是知道spring是一个ioc容器(即依赖注入),同时提供了aop功能。既然我们前面已经与ioc深入交流过,那么aop这位大佬我们也不能放过。究竟aop是用了什么手段,才坐上了spring扛把子的头把交椅呢?让我们一探究竟。本文可以分为如下几个模块

  1. aop
    1.1 什么是aop
    1.2 spring aop 用法
    1.3 两个问题
    1.3.1 切入实现类的自有方法
    1.3.2 切入未实现接口的final类
  2. 代理
    2.1 静态代理
    2.2 动态代理
    2.2.1 JDK proxy
    2.2.1.1 jdk proxy 用法
    2.2.2 cglib proxy
  3. spring aop 源码分析
    3.1 动态aop 自定义标签
    3.1.1 开启aop 自定义标签
    3.1.2 aop 自定义标签标签的解析过程
    3.2 注册AnnotationAwareAspectJAutoProxyCreator
    3.2.1 处理proxy-target-class属性和expose-proxy属性
    3.3 创建aop
    3.3.1 获取增强方法或者增强器
    3.3.1.1 寻找所有增强器和增强方法
    3.3.1.2 寻找匹配增强器
    3.3.2 根据增强方法创建代理
    3.3.2.1 初始化ProxyFactory
    3.3.2.2 选择代理类型
    3.3.3 创建代理
    3.3.2.3 获取代理
    3.4 代理的方法拦截和方法回调
    3.4.1 JdkDynamicAopProxy方法拦截
    3.4.1.1 proceed 方法的调用
    3.4.2 cglib 方法回调
  4. 总结

1. 前言

用过spring的相信都用过spring的Aspectj和transaction,我们只需要编写相应的业务逻辑,然后开启配置就能实现切面和事物。不知道大家有没有想过,这些功能spring是如何做的,这就是下面我们要探讨的内容。当然本文不涉及事物的源码,事物源码刨析会放在下一篇文章中,单独分析。

1.1 什么是aop

究竟何为aop呢?

  • aop 即Aspect Oriented Programming,面向切面编程。
  • aop 将业务共通点进行切面提取,横切到代码中
  • aop 是对oop(Object Oriented Programming),面向对象编程的补充
  • oop 是一种纵向的层级关系,强调的是通过类之间的关系(组合,引用,继承等)来实现精准的逻辑单元
  • aop 是一种横向的关系,强调的是业务共通性的切面提取,然后横切到代码中。

    上面的话可能有点晦涩,举个栗子。我们现在有很多service,现在有个需求要统计各个service的代码的执行时间。那么这个需求要如何实现呢?
  • 基于oop的实现方法:每个service里增加个stopwatch计时。service和统计紧耦合。
    哪天统计的内容改变,我们就需要把每个service中的统计方法改一遍。service和
  • 基于aop的实现方法:定义切面,开启aop功能,ok。无需硬编码到每个service,后续有修改只需要改动切面内容即可。service和统计松耦合。

1.2 spring aop 用法

下面演示一段spring aop的基本用法

  • 定义切面
@Aspect
public class MyAspectJ {
    //定义切点,即要切入的范围
    @Pointcut(value = "execution(* com.moxieliunian.spring.service.*.*(..))")
    public void something(){
    }
    @Before("something()")
    public void before(){
        System.out.println("before***********");
    }
    @After("something()")
    public void after(){
        System.out.println("after***************");
    }
    @Around("execution(* com.moxieliunian.spring.service.*.*(..)) && args(name)")
    public Object around(ProceedingJoinPoint joinPoint,String name){
        System.out.println("around***********start****name:"+name);
        name = "moxieliunian";
        Object result=null;
        try {
            result=joinPoint.proceed(new Object[]{name});
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around***********end");
        return result;
    }

}
  • 定义代理类
public interface  TestService  {

    void sayHello(String name);

}

public class TestServiceImpl implements TestService {
    @Override
    public void sayHello(String name) {
        System.out.println("hello:"+name);
    }
}

  • 开启spring的aop 功能,同时导入需要的aspectjweaver包
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--开启spring aop 功能-->
        <aop:aspectj-autoproxy/>
        <!--注册切面,使其由spring管理-->
        <bean id="ms" class="com.moxieliunian.spring.aop.MyAspectJ"/>
        <!--配置bean-->
        <bean id="tsi" class="com.moxieliunian.spring.service.impl.TestServiceImpl"/>
</beans>

这样就完成了aop的功能,我们来测试一下

 public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-config.xml");
        TestService testService=(TestService)applicationContext.getBean("tsi");
        System.out.println(testService.sayHello("test"));
    }

结果如下

around***********start****name:test
before***********
hello:moxieliunian
around***********end
after***************

可以看到我们定义的切面生效了,是不是很easy。spring 的aop可以很方便的让我们把业务共通的东西提取为切面,降低了系统的耦合度。带来这种便捷性的同时,我们需要更多的去思考这种黑盒后面的实现,以及我们可能会踩到的坑。

1.3 两个问题

下面我们看以下两个case

1.3.1 切入实现类的自有方法

public interface  TestService  {

    String sayHello(String name);

}
public class TestServiceImpl implements TestService {
    @Override
    public String sayHello(String name) {
        return "hello:"+name;
    }

    /**
     * 这个方法未在接口里定义
     * @param hi hi
     * @return String
     */
    public String sayHi(String hi){
        return "hi:"+hi;
    }
}
public class TestAop {
    public static void main(String[] args) {
        ApplicationContext applicationContext=
                new ClassPathXmlApplicationContext("spring-config.xml");
        TestServiceImpl testService=
                (TestServiceImpl)applicationContext.getBean("tsi");
        System.out.println(testService.sayHi("test"));
    }
}

执行结果

Exception in thread "main" java.lang.ClassCastException: 
com.sun.proxy.$Proxy8 cannot be cast to com.moxieliunian.spring.service.impl.TestServiceImpl
    at com.moxieliunian.spring.TestAop.main(TestAop.java:16)

可以看到,无法切入接口实现类的自有方法

1.3.2 切入未实现接口的final类

public  class TestFinalImpl {
    public String sayHello(String name){
        return "say Hello from:"+name;
    }
}

public static void main(String[] args) {
        ApplicationContext applicationContext=
                new ClassPathXmlApplicationContext("spring-config.xml");
        TestFinalImpl testFinal=
                (TestFinalImpl)applicationContext.getBean("tfi");
        System.out.println(testFinal.sayHello("test"));
    }

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--开启spring aop 功能-->
        <aop:aspectj-autoproxy/>
        <!--注册切面,使其由spring管理-->
        <bean id="ms" class="com.moxieliunian.spring.aop.MyAspectJ"/>
        <!--配置bean-->
        <bean id="tsi" class="com.moxieliunian.spring.service.impl.TestServiceImpl"/>
        <!--配置bean-->
        <bean id="tfi" class="com.moxieliunian.spring.service.TestFinalImpl"/>
</beans>

执行结果

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tfi' defined in class path resource [spring-config.xml]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.moxieliunian.spring.service.TestFinalImpl: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class com.moxieliunian.spring.service.TestFinalImpl
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)

可以看到,无法切入未实现接口的final类
通过以上case,我们可以得到如下问题

  1. 为什么无法切入接口实现类的自有方法?
  2. 为什么无法切入未实现接口的final类?
  3. 为什么around方法执行中才执行before方法?为什么around方法执行完才执行after方法?

2. 代理

我们都知道spring的aop是基于代理实现的,那么要解释spring的aop,就有必要先回顾一下代理的相关内容。java中的代理按照代理类的生成时间可以分为静态代理与动态代理。动态代理又分为jdk动态代理(接口代理),cglib代理(子类代理)。

2.1 静态代理

所谓静态代理,即在编译期已经存在的代理类,一般手动指定代理类,下面是一个简单的例子。

//接口
public interface IOriginalService {
    void serviceMethod();
}

//实现类
public class OriginalServiceImpl implements IOriginalService {
    @Override
    public void serviceMethod() {
        System.out.println("OriginalServiceImpl do something....");
    }
}
//代理类
public class OriginalServiceProxy implements IOriginalService {
    private IOriginalService originalService;

    public OriginalServiceProxy(IOriginalService originalService) {
        this.originalService = originalService;
    }

    @Override
    public void serviceMethod() {
        System.out.println("OriginalServiceProxy do something begin ");
        originalService.serviceMethod();
        System.out.println("OriginalServiceProxy do something end ");
    }
}

测试一下

    public static void main(String[] args) {
        IOriginalService iOriginalService=new OriginalServiceImpl();
        IOriginalService originalServiceProxy=new OriginalServiceProxy(iOriginalService);
        originalServiceProxy.serviceMethod();
    }

运行结果如下

OriginalServiceProxy do something begin 
OriginalServiceImpl do something....
OriginalServiceProxy do something end 

可以看到静态代理在编译期已经指定了代理类是谁。如果将来被代理的类方法变动,则代理类也要手动修改代码

2.2 动态代理

所谓动态代理指的是在运行期间才生成代理类的代理技术。根据类结构的不同,又分为接口代理(JDK Proxy)和 类代理(cglib proxy)
注意:spring选择代理的时候,默认情况下,会根据类的结构来选择代理的实现方式。即如果类实现了接口,则使用jdk proxy。反之使用cglib proxy。
下面对这两种代理方式做基本演示:

2.2.1 jdk proxy

2.2.1.1 jdk proxy 用法

//接口
public interface IOriginalService {
    void serviceMethod();
}
//实现类
public class OriginalServiceImpl implements IOriginalService {
    @Override
    public void serviceMethod() {
        System.out.println("OriginalServiceImpl do something....");
    }
}

test

 public static void main(String[] args) {
        IOriginalService iOriginalService=new OriginalServiceImpl();
        InvocationHandler handler =  (proxy,method,as)->{
            System.out.println("jdk proxy start");
            method.invoke(iOriginalService, as);
            System.out.println("jdk proxy end");
            return null;
        };
        IOriginalService originalService=(IOriginalService)  Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IOriginalService.class},handler);
        originalService.serviceMethod();
    }

运行结果

jdk proxy start
OriginalServiceImpl do something....
jdk proxy end

可以看到关键在于InvocationHandler的定义,同时我们注意到Proxy.newProxyInstance第二个参数必须传入要代理类的接口名称,所以这也就是为什么其只能代理实现接口的类。

2.2.1.1 jdk proxy 实现原理

可能有的同学会好奇jdk动态代理的实现原理是什么,其实核心就在与如何将InvocationHandler作为参数传递给要生成的代理类,同时加载该代理类到内存中使用。
大致看下生成的proxyclasss

package com.sun.proxy;

import com.moxieliunian.spring.proxy.staticproxy.IOriginalService;
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 IOriginalService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void serviceMethod() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.IOriginalService").getMethod("serviceMethod");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看到$Proxy0 通过继承 Proxy 持有了Invocation的引用,同时通过实现 代理接口,重写了代理接口的实现

   public final void serviceMethod() throws  {
        try {
            //调用自定义InvocationHandler的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

通过调用自定义InvocationHandler的invoke方法,实现了代理

2.2.2 cglib proxy

public class OriginalServiceImpl implements IOriginalService {
    @Override
    public void serviceMethod() {
        System.out.println("OriginalServiceImpl do something....");
    }
}

test

   public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(OriginalServiceImpl.class);
        //设置方法拦截
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("cglib start");
                methodProxy.invokeSuper(o,objects);
                System.out.println("cglib end");
                return null;
            }
        });
        OriginalServiceImpl originalService=(OriginalServiceImpl) enhancer.create();
        originalService.serviceMethod();
    }

运行结果

cglib start
OriginalServiceImpl do something....
cglib end

看下cglib生成的代理class

public class OriginalServiceImpl$$EnhancerByCGLIB$$26f0d50b extends OriginalServiceImpl implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$serviceMethod$0$Method;
    private static final MethodProxy CGLIB$serviceMethod$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.OriginalServiceImpl$$EnhancerByCGLIB$$26f0d50b");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$serviceMethod$0$Method = ReflectUtils.findMethods(new String[]{"serviceMethod", "()V"}, (var1 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.OriginalServiceImpl")).getDeclaredMethods())[0];
        CGLIB$serviceMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "serviceMethod", "CGLIB$serviceMethod$0");
    }

    final void CGLIB$serviceMethod$0() {
        super.serviceMethod();
    }

    public final void serviceMethod() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$serviceMethod$0$Method, CGLIB$emptyArgs, CGLIB$serviceMethod$0$Proxy);
        } else {
            super.serviceMethod();
        }
    }

可以看到cglib是通过extends 目标类,即生成目标类的子类的方式来实现代理的。这也就解释了final类不能被cglib代理的原因


3. spring aop 源码分析

前面我们介绍了spring aop的用法,及代理的种类及实现原理。终于到了本文的核心部分,源码分析。其实总结的过程就是这样,往往要解释清楚一个点,需要N个点做铺垫。这个过程往往是比较劳心费神,同时也是提升最大的。

3.1 动态aop 自定义标签

3.1.1 开启aop 自定义标签

上面我们演示使用spring aop的时候,我们首先在配置文件中开启了aop功能

        <!--开启spring aop 功能-->
        <aop:aspectj-autoproxy/>

那么解析aop的源码也得从这个配置入手。先说结果:这个配置文件的最终作用是注册AnnotationAwareAspectJAutoProxyCreator类。那么就又出来两个问题:

  • 问题1<aop:aspectj-autoproxy/> 是如何解析到 AnnotationAwareAspectJAutoProxyCreator类?
  • 问题2AnnotationAwareAspectJAutoProxyCreator类又有什么作用,为什么要注册它?

3.1.2 aop 自定义标签标签的解析过程

解析<aop:aspectj-autoproxy/> 就是典型的自定义节点的解析过程,
先给出流程图,再对细节部分做出说明。


aop 自定义标签标签的解析过程.png

1.加载Bean的定义文件
关键在于 XmlBeanDefinitionReader.loadBeanDefinitions 方法

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //开始加载配置文件,转换bean定义
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
}
  1. 获取document 对象,准备解析document 转换为BeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
try {
           //将流转换为document
            Document doc = doLoadDocument(inputSource, resource);
          //解析document
            return registerBeanDefinitions(doc, resource);
        }
}
  1. 解析document,并创建XmlReader上下文(该上下文包含默认的Namespace解析器)
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //创建XmlReaderContext
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
public XmlReaderContext createReaderContext(Resource resource) {
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, getNamespaceHandlerResolver());
    }

public NamespaceHandlerResolver getNamespaceHandlerResolver() {
        if (this.namespaceHandlerResolver == null) {
            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        }
        return this.namespaceHandlerResolver;
    }

protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
        return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
    }

这里面有个很关键的地方,即DefaultNamespaceHandlerResolver,该类定义了 从"META-INF/spring.handlers"中加载对应的key,value到 private volatile Map<String, Object> handlerMappings。为以后解析自定义配置文件的Namespace提供查找依据
如 spring-aop-4.3.18.RELEASE.jar 中的spring.handlers 中定义如下

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

则以后遇到namespace为http://www.springframework.org/schema/aop的xml标签时,则会去取AopNamespaceHandler作为Namespace解析器。

  1. 解析document,将其转换为BeanDefinition
protected void doRegisterBeanDefinitions(Element root) {
        preProcessXml(root);
        //解析配置文件
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);
}
  1. 开始配置文件解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        //aop 的标签解析会走这里
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }
  1. 解析自定义配置文件
    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
  • 从private volatile Map<String, Object> handlerMappings 中根据key=http\://www.springframework.org/schema/aop,取到value=org.springframework.aop.config.AopNamespaceHandler
  • 同时调用 AopNamespaceHandler.init 方法,为aop标签的每个属性绑定一个BeanDefinitionParser
  • 调用上一步绑定的AspectJAutoProxyBeanDefinitionParser.parse 方法注册AnnotationAwareAspectJAutoProxyCreator
    下面是AopNamespaceHandler的init 实现
public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

到此为止,我们终于完成了<aop:aspectj-autoproxy/>配置的解析,可以看到spring在解析的过程中,有很多考虑的地方,篇幅限制,我们只是理出了其骨架。

3.2 注册AnnotationAwareAspectJAutoProxyCreator

调用AspectJAutoProxyBeanDefinitionParser.parse方法来注册AnnotationAwareAspectJAutoProxyCreator。

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }

这里有个特别关键的点AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary

    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {

        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }
  1. 注册AnnotationAwareAspectJAutoProxyCreator,这个关键类的作用我们后面再详细说
  2. 处理proxy-target-class属性和expose-proxy属性

3.2.1 处理proxy-target-class属性和expose-proxy属性

上面我们说到处理proxy-target-class属性和expose-proxy属性,那么这俩属性有什么作用,我们可以从下面的代码中得到答案

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
            boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }
    }
  • proxy-target-class:spring aop在创建代理的时候,会选择jdk动态代理或者cglib代理的方式创建。选择的依据为:如果当前类实现了至少一个接口,则会使用jdk动态代理,所有该目标类型实现的接口都将被代理(基于实现接口)。如果当前类没有实现接口,则使用cglib创建代理(基于继承当前类)。如果要强制使用cglib代理(通过asm生成字节码,比jdk 代理效率高),则将proxy-target-class设置为true即可。但是要注意cglib代理不能代理final类(final类不能被继承),这也就是问题1和问题2 的答案
  • expose-proxy:暴露当前代理。当使用JDK代理的时候,方法内部的自我调用将无法实施切面中的增强。比如下面代码
public interface AService {
    void a();
    void b();
}

public class AServiceImpl implements AService {
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void a() {
        this.b();
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void b() {

    }
}

此时this.b()方法被调用的时候,其方上配置的开启新事物的增强将不会生效。为了解决这个问题,我们可以将expose-proxy 设置为true,暴露当前代理,并通过AopContext.currentProxy()方式调用

public class AServiceImpl implements AService {
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void a() {
        ((AService)AopContext.currentProxy()).b();
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void b() {

    }
}

值得注意的是,使用cglib不会有上面的问题,因为cglib是对所有方法做了增强,这也是cglib和jdk代理的不同点之一,关于这个我们后续会详细解释。


3.3 创建aop

还记得我们上面说的AnnotationAwareAspectJAutoProxyCreator吗,前面做的核心工作就是为了注册AnnotationAwareAspectJAutoProxyCreator。那么这个AnnotationAwareAspectJAutoProxyCreator究竟是怎么实现了aop的创建。下面我们来一层一层剥开她的心。


AbstractAutoProxyCreator类图

从类图中我们看到了一个熟悉的接口BeanPostProcessor。我们都知道类初始化的的时候,会调用所有BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,看下AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInitialization和postProcessAfterInitialization方法,这也是我们分析aop的入口所在

    /**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

关键在于wrapIfNecessary(bean, beanName, cacheKey),它封装了实现aop的核心逻辑。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && 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;
    }

流程图如下


创建aop流程图.jpg

其中蓝色部分都是AbstractAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator所实现的功能,也是整个aop的核心逻辑。关键流程为

  1. 获取增强方法或者增强器-getAdvicesAndAdvisorsForBean
  2. 根据增强方法创建代理-createProxy
    下面我们详细分析这两个步骤

3.3.1 获取增强方法或者增强器

获取增强方法或者增强器又分为两个步骤

  1. 寻找所有增强器和增强方法
  2. 寻找匹配增强器
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //查找所有增强器和增强方法
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //选择适用当前bean的并应用
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

3.3.1.1 寻找所有增强器和增强方法

试想如果我们要寻找所有增强器和增强方法,最简单直接的做法就是遍历所有的bean,找到type为Aspect的bean,并包装。其实spring也是这么做的:

  1. 获取所有的beanname(这个所有指的是所有在beanfactory中注册的bean)
  2. 遍历所有beanname,找到声明为Aspect 的类。
  3. 对步骤2 查找到的bean进行增强器的提取。
  4. 将提取的结果加入缓存。
public List<Advisor> buildAspectJAdvisors() {
        List<String> aspectNames = this.aspectBeanNames;

        if (aspectNames == null) {
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {
                    List<Advisor> advisors = new LinkedList<Advisor>();
                    aspectNames = new LinkedList<String>();
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
                    for (String beanName : beanNames) {
                        if (!isEligibleBean(beanName)) {
                            continue;
                        }
                        // We must be careful not to instantiate beans eagerly as in this case they
                        // would be cached by the Spring container but would not have been weaved.
                        Class<?> beanType = this.beanFactory.getType(beanName);
                        if (beanType == null) {
                            continue;
                        }
                        if (this.advisorFactory.isAspect(beanType)) {
                            aspectNames.add(beanName);
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                MetadataAwareAspectInstanceFactory factory =
                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                if (this.beanFactory.isSingleton(beanName)) {
                                    this.advisorsCache.put(beanName, classAdvisors);
                                }
                                else {
                                    this.aspectFactoryCache.put(beanName, factory);
                                }
                                advisors.addAll(classAdvisors);
                            }
                            else {
                                // Per target or per this.
                                if (this.beanFactory.isSingleton(beanName)) {
                                    throw new IllegalArgumentException("Bean with name '" + beanName +
                                            "' is a singleton, but aspect instantiation model is not singleton");
                                }
                                MetadataAwareAspectInstanceFactory factory =
                                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                this.aspectFactoryCache.put(beanName, factory);
                                advisors.addAll(this.advisorFactory.getAdvisors(factory));
                            }
                        }
                    }
                    this.aspectBeanNames = aspectNames;
                    return advisors;
                }
            }
        }

        if (aspectNames.isEmpty()) {
            return Collections.emptyList();
        }
        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String aspectName : aspectNames) {
            List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
            if (cachedAdvisors != null) {
                advisors.addAll(cachedAdvisors);
            }
            else {
                MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                advisors.addAll(this.advisorFactory.getAdvisors(factory));
            }
        }
        return advisors;
    }

下面分步骤解析上面的代码

  • 获取所有的beanname
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
  • 遍历所有beanname,找到声明为Aspect 的类
for (String beanName : beanNames) {
                        if (!isEligibleBean(beanName)) {
                            continue;
                        }
                        // We must be careful not to instantiate beans eagerly as in this case they
                        // would be cached by the Spring container but would not have been weaved.
                        Class<?> beanType = this.beanFactory.getType(beanName);
                        if (beanType == null) {
                            continue;
                        }
                        if (this.advisorFactory.isAspect(beanType)) {
                .........................
    }
}
private boolean hasAspectAnnotation(Class<?> clazz) {
        return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
    }
  • 增强器的提取
    增强器的提取又包含以下步骤:
  1. 查找当前Aspect类及其父类或者父接口中非@Pointcut标记的方法。注意这里包含从Object类继承的方法。
  2. 查找切点信息,即被@Before、@Around、@After、@AfterReturning、@AfterThrowing、@Pointcut 标记的方法。并将其包装成AspectJAnnotation。
  3. 根据AspectJAnnotation 初始化AspectJExpressionPointcut
  4. 根据AspectJExpressionPointcut 初始化 InstantiationModelAwarePointcutAdvisorImpl。
  5. InstantiationModelAwarePointcutAdvisorImpl 初始化的时候,根据步骤2 中annotation的不同,生成不同的Advice,绑定在当前类中
    获取全部增强器流程图.png
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
List<Advisor> advisors = new LinkedList<Advisor>();
        for (Method method : getAdvisorMethods(aspectClass)) {
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
    @Override
    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {

        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }

        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }

关键点在于实例化InstantiationModelAwarePointcutAdvisorImpl 时的instantiateAdvice

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
        return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
                this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }
switch (aspectJAnnotation.getAnnotationType()) {
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }

从上面的代码中我们可以看到,初始化Advice的时候,会根据method上的注解类型,生成不同的Advice。包括AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice。这些是代理实现的核心
至此我们已经完成了增强器的提取,下面就是把增强器应用到当前bean了

3.3.1.2 寻找匹配增强器

寻找匹配的增强器的过程,就是查找当前类的方法信息是否在@pointcout("execution()")生效范围内的过程。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }

关键在于canApply方法

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }

        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
            // No need to iterate the methods if we're matching any method anyway...
            return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class<?> clazz : classes) {
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                if ((introductionAwareMethodMatcher != null &&
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                        methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }

        return false;
    }

3.3.2 根据增强方法创建代理

创建代理又是一个复杂的工程,总体来说包含以下几步

  1. 初始化ProxyFactory。这个步骤会当前代理类的相关属性及之前匹配到的Advisors复制进去。
  2. 选择代理类型。
  3. 获取代理。

3.3.2.1 初始化ProxyFactory

初始化ProxyFactory其实就是一个赋值的过程,便于后面创建代理时使用

protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        return proxyFactory.getProxy(getProxyClassLoader());
    }

3.3.2.2 选择代理类型

之前我们多次提到,spring 会根据类的结构选择使用jdk 代理或者cglib 代理,即当前类实现至少一个接口则使用jdk代理,否则使用cglib代理。现在我们从代码上看这个逻辑

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);
        }
    }
  • isOptimize 使用cglib优化策略
  • isProxyTargetClass proxy-target-class为true
  • hasNoUserSuppliedProxyInterfaces 不存在代理接口
  • isInterface 继承自接口
  • isProxyClass 是Proxy的子类
    可以看到,当使用cglib优化策略或者proxy-target-class=true或者不存在代理接口,且当前类不是interface,且不是Proxy的子类的时候,才会使用cglib代理 。否则都使用jdk代理

3.3.2.3 获取代理

上面我们选择了代理类型,那么就可以根据代理类型(JdkDynamicAopProxy/ObjenesisCglibAopProxy)来创建代理了。创建代理的过程与我们在章节2中演示的两种代理的创建方式类似,都是api的调用过程,核心就在于拦截器的使用,下面我们先看下代理的获取过程

  • JdkDynamicAopProxy
@Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
       //关键在这里,设置InvocationHandler
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

  • cglib
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            //关键在于设置不同方法对应不同的callback索引
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
           // 关键点,设置callback ,方法拦截的回掉
            return createProxyClassAndInstance(enhancer, callbacks);

我们可以看到,上面两种代理的创建是对jdk代理和cglib代理的标准使用。与我们在章节2中演示的最大区别就在于设置方法拦截或方法回调,这也是整个aop实现的核心。下面我们分别来介绍jdk动态代理的方法拦截,以及cglib动态代理的方法回调

3.4 代理的方法拦截和方法回调

上面我们说了这么多,其实已经完成了代理的创建,但是关于问题3(为什么around方法执行中才执行before方法?为什么around方法执行完才执行after方法?)即aop方法的执行顺序问题,我们一直没有谈到,篇幅所限,我们未放到3.3 章节中去讲,而是单独作为一个章节,值得注意的是:在aop的创建时已经完成了代理的方法拦截及方法回调的设置,下面我们分别来介绍问题3的答案

3.4.1 JdkDynamicAopProxy方法拦截

在3.3.2.2 获取代理章节中,我们贴出了jdk动态代理的源码,其中有一行很关键部分

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

我们都知道,Proxy.newProxyInstance方法的第三个参数需要传一个InvocationHandler对象,而这里传的this,我们猜测当前类即JdkDynamicAopProxy一定实现了InvocationHandler接口,并重写了invoke方法

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

果真如此,那么也就是说核心逻辑都在invoke里面了,贴出invoke的代码

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;

            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            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 {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

可以看到,代码很多,但其实核心就是两件事

  1. 获取拦截器链 List<Object> chain。
  2. 将拦截器链封装为ReflectiveMethodInvocation。
  3. 调用ReflectiveMethodInvocation.proceed 开始拦截器链的循环处理。
    同时我们可以看到,上面的代码中有对我们之前所说的expose-proxy属性的处理,处理的方式就是将当前proxy设置到threadlocal中,用完再将之前oldproxy设置回去
if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

//省略很多代码
finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }

3.4.1.1 proceed 方法的调用

终于到了解开庐山真面目的时候了,proceed 方法最终实现了@Before方法执行前执行,@After在方法执行后执行。在说具体执行逻辑之前,有几个前提条件要预先了解

  • ReflectiveMethodInvocation 持有List<?> interceptorsAndDynamicMethodMatchers 的引用,这个list里装的是在创建代理前,提取到的Advisors。
  • interceptorsAndDynamicMethodMatchers 是按照固定顺序排序,排序的操作是在提取advisors的时候做的。按照索引从0-3分别为 ExposeInvocationInterceptor,AspectJAfterAdvice,InterceptorAndDynamicMethodMatcher(持有AspectJAroundAdvice引用),MethodBeforeAdviceInterceptor(持有AspectJMethodBeforeAdvice引用)。
  • ReflectiveMethodInvocation 定义了一个实例变量currentInterceptorIndex=-1,interceptorsAndDynamicMethodMatchers 最后执行的MethodInterceptor的索引。
    了解以上几个前提条件。我们再来回顾下之前1.2 spring aop用法示范中的输出结果
around***********start****name:test
before***********
hello:moxieliunian
around***********end
after***************

可以得到如下结论

  1. 先执行around方法
  2. around执行中,且ProceedingJoinPoint.proceed()方法调用的时候执行before方法
  3. 继续执行完around方法
  4. 最后执行after方法

根据上面的结论,我们一步步来解释具体的执行流程,再次ReflectiveMethodInvocation.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);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.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 {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

上面代码即是整个aop执行的最核心的部分实现,下面来分步骤解释上面的执行过程

  1. 首次进入ReflectiveMethodInvocation.proceed(),先取到interceptorOrInterceptionAdvice=list[0]=ExposeInvocationInterceptor,并将当前ReflectiveMethodInvocation做为参数调用传递,调用ExposeInvocationInterceptor.invoke(this)方法。此时currentInterceptorIndex = 0 。
++this.currentInterceptorIndex此时为0
Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

ExposeInvocationInterceptor.invoke(this)方法又会再次调用ReflectiveMethodInvocation.proceed()

public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = invocation.get();
        invocation.set(mi);
        try {
            再次调用ReflectiveMethodInvocation.proceed()`
            return mi.proceed();
        }
        finally {
            invocation.set(oldInvocation);
        }
    }
  1. 第二次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[1]=AspectJAfterAdvice,此时会调用AspectJAfterAdvice.invoke(this)方法。此时currentInterceptorIndex=1。
++currentInterceptorIndex 此时等于1
Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

而AspectJAfterAdvice.invoke()的内部实现,又会调用ReflectiveMethodInvocation.proceed(),将其包再try/finally语句中,即所有的MethodInterector都执行完毕后,才会执行finally中的逻辑。而finally的逻辑,则是通过反射调用被@After标记的方法,这样一来也就实现了after在最后执行的逻辑,即结论4

@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            继续执行ReflectiveMethodInvocation.proceed(),第三次进入
            return mi.proceed();
        }
        finally {
            最终执行after
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
  1. 第三次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[2]=InterceptorAndDynamicMethodMatcher,此时会执行dm.interceptor.invoke(this)即AspectJAroundAdvice.invoke(this)方法。此时currentInterceptorIndex=2 。
++this.currentInterceptorIndex此时为2
Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

而AspectJAroundAdvice.invoke()最终会通过反射调用,我们编写的切面类中被@Around标记的方法。而我们在编写@Around标记的方法的时候,总是会调用ProceedingJoinPoint.proceed(),这个方法最终还是会调用到步骤前面几部的ReflectiveMethodInvocation.proceed 方法,接着串联起来。

public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
        JoinPointMatch jpm = getJoinPointMatch(pmi);
        通过反射调用被@Aroud标记的切面方法
        return invokeAdviceMethod(pjp, jpm, null, null);
    }
   public Object around(ProceedingJoinPoint joinPoint,String name){
        第一个输出语句执行
        System.out.println("around***********start****name:"+name);
        name = "moxieliunian";
        Object result=null;
        try {
            result=joinPoint.proceed(new Object[]{name});
            System.out.println("1111");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around***********end");
        return result;
    }

}

此时会执行第一个输出语句,输出

around***********start****name:test

接着执行joinPoint.proceed(new Object[]{name});

    public Object proceed(Object[] arguments) throws Throwable {
        Assert.notNull(arguments, "Argument array passed to proceed cannot be null");
        if (arguments.length != this.methodInvocation.getArguments().length) {
            throw new IllegalArgumentException("Expecting " +
                    this.methodInvocation.getArguments().length + " arguments to proceed, " +
                    "but was passed " + arguments.length + " arguments");
        }
        this.methodInvocation.setArguments(arguments);
        第四次进入
        return this.methodInvocation.invocableClone(arguments).proceed();
    }
  1. 第四次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[3]=MethodBeforeAdviceInterceptor,此时会执行MethodBeforeAdviceInterceptor.invoke(this)方法。此时currentInterceptorIndex=3 。
public Object invoke(MethodInvocation mi) throws Throwable {
        通过反射执行被before标记的方法
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        继续执行拦截器链,第五次进入
        return mi.proceed();
    }

而AspectJMethodBeforeAdvice.invoke最终会通过反射,执行切面中会@Before标记的方法

此时将执行第二个输出语句,输出before方法中的内容

before***********
  1. 第五次进入ReflectiveMethodInvocation.proceed()方法,此时 this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1。执行invokeJoinpoint()
currentInterceptorIndex等于3
this.interceptorsAndDynamicMethodMatchers.size()等于4
此时所有的方法拦截器都走完,则通过反射调用要被增强的方法,即TestServiceImpl.sayHello(String name)方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
    
      ReflectionUtils.makeAccessible(method);
      return method.invoke(target, args);

通过反射调用到TestServiceImpl.sayHello(String name)方法
此时将会执行sayHello方法,执行第三个输出语句,输出

hello:moxieliunian
  1. 到此为止,拦截器链循环结束,但是方法还未执行完。刚才我们是在调用MyAspectJ.around()里的joinPoint.proceed(new Object[]{name}) 语句进入的拦截器链,进行拦截器最后一次循环。那么接下来会继续顺序执行 未执行完代码
  System.out.println("around***********start****name:"+name);
        name = "moxieliunian";
        Object result=null;
        try {
            这部分代码已经执行完毕
            result=joinPoint.proceed(new Object[]{name});
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        未执行,继续往下执行
        System.out.println("around***********end");
        return result;

此时顺序执行完around剩余的代码,输出第四条语句

around***********end

当所有ReflectiveMethodInvocation.proceed() 递归调用完毕后,执行 最初 AspectJAfterAdvice.invoke方法中的finally 逻辑,即通过反射调用@After标记的方法

    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            递归调用
            return mi.proceed();
        }
        finally {
            通过反射最终执行被@After标记的方法
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }

此时输出第五条输出语句

after***************
ReflectiveMethodInvocation.proceed() 执行流程.png

可以看到整个执行过程比较复杂,而且具体的执行逻辑并不在ReflectiveMethodInvocation类中,而是委托给具体的MethodInterceptor 去执行

3.4.2 cglib 方法回调

上面我们详细的刨析了jdk动态代理的方法拦截,与之对应的是cglib的方法回调,这个也是cglib代理的关键所在,先上代码

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        // Parameters used for optimization choices...
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();

        // Choose an "aop" interceptor (used for AOP calls).
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }

        // Choose a "direct to target" dispatcher (used for
        // unadvised calls to static targets that cannot return this).
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };

        Callback[] callbacks;

        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimizations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

            // TODO: small memory optimization here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }

            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        return callbacks;
    }

关键点在于Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised)。即将advisors封装进DynamicAdvisedInterceptor中。我们都知道cglib拦截器必须实现自MethodInterceptor,可以推测DynamicAdvisedInterceptor必然实现了MethodInterceptor。查看类定义

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable

那么就必须实现intercept方法,查看源码

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Class<?> targetClass = null;
            Object target = null;
            try {
                if (this.advised.exposeProxy) {
                    // Make invocation available if necessary.
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // May be null. Get as late as possible to minimize the time we
                // "own" the target, in case it comes from a pool...
                target = getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // Check whether we only have one InvokerInterceptor: that is,
                // no real advice, but just reflective invocation of the target.
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    // We can skip creating a MethodInvocation: just invoke the target directly.
                    // Note that the final invoker must be an InvokerInterceptor, so we know
                    // it does nothing but a reflective operation on the target, and no hot
                    // swapping or fancy proxying.
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null) {
                    releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
  • 是不是跟我们上面分析的JdkDynamicAopProxy类似,都是获取拦截器链,封装拦截器链,构造并串联调用。
  • 区别就在于JdkDynamicAopProxy是直接构造ReflectiveMethodInvocation,而CglibAopProxy则是构造CglibMethodInvocation,CglibMethodInvocation继承自ReflectiveMethodInvocation,但未覆盖其proceed方法。
  • 所以最终会走到跟JdkDynamicAopProxy一样的逻辑,即递归调用ReflectiveMethodInvocation.proceed()。这里我们就不在重复去分析了。

4. 总结

这篇文章中,我们由两个aop失效及一个aop使用正常的例子,简单分析了spring aop的实现原理。其实用一句话概括就是:提取Advisors,以advisors创建代理。但是为了简单说清楚这个问题,我们先是演示了aop的使用方法及失效案例,再演示了java中的三种代理类型,接着才着重分析了aop的实现原理。可以看到,有的时候要说清楚一个问题,往往要以N个问题做铺垫。还是相对来说比较繁杂的,但是总结的过程往往也是升华的过程。

希望看到这篇文章的朋友都有些许收获,也希望自己的目标早日实现。因能力有限,文章难免会有错漏的地方,欢迎指正和探讨。我们下篇文章spring源码系列-事物的失效知多少见。。。。

参考文章
Spring 源码深度解析-郝佳

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343