spring学习之aop

spring学习之Aop

一:AOP

@EanbleAspectJAutoProxy

被代理类

@Service("calculate")
public class CalculateImpl implements  Calculate {
    @Override
    public int add(int numA, int numB) {
        System.out.println("执行目标方法:add");
        return numA + numB;
    }

    @Override
    public int reduce(int numA, int numB) {
        System.out.println("执行目标方法:reduce");
        return numA - numB;
    }
}

切面

@Component
@Aspect
public class LogAspect {

    @Pointcut("execution(* com.zt.springboot.aop.CalculateImpl.*(..))")
    public void pointCut(){};

    @Before(value = "pointCut()")
    public void methodBefore(JoinPoint joinPoint){
        ProceedingJoinPoint point = (ProceedingJoinPoint) joinPoint;
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行方法【" + methodName + "】之前执行了<前置通知>,入参" + Arrays.asList(joinPoint.getArgs()));
    }

    @After(value = "pointCut()")
    public void methodAfter(JoinPoint joinPoint){
        ProceedingJoinPoint point = (ProceedingJoinPoint) joinPoint;
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行方法【" + methodName + "】之后执行了<后置通知>,入参" + Arrays.asList(joinPoint.getArgs()));
    }
    @AfterReturning(value = "pointCut()",returning = "result")
    public void methodReturning(JoinPoint joinPoint, Object result){
        System.out.println(result);
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行方法【" + methodName + "】之后执行了<返回通知>,入参" + Arrays.asList(joinPoint.getArgs()));
    }
    @AfterThrowing(value = "pointCut()")
    public void methodAfterThrowing(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行方法【" + methodName + "】之后执行了<异常通知>,入参" + Arrays.asList(joinPoint.getArgs()));
    }
}

启动函数

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

测试代码

@Test
	void contextLoads() {

		Calculate calculate = (Calculate) act.getBean("calculate");
		int reVal = calculate.add(1,3);
		System.out.println(reVal);

	}

在这里插入图片描述

引发的问题:

  1. 为什么我们获取的组件calculate是一个动态代理对象?

    ​ 因为我们定义了切面,并设置了切点,切点是针对所有得calculate中的方法。

  2. 什么生成的代理对象?

    ​ jdk动态代理

  3. 这个代理对象存放在哪里? 单例一级缓存中 singletonObjects中

整个Aop代理实现的流程

1、@EableAspectJAutoProxy注解的作用

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

可以看到,它通过@Import注解向容器中注册了名为AspectJAutoProxyRegistrar.class的类。

2、AspectJAutoProxyRegistrar.class

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@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);
			}
		}
	}

}

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);方法源码如下

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
	//可以看到它接着运行了下面的方法,我们继续跟进
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);源码如下:

这个方法的功能就是将AnnotationAwareAspectJAutoProxyCreator.class类注册到容器中,

		private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

说明这个类肯定会在以后有作用!!! 我们查看一下这个类的结构。

在这里插入图片描述

注意右上角,这个类实现了BeanPostProcessor接口和InstantiationAwareBeanPostProcessor接口,说明这个类会在每个bean的生命周期中执行其回调函数,也就是这里可能会解析生成我们的切面数据或者生成代理对象。

  • 综上所属,我们可以分析出,在容器启动调用refresh(),之后在调用finishBeanFactoryInitialization(beanFactory)来实例化所有的单例bean----------->preInstantiateSingletons() 具体到beanFactory来实例化所有的单例bean,----->getBean()-------->doGetBean()------>getSingletion(beanName, ObjectFactory)这是第二次从单例注册器中获取bean的方法,如果获取不到bean它会通过ObjectFactory来创建一个bean-------->createBean()虽然说最后创建对象是通过doCreateBean()来实现的,但是它里面有一个方法需要我们注意,resolveBeforeInstantiation()它实现了对我们切面类的解析,将通知缓存到内存中。
  • 我们接下来具体分析一下resolveBeforeInstantiation()这个方法。

resolveBeforeInstantiation()源码如下:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
    //判断这个bean是否已经执行了beforeInstantiation后置流程
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
                    //执行beforeInstantiation()
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
                        //执行afterInitialization()
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

整个方法的意义就是给那些实现了InstantiationAwareBeanPostProcessors()接口的类一个机会,去自己创建一个bean,而不是走spring指定的创建bean流程(doCreateBean())。 大家如果对接口敏感的话,一定会发现InstantiationAwareBeanPostProcessors()接口我们在上文提到过,没错!!!就是@EnbleAspectJAutoProxy 注解注入的AnnotationAwareAspectJAutoProxyCreator.class类,它就实现了这个接口! 那么它一定会实现这个接口的beforeInstantiation()afterInitiantion(),我们去源码里面找一下!

