Spring注解开发(四)AOP原理与源码分析

先来看一个简单的例子:

先建一个Person类作为业务类:

public class Person {
    public int doDivision(int a, int b) {
        return (a / b);
    }
}

新建切面类LogWriter,此处只加了两个通知:

@Aspect //指定此类为一个切面类
public class LogWriter {
    //切点及切入点表达式
    @Pointcut("execution(public int com.practice.bean.Person.*(..))")
    public void pointCut() {
    }

    @Before("pointCut()") //前置通知
    public void beforeDivision(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println("LogWriter....+before" + joinPoint.getSignature().getName() + Arrays.asList(args));
    }

    //返回通知, 在方法返回结果之后执行
    @AfterReturning(value="pointCut()",returning="result")
    public void divisionReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回,结果为:"+result);
    }
}

配置类如下,为注入业务类和启用自动代理:

@Configuration
@EnableAspectJAutoProxy//启用切面自动代理
public class MainConfig {
    @Bean
    public Person person() {
        return new Person();
    }
    @Bean
    public LogWriter logWriter() {
        return new LogWriter();
    }
}

执行测试类:

    @Test
    public void test01() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person person = applicationContext.getBean(Person.class);
        person.doDivision(1, 2);
    }

结果如下:

LogWriter....+beforedoDivision[1, 2]
doDivision正常返回,结果为:0

Tips:AspectJ支持五种切面类型的通知注解:

  • @Before: 前置通知, 在方法执行之前执行
  • @After: 后置通知, 在方法执行之后执行 。
  • @AfterRunning: 返回通知, 在方法返回结果之后执行
  • @AfterThrowing: 异常通知, 在方法抛出异常之后,(方法参数中加上Exception可以接收到返回的异常)
  • @Around: 环绕通知, 围绕着方法执行

@Around方法做一个测试,还是以上代码,切面类中的方法为:

 @Around("pointCut()")
    public Object aroundMethod(ProceedingJoinPoint jointPoint) throws Throwable{
         //前置方法
        long startTime=System.currentTimeMillis();
        System.out.println("-->开始时间为:"+startTime);
        //调用执行目标方法(result为目标方法执行结果)
        Object result=jointPoint.proceed();
        System.out.println("执行结果为:"+result);
        long endTime=System.currentTimeMillis();
        //后置方法。记录结束时间和执行时长
        System.out.println("-->结束时间为:"+endTime+"。执行时长为:"+(endTime-startTime));
        //获取业务方法签名
        System.out.println(jointPoint.getSignature().getName());
        //获取执行参数
        System.out.println(Arrays.asList(jointPoint.getArgs()));
        return result;
    }

测试结果为:

-->开始时间为:1571236822985
执行结果为:0
-->结束时间为:1571236822992。执行时长为:7
doDivision
[1, 2]

 

一.在配置类中,引入了@EnableAspectJAutoProxy注解,这个注解是做什么的?

1.先看一下这个注解的源代码:

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

可以看出该注解为容器导入了AspectJAutoProxyRegistrar组件,

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar

该组件实现了ImportBeanDefinitionRegistrar接口,这个接口可以为容器导入组件(在第一篇文章中已有介绍)

可以看到为容器导入了org.springframework.aop.config.internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator

导入的类如下(源码注释):

Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
------->
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

beanName为:

public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

二.注入的AnnotationAwareAspectJAutoProxyCreator组件做了什么?

AnnotationAwareAspectJAutoProxyCreator类图如下:

 

21.该类实现了Aware接口下的BeanFactoryAware接口,说明为AnnotationAwareAspectJAutoProxyCreator类注入了beanFactory。

具体实现在AbstractAdvisorAutoProxyCreator类中

@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}

	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}

initBeanFactory又被子类AnnotationAwareAspectJAutoProxyCreator重写:

@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		if (this.aspectJAdvisorFactory == null) {
			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
		}
		this.aspectJAdvisorsBuilder =
				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
	}

2.2实现了BeanPostProcess接口,说明在初始化Bean阶段会调用后置处理器方法。

 

三.AnnotationAwareAspectJAutoProxyCreater组件的创建过程。


在registerBeanPostProcessors(beanFactory)方法中注册bean的后置处理器来拦截bean的创建:

进入registerBeanPostProcessors方法,

  • 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor的ID;
  • 注册BeanPostProcessorChecker;
  • 优先注册实现了PriorityOrdered接口的BeanPostProcessor;
  • 再给容器中注册实现了Ordered接口的BeanPostProcessor;
  • 注册没实现优先级接口的BeanPostProcessor;

在beanFactory.getBean(ppName, BeanPostProcessor.class)创建了BeanPostProcess组件,最后注册组件到容器中:

