Spring AOP 源码探究

概述

我们都知道 Spring 的事务管理有两种方式,编程性事务和声明式事务,而声明式事务是基于 aop 来实现的,上篇文章分析了 Spring Bean 的一个初始化过程,本文来聊聊 Spring aop 的源码执行过程。

项目结构搭建

为简单起见,这里就不搞那么复杂的分层了,本项目的目的是利用 spring aop 来计算一个方法的执行时间

@EnableAspectJAutoProxy
@ComponentScan("com.lhg.demo.*")
public class App{
    public static void main( String[] args ) throws Exception {
        ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
        //本意是输出 user 对象
        User user = (User) ac.getBean("user");
        user.compute();
    }
}
@Component
public class User {
    //计算 0-800000000 耗时操作
    public void compute() throws Exception{
        ForkJoinPool pool = new ForkJoinPool();
        MyTask task = new MyTask(0, 800000000);
        Future<Long> future = pool.submit(task);
        System.out.println("多线程加法: " + future.get());
        pool.shutdown();
    }

    public User() {
        System.out.println("User constructor....");
    }
}
@Aspect
@Component
public class MyAspect {
    //指定切入点表达式
    @Pointcut("execution(* com.lhg.demo.config.*.*())")
    public void pointCut(){}
    /**
     * spring 框架为我们提供了一个接口:ProceedingJoinPoint,该接口有一个方法proceed(),
     * 此方法就相当于明确调用切入点方法,该接口可以作为环绕通知的方法参数,在程序执行时,
     * spring 框架会提供该接口的实现类供我们使用
     **/
    @Around("pointCut()")
    public Object aroundPringLog(ProceedingJoinPoint pjp){
        try {
            Object res ;
            Object[] args = pjp.getArgs();//这个参数就是实际方法执行所需的参数
            long start = System.currentTimeMillis();
            res = pjp.proceed(args);//明确调用业务层方法(切入点方法)
            long end = System.currentTimeMillis();
            System.out.println("总时间:"+(end-start));
            return res;
        }catch (Throwable t){//这个异常必须写Throwable,Exception拦不住的
            throw new RuntimeException(t);
        } finally {
        }
    }
}
/*
* 来复习下 分支合并线程池 
*/ 
public class MyTask extends RecursiveTask<Long> {
    final static int MAX_SIZE = 500;//定义切割的步长值
    int begin, end;

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    protected Long compute() {
        if ((end - begin) <= MAX_SIZE) {//如果比步长值小直接累加就好
            long sum = 0L;
            for (int i = begin; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {//否则开启任务分治递归相加再汇总
            int middle = begin + (end - begin) / 2;
            MyTask task1 = new MyTask(begin, middle);
            MyTask task2 = new MyTask(middle + 1, end);
            task1.fork();// 就是用于开启新的任务的。 就是分支工作的。 就是开启一个新的线程任务。
            task2.fork();
            // join - 合并。将任务的结果获取。 这是一个阻塞方法。一定会得到结果数据。
            return task1.join() + task2.join();
        }
    }
}

这个小案例的目的是测试 User 类中的 test 方法耗时,为了不修改原有业务,我们使用 AOP ,从这里可以看出 AOP 的一大特点,简单的说就是把程序重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上对原有方法进行增强

运行项目,查看结果

D:\ProgramFiles\Java\jdk1.8.0_201\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.2\lib\idea_rt.jar=52765:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath 3.6.0\localRepository\org\aspectj\aspectjweaver\1.9.5\aspectjweaver-1.9.5.jar com.lhg.demo.spring.App
User constructor....
多线程加法: 320000000400000000
总时间:655

Process finished with exit code 0

经过 debug 发现,Spring bean 初始化过程中就已经完成了代理,

Spring AOP 源码探究_第1张图片
对程序 debug 你会发现 user 是个代理类,那问题来了,究竟是什么时候生成的呢,是在 getBean 的时候还是初始化的时候?

MyAspect 类的方法是如何被调用的?

源码探析

在上篇文章分析的时候说过,在Spring bean 初始化过程中有一个 refresh() 方法非常重要,而且其中invokeBeanFactoryPostProcessors finishBeanFactoryInitialization两个方法非常重要

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    this.register(componentClasses);
    this.refresh();
}
public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        ...
        try {
            this.postProcessBeanFactory(beanFactory);
            //设置执行自定义的 ProcessBeanFactory 和 Spring 内部定义的的
            this.invokeBeanFactoryPostProcessors(beanFactory);
            ...
            //实例化对象
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } ...
    }
}

