Spring源码——AOP

10 篇文章 0 订阅
7 篇文章 1 订阅

准备

public class MathCalculator {
    public int div(int i, int j) {
        System.out.println("目标方法执行,结果:" + (i / j));
        
        return i / j;
    }
}
@Aspect
public class LogAspects {

    //抽取公共的切入点表达式
    @Pointcut("execution(public int cn.example.aop.MathCalculator.*(..))")
    public void pointCut(){};

    //@Before在目标方法之前切入
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"执行。@Before:参数列表是:{"+ Arrays.asList(args)+"}");
    }

    //@After在目标方法之后切入
    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"执行。@After:");
    }

    //@AfterReturning在目标方法正常返回的时候切入
    // JoinPoint一定要出现在参数表的第一位
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"执行。@AfterReturning:运行结果:{"+result+"}");
    }

    //@AfterThrowing在目标方法出现异常的时候切入
    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"执行。@AfterThrowing异常信息:{"+exception+"}");
    }
}
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
    @Bean
    public MathCalculator calculator() {
        return new MathCalculator();
    }

    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }
}
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
        MathCalculator calculator = ioc.getBean("calculator", MathCalculator.class);
        calculator.div(1, 1);
    }
}

分析

@EnableAspectJAutoProxy

@EnableAspectJAutoProxy注解用于开启AOP的支持,源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	//...省略
}

主要是@Import(AspectJAutoProxyRegistrar.class),AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar 接口,给系统注册组件AspectJAnnotationAutoProxyCreator,这个组件的最终有一个父接口是BeanPostProcessor,说明这个组件是个后置处理器,看源码可以发现它是InstantiationAwareBeanPostProcessor类型的后置处理器,后置处理器的功能就能在其他Bean创建之前进行拦截。AspectJAutoProxyRegistrar 源码:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		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);
			}
		}
	}
}
创建MathCalculator的代理对象-前期流程

第一步从容器的refresh()开始
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);会进入到容器的refresh()方法开始:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
	}

refresh()方法的具体步骤在《Spring源码——容器创建》写过

@Override
	public void refresh() throws BeansException, IllegalStateException {
		//...忽略很多源码片段...
		// 一、
		//Instantiate all remaining (non-lazy-init) singletons.
		// 开始实例化所有剩下的单实例Bean(不包含懒加载的Bean)
		// MathCalculator的Bean对象创建就是从这里开始的(虽然它是个需要增强的Bean,但是最开始的流程和普通的Bean没有区别,到最后后置处理器工作的时候才会看到它的不同)
		finishBeanFactoryInitialization(beanFactory);
	}

进入finishBeanFactoryInitialization()方法之后的一些函数调用链也在《Spring源码——容器创建》写过,所以这里直接跳到AbstractAutowireCapableBeanFactory的initializeBean()方法中:

	/**
	 * Initialize the given bean instance, applying factory callbacks
	 * as well as init methods and bean post processors.
	 * 初始化Bean的实例,应用工厂的回调方法、自定义的初始化方法
	 * 和BeanPostProcessor后置处理器
	 */
	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {				
				/**
				* 二、
				* 调用:
				* 	BeanNameAware
				* 	BeanClassLoaderAware
				* 	BeanFactory
				* 的方法
				*/
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			/**
			* 三、
			* 执行后置处理器的before方法
			*/
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			/**
			* 四、
			* 执行自定义初始化方法
			*/
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			/**
			* 五、
			* 执行后置处理器的after方法
			*/
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		/**
		* 六、
		* 返回包装过的Bean对象(对于我们的MathCalculator,返回的就是代理对象)
		*/
		return wrappedBean;
	}
创建MathCalculator的代理对象-中期流程(执行后置处理器)

applyBeanPostProcessorsAfterInitialization()方法中获取到所有的后置处理器,执行它们的after()方法,applyBeanPostProcessorsAfterInitialization()源码:

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		/**
		* 5.1 
		* 遍历所有的后置处理器,依次执行after方法
		*/
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

调用getBeanPostProcessors()获取的所有后置处理器,第3号位置就是AspectJAnnotationAutoProxyCreator的后置处理器:
在这里插入图片描述
在这里插入图片描述
当遍历到AspectJAnnotationAutoProxyCreator的后置处理器时,进入postProcessAfterInitialization()方法

	/**
	 * 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(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				/**
				* 5.2
				* 创建代理对象
				*/
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
创建MathCalculator的代理对象-后期流程(开始创建)