//找到所有的BeanPostProcessessors,并注册到容器中
registerBeanPostProcessors(beanFactory, internalPostProcessors);
---》
 private static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

		for (BeanPostProcessor postProcessor : postProcessors) {
			beanFactory.addBeanPostProcessor(postProcessor);
		}
	}

 

四.AnnotationAwareAspectJAutoProxyCreator(InstantiationAwareBeanPostProcessor) 的作用:

  • 以下为获取业务类Person为例:

进入refresh()方法中的finishBeanFactoryInitialization(beanFactory),完成BeanFactory初始化工作,创建剩下的单实例bean

getBean->doGetBean()->getSingleton()-->先从缓存中获取,如果没有获取到则执行:

return createBean(beanName, mbd, args);进入创建Bean方法。

1.进入此方法,我们在容器中获取要创建的组件,在组件创建之前,会执行下面的方法:

给后置处理器一个机会去创建代理实例去替代Bean的实例对象:

try {
	// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
		}
	}

进入resolveBeforeInstantiation方法,有执行下面两个方法:

---->applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

---> applyBeanPostProcessorsAfterInitialization(bean, beanName);

第一个方法的主要逻辑执行的为下面这个接口中定义的方法:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor

 判断是否为InstantiationAwareBeanPostProcessor,如果是则执行ibp.postProcessBeforeInstantiation(beanClass, beanName);

此方法为AbstractAutoProxyCreator实现:

  • 判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
  •  判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)或是否需要跳过
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// TODO: Consider optimization by caching the list of the aspect names
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
		return true;
		}
	}
	return super.shouldSkip(beanClass, beanName);
}
  • 获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】 每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
  • 父类super方法永远返回false

Tips:在此处不会执行以下方法创建代理对象逻辑:

/*如果我们有自定义的targetsource将在此处创建代理。禁止不必要的目标bean默认实例化:targetsource将以自定义方式处理目标实例。*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);	
if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

返回为空;第二个applyBeanPostProcessorsAfterInitialization方法在此处不会执行;

2.接下来会进入创建对象的逻辑:

doCreateBean-->initializeBean-->

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

第二个方法主要逻辑在这-->processor.postProcessAfterInitialization(result, beanName)

此处在AbstractAutoProxyCreator类中实现:

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

-->return wrapIfNecessary(bean, beanName, cacheKey):

如果有通知的话则创建代理

// 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;
	}

1、获取当前bean的所有通知方法  Object[]  specificInterceptors
             1、找到候选的所有的通知方法(找哪些通知方法是需要切入当前bean方法的)
             2、获取到能在bean使用的通知方法。
             3、给获取到的通知方法排序
2、将当前bean保存到advisedBeans中;
3、创建当前bean的代理对象;

return proxyFactory.getProxy(getProxyClassLoader());

          1、获取所有通知方法
          2、保存到proxyFactory
          3、创建代理对象:Spring自动决定

@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.");
		}
	if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
		return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

              Tips:两种代理方式:

                 1.JdkDynamicAopProxy(config);jdk动态代理;
                 2.ObjenesisCglibAopProxy(config);cglib的动态代理;
4、给容器中返回当前组件使用cglib增强了的代理对象;
5、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

 

五、代理对象方法的执行

在业务方法打上断点,执行进入:

容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);

1.进入CglibAopProxy类的下面这个方法:拦截目标方法的执行

CglibAopProxy.intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) 

2.根据ProxyFactory对象获取将要执行的目标方法拦截器链:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

进入上面的方法,主要逻辑如下--->拦截器链的获取:

cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);

用List<Object> interceptorList = new ArrayList<>(advisors.length);来保存所有拦截器

可以看到其中有两个:

一个默认的ExposeInvocationInterceptor 和 1个LogWriter的aroundMethod通知方法。

遍历所有的通知方法,将其转为Interceptor---->registry.getInterceptors(advisor);

如果是MethodInterceptor,直接加入到集合中,如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;

拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)

registry.getInterceptors(advisor);
-----》
@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

3.如果没有拦截器链,直接执行目标方法;
4. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建的一个 CglibMethodInvocation 对象,并调用 proceed()方法

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

5.拦截器链的触发过程:

     如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

      currentInterceptorIndex 默认为-1,每执行一个通知方法则++currentInterceptorIndex ;

private int currentInterceptorIndex = -1;
++this.currentInterceptorIndex

链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;

当遍历到最后一个拦截器时,执行

return invokeJoinpoint();跳出递归调用

前置通知在递归向上层返回时调用了,先执行了前置通知方法:

return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
------>
@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

执行完前置通知后进入目标方法执行然后依次执行各通知,利用catch,finally等控制异常通知和返回通知的顺序。

拦截器链的机制,保证通知方法与目标方法的执行顺序;

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值