AnnotationAwareAspectJAutoProxyCreator.class 源码

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

	@Nullable
	private List<Pattern> includePatterns;

	@Nullable
	private AspectJAdvisorFactory aspectJAdvisorFactory;

	@Nullable
	private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

	public void setIncludePatterns(List<String> patterns) {
	}

	public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
	}
	@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	}
	@Override
	protected List<Advisor> findCandidateAdvisors() {
	}
	@Override
	protected boolean isInfrastructureClass(Class<?> beanClass) {
	}
	protected boolean isEligibleAspectBean(String beanName) {
	}
	private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
	}

}

​ 可以看到这个类中并没有我们提到的方法,难道我们判断的有误? 别急,我们去它的父类找找。

这里就不一一贴源码了,有兴趣的同学可以自己去找源码看看,它的父类也没有这个方法,我们最后在它父类的父类AbstractAutoProxyCreator中找到了。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
       //设置缓存的名称
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		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;
		}

		return null;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}

postProcessBeforeInstantiation()有两个逻辑,如果我们能获取到当前bean,就创建它的代理对象。如果获取不到就返回null,但是它通过shouldSkip(beanClass, beanName)完成了我们项目中通知的发现和缓存,它是怎么完成的我们看一下源码:

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

findCandidateAdvisors()源码如下:

protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
    	//注意这一行是获取我们标注了事务注解的通知,而不是我们AspectJ的通知
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
            //这里才是获取我们@AspectJ的通知
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

aspectJAdvisorsBuilder.buildAspectJAdvisors() 源码如下:

方法功能: 在beanFactory中寻找被AspectJ标注的类,并返回一组通知。也就是找我们的切面,并返回切面中的通知列表。

public List<Advisor> buildAspectJAdvisors() {
    //切面名称
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
                    //去beanFactory中找到所有是Object类型bean的名称
					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);
								}
                                //将通知放到list中
								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 ArrayList<>();
		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;
	}

到这里我们之前写的切面和通知就已经被缓存的容器中了,那么这些通知我们在什么时候用呢? 我想大多数同学肯定会猜到肯定在创建aop代理对象的时候使用啊,没错!

那么什么时候创建aop代理对象呢?

  • ​ 首先,创建代理对象我们肯定需要一个被代理对象存在,所以如果是创建一个bean的代理对象,那么肯定在它的实例化生命周期之后才能完成。
  • 那么我们就可以定位到代理对象的创建时在对象的population阶段或者initiation阶段
  • 代理对象的创建肯定和AbstractAutoProxyCreator类有关,上面提到它实现了InstantiationAwareBeanPostProcessors() 和BeanPostProcessor 两个接口,前者我们已经分析过了是用来寻找我们的切面类并将其中的通知方法缓存到容器中,那么后者就很有可能创建具体的代理对象时候用到的,并且我们知道BeanPostProcessor接口的轮询调用是在initializeBean()调用的,刚刚好符合我们上面的推理。
  • initializeBean()里面会轮询实现了BeanPostProcessor接口的类,其中就包含了我们用@EnableAspectJAutoProxy注入的AnnotationAwareAspectJAutoProxyCreator.class,那么我们直接来查看这个类实现的postProcessBeforeInitialization()postProcessAfterInitialization()看看到底是哪个方法,和具体怎么生成的代理类。

上面两个方法的实现,并不在本类中而是在AbstractAutoProxyCreator 这个父类实现的, 其中postProcessBeforeInitialization() 直接返回了传入的bean,所以没有什么实际的意义,我们主要看一下After方法。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
            //缓存中去拿bean的标识
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //主要看这里,这里是返回我们的代理对象,源码如下
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

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

		// Create proxy if we have advice.
    // 看这里,明确的注释,创建代理,如果我们存在它对应的通知的话
    //获取我们类能注入的通知,也就是上面我们缓存到容器中的那些
    //这里也判断这个bean存不存在需要注入的通知----->AopUtils.canApply()来判断这个bean是不是可以注入指定通知----->pointcut.fastMatch(info).maybeTrue()
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
            //将这个bean缓存成代理bean,标记它为是通过代理生成的bean
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            //创建代理对象,这里就返回了一个aop代理对象,包含我们写的通知。
			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;
	}

下面分析一下,createProxy源码:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

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

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            //将被代理bean定义的org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass这个key的值,设置为bean的全类名
			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());
	}

org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader),最终由这个方法来创建的。

// 默认采用cglig 来创建代理了
// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
// 这里就是把我们的通知变成了接口,放到了enhancer中
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//最终由这个方法创建了代理对象
return createProxyClassAndInstance(enhancer, callbacks);

总结

整个aop代理流程,其实核心就是利用bean的后置处理器,和cglib或者jdk动态代理技术实现的。bean的后置处理器,分两类,一类是InstantiationAwareBeanPostProcessors()另一类是BeanPostProcessors()

第一类的作用是解析我们代码中的切面类,并将切面里面的通知缓存到容器中,第二类就是具体来创建我们的代理对象,拿到第一步获取的通知,利用cglib或者jdk动态代理技术来创建代理对象并返回。

总结: bean后置处理器+动态代理技术 实现了aop。

pProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//最终由这个方法创建了代理对象
return createProxyClassAndInstance(enhancer, callbacks);

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值