wrapIfNecessary()方法:

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		/**
		* 5.2.1
		*  如果当前Bean已经在advisedBeans中(保存了所有增强过的Bean),就直接返回
		*  当前MathCalculator还没有被增强,继续下面的流程
		*/
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
    	/**
	    * 5.2.2
	    * isInfrastructureClass:
	    * 	判断当前Bean是不是切面类(实现了Advisor等接口或者有@Aspect注解)
	    * shouldSkip:
	    * 	获取所有的候选增强器(切面里的通知方法包装过的东西,
	    *   对应我们的例子就是logStart()、logEnd()、logReturn()、logException()保证后的东西)
	    *   然后判断增强器是不是AspectJPointcutAdvisor类型的(我们的增强器是
	    * 	InstantiationModelAwarePointcutAdvisor类型的)
		* 
		* 所以这判断使false,继续下面的流程
	    */
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		/**
		* 
		* 5.2.3 
		* 现在,真正的开始创建代理对象
		* 5.2.3.1.
		* 	 getAdvicesAndAdvisorsForBean()方法会去遍历所有的通知方法,
		* 	 使用通知方法的类型和切入点表示式等计算,
		* 	 得到当前Bean可用的增强器(包装过的通知方法),然后进行排序(见下面当前Bean可用的通知方法截图)
		* 	 返回当前Benn可用的增强器
		*/
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			/**
			* 5.2.3.2. 
			* 	将当前Bean保存到advisedBeans中,value设置为true,表示织入了通知方法
			*/
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			/**
			* 5.2.3.3. 
			* 	创建代理(见下面的创建代理createProxy()方法)
			*/
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			/**
			* 5.2.3.4. 
			* 	返回代理对象
			*/
			return proxy;
		}
		/*
		* 如果当前Bean没有增强器:
		* 把当前Bean放入advisedBeans,value设置为false,表示当前Bean没有通知方法
		*/
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

当前Bean可用的通知方法:
在这里插入图片描述
创建代理createProxy()方法

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

		//...忽略部分源码

		/**
		* 5.2.3.3--1 先拿到增强器(就是上面截图的那5个,第一个是固有的)
		*/
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		// 设置代理工厂
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		/**
		* 5.2.3.3--2 用代理工厂创建代理对象
		*/
		return proxyFactory.getProxy(getProxyClassLoader());
	}

getProxy()方法:

public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

createAopProxy()方法:

protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

createAopProxy()方法:

@Override
	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.");
			}
			/**
			* 5.2.3.3--3 如果目标类实现了接口(任意接口),就使用JDK动态代理,否则使用Cglib代理
			* 	  我们的MathCalculator走的是Cglib代理
			*/
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
用代理对象执行目标方法

现在,MathCalculator的代理对象已经放到容器中了,以后从容器中取的就是这个代理对象,可以看到四个通知方法和一个默认方法:
在这里插入图片描述
断点调试执行到div()方法,这个方法的执行会被CgligAopProxy静态内部类的intercept()方法拦截,进入:

class CglibAopProxy implements AopProxy, Serializable {
	//....省略部分源码

	// 一个静态内部类
	private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
		//....省略部分源码
		@Override
		@Nullable
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
				/**
				* 核心在这里
				* 1. 通过advised(ProxyFactory)对象获取将要执行的目标方法(div())的拦截器链
				* 	 连接器链就是封装过的通知方法(MethodInterceptor类型)
				*    看下面的拦截器链chain截图
				*/
				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...
					/**
					* 2. 有拦截器链,调用CglibMethodInvocation.proceed()方法执行
					* 	 proceed()就是拦截器链的执行过程
					*    看下面的 CglibMethodInvocation.proceed()执行拦截器链
					*/
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}
//....省略部分源码
拦截器链chain

包含5种类型的拦截器
在这里插入图片描述

CglibMethodInvocation.proceed()执行拦截器链
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    //....省略部分源码
	private int currentInterceptorIndex = -1;

	@Override
	@Nullable
	public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		/**
		* 2.1 如果拦截器索引(currentInterceptorIndex)大小等于拦截器数组大小减1,
		*   ,直接进入invokeJoinpoint()执行目标方法
		*/
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		/**
		* 2.2 遍历拦截器数组,获取拦截器,拦截器索引加1,调用对应的invoke()方法
		*/
		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);
		}
	}

	//....省略部分源码

拦截器链的执行过程有点像递归:

  1. 先获取第一个拦截器ExposeInvocationInterceptor,currentInterceptorIndex =0,执行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);invoke()方法,这个拦截器的invoke()方法中又会调回到ReflectiveMethodInvocation.proceed()方法
  2. 获取第二个拦截器AspectJAfterThrowingAdvice,currentInterceptorIndex =1,执行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);invoke()方法,这个拦截器的invoke()方法中又会调回到ReflectiveMethodInvocation.proceed()方法
  3. 获取第三个拦截器AfterRunningAdviceInterceptor,currentInterceptorIndex =2,执行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);invoke()方法,这个拦截器的invoke()方法中又会调回到ReflectiveMethodInvocation.proceed()方法
  4. 获取第四个拦截器AspectJAfterAdvice,currentInterceptorIndex =3,执行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);invoke()方法,,这个拦截器的invoke()方法中又会调回到ReflectiveMethodInvocation.proceed()方法
  5. 获取第五个拦截器MethodBeforeAdviceInterceptor,currentInterceptorIndex =4,执行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);invoke()方法,这个拦截器的invoke()方法中会先执行前置通知,再调回到ReflectiveMethodInvocation.proceed()方法
  6. 此时currentInterceptorIndex =4,和拦截器数组减1大小一样,调用invokeJoinpoint()方法执行目标方法
  7. 调用AspectJAfterAdvice的invoke()方法,执行后置通知
  8. 调用AfterRunningAdviceInterceptor的invoke方法,执行正常返回通知
  9. 如果目标方法执行过程中出现异常,则流程是:前置通知->目标方法->后置通知->异常通知
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOPSpring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值