根据之前文章的分析,bean的实例化是在 finishBeanFactoryInitialization() 方法进行操作的,大致过程如下

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ....

    beanFactory.setTempClassLoader((ClassLoader)null);
    beanFactory.freezeConfiguration();
    beanFactory.preInstantiateSingletons();
}

进入 preInstantiateSingletons() 方法,层层查看,最终找到 doGetBean() 方法,因为 Spring的源码太过庞大,所以查看源码的时候就要有的放矢,比如我们这次要 查看 bean 的实例初始化过程,那么在看源码时那些没有返回值的可以略过,有返回值但返回值类型是基本类型或者 String 可以不看,然后按照 Spring 的编码规范,方法见名知意,再通过 debug,条件断点,就能大致判断是哪个方法了

 protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
       // Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("...");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
        if (mbd.isSingleton()) {
             sharedInstance = this.getSingleton(beanName, () -> {
                 try {
                     return this.createBean(beanName, mbd, args);
                 } catch (BeansException var5) {
                     this.destroySingleton(beanName);
                     throw var5;
                 }
             });
             bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         } else if (mbd.isPrototype()) {
             。。。
         }  
     } 。。。
}

还记得吧,对象的创建是在 createBean 方法中,经过获得 class、推断构造方法、并反射,实例化对象,然后把创建好的 bean 返回出来

/**
	 * Central method of this class: creates a bean instance,
	 * populates the bean instance, applies post-proce ssors, etc.
	 * @see #doCreateBean
	 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	RootBeanDefinition mbdToUse = mbd;
	//得到 class
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}
	...
	try {
		//在 doCreateBean 方法中创建对象
		//推断构造方法,并反射,实例化对象
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		//在这个方法里面完成了对象的创建
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	// Allow post-processors to modify the merged bean definition.
	//从 java-doc 可以看出这里说的是可以通过 post-processors 去 modify 合并的 beandefinition.
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				...
			}
			mbd.postProcessed = true;
		}
	}
	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//从 java-doc 可以看出这里是 缓存对象来解决循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		...
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		//完成属性填充
		//比如 A类里面有个 B,那么这个方法就是完成 B 的注入
		populateBean(beanName, mbd, instanceWrapper);
		//主要执行各种生命周期回调方法以及 AOP 等
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	...
}

595 行没有执行完前,user 对象已经被放入 singletonObjects 单例池了,而且这个时候没有完成代理
Spring AOP 源码探究_第2张图片
当继续往下执行时,可以看到已经完成了代理
Spring AOP 源码探究_第3张图片
所以去看看方法底层实现

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    ...
        Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    }
    ...
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

    return wrappedBean;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
    Object result = existingBean;
    Object current;
    for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {
        BeanPostProcessor processor = (BeanPostProcessor)var4.next();
        //直接进去看源码
        current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
    }
    return result;
}
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                //发现经过这一步创建了代理对象
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
       ...
        Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        this.customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (this.advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
		//查看 getProxy() 方法的源码
        return proxyFactory.getProxy(this.getProxyClassLoader());
    }
public Object getProxy(@Nullable ClassLoader classLoader) {
    //到这里已经很明显了,createAopProxy() 创建了代理对象,而 getProxy()可以看到动态代理的底层实现(字节码实现)
    return this.createAopProxy().getProxy(classLoader);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
        //使用 jdk 动态代理,基于接口的动态代理
        return new JdkDynamicAopProxy(config);
    } else {
        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.");
        } else {
            //使用 cglib 动态代理,基于子类的动态代理
            return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
        }
    }
}

对 if 条件进行分析,isOptimize 和 isProxyTargetClass 是属性,isProxyTargetClass 可以在@EnableAspectJAutoProxy 注解进行赋值,而 hasNoUserSuppliedProxyInterfaces 方法便是判断类是否有继承自接口,由于 User 并没有实现某接口,所以会 走 cglib,通过 debug 也可以证实
Spring AOP 源码探究_第4张图片
好,为了更好验证动态代理,现在让 User 类 实现一个接口,debug 看看是否会走 JKD动态代理

@Component
public class User implements ComputerMapper {

    //计算 0-800000000 耗时操作
    @Override
    public void compute() throws ExecutionException, InterruptedException {
        ForkJoinPool pool = new ForkJoinPool();
        MyTask task = new MyTask(0, 800000000);
        Future<Long> future = pool.submit(task);
        System.out.println("多线程加法: " + future.get());
        pool.shutdown();
    }

    public User() {
        System.out.println("User constructor....");
    }
}

Spring AOP 源码探究_第5张图片

你可能感兴趣的:(源码分析,spring,aop)