Spring源码-AOP

AOP基本概念

面向切面编程(Aspect-oriented Programming 简称AOPAOP) ,是相对面向对象编程(Object-oriented Programming 简称OOP)的框架,作为OOP的一种功能补充. OOP主要的模块单元是类(class)。而AOP则是切面(aspect)。切面会将诸如事务管理这样跨越多个类型和对象的关注点模块化(在AOP的语义中,这类关注点被称为横切关注点(crosscutting))。

  • 切面(Aspect): 指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级Java应用中有关横切关注点的例子。 在Spring AOP中,切面可以使用通用类基于模式的方式(schema-based approach)或者在普通类中以@Aspect注解(@AspectJ 注解方式)来实现。

    • 切面包含通知,切点,连接点; 映射Spring中,可以理解为加了@Aspect注解的类就是一个切面;

  • 连接点(Join point): 在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点。在Spring AOP中,一个连接点总是代表一个方法的执行。

    • 所有被增强的方法

  • 通知(Advice): 在切面的某个特定的连接点上执行的动作。通知有多种类型,包括“around”, “before” and “after”等等。通知的类型将在后面的章节进行讨论。 许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。

    • 所有的增强逻辑,可以理解为加了@Before,@After 等注解的方法

  • 切点(Pointcut): 匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用AspectJ切点语义。

    • 切点表达式,可以理解为加了@PointCut注解中 execution(* com.jtfu.demo.service.OrderService.*(..))

  • 引入(Introduction): 声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被通知的对象上。例如,可以使用引入来使bean实现 IsModified接口, 以便简化缓存机制(在AspectJ社区,引入也被称为内部类型声明(inter))。

  • 目标对象(Target object): 被一个或者多个切面所通知的对象。也被称作被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,那么这个对象永远是一个被代理(proxied)的对象。

    • 被代理的对象

  • AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。

    • 代理对象

  • 织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被被通知的对象的过程。这个过程可以在编译时(例如使用AspectJ编译器)、类加载时或运行时中完成。 Spring和其他纯Java AOP框架一样,是在运行时完成织入的。

    • 将通知应用到代理对象中方法的过程可以理解成织入

SpringAop实现方式

Spring中将所有的增强封装为一个Advisor对象, 可以理解成Advisor包含了 通知(Advice) 和 切点(PointCut);

接口实现

@Component
public class MyAdvisor implements MethodBeforeAdvice, PointcutAdvisor {

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println(method.getName()+"前置增强");
	}

	@Override
	public Pointcut getPointcut() {
		return new MyPointCut();
	}

	@Override
	public Advice getAdvice() {
		return this;
	}

	@Override
	public boolean isPerInstance() {
		return false;
	}


	public static class  MyPointCut implements Pointcut{
		@Override
		public ClassFilter getClassFilter() {
			//进行Class过滤,
			return new ClassFilter() {
				@Override
				public boolean matches(Class<?> clazz) {
					return clazz.equals(UserService.class);
				}
			};
		}

		@Override
		public MethodMatcher getMethodMatcher() {
			//进行Method过滤,
			return new MethodMatcher() {
				@Override
				public boolean matches(Method method, Class<?> targetClass) {
					return method.getName().equals("test");
				}
				@Override
				public boolean isRuntime() {
					return false;
				}

				@Override
				public boolean matches(Method method, Class<?> targetClass, Object... args) {
					return method.getName().equals("test");
				}
			};
		}
	}
}

注解实现


@Aspect
@Component
public class LubanAspect {

	@Pointcut("execution(* com.jtfu.demo.service.OrderService.*(..))")
	public void test() {

	}

	@Before(value = "test()")
	public void before(){
		System.err.println("方法执行前调用.....");
	}
}

@Import注解

@Import注解可以添加一个Bean到Spring容器中,在Spring源码中 对实现了 ImportSelector,DeferredImportSelector,ImportBeanDefinitionRegistrar 接口的类,有不同的处理逻辑;

解析Advisor

在Spring中想使用Aop功能要先添加  @EnableAspectJAutoProxy 注解,这个注解中又包含  @Import(AspectJAutoProxyRegistrar.class), @Import注解 可以往Spring中添加一个Bean,来看一下AspectJAutoProxyRegistrar 具体执行什么逻辑;  追踪代码 发现往Spring中注册了一个  AnnotationAwareAspectJAutoProxyCreator.class 的Bean,查看它的继承关系;

 

可以从继承关系图上看到 实现了 BeanPostProcessor, InstantiationAwareBeanPostProcessor,SmartInstantiationAwareBeanPostProcessor 三个Bean的后置处理器;

BeanPostProcessor

postProcessBeforeInitialization  初始化之前调用
postProcessAfterInitialization   初始化之后调用

InstantiationAwareBeanPostProcessor

postProcessBeforeInstantiation  实例化之前调用
postProcessAfterInstantiation   实例化之后调用
postProcessProperties  属性填充后调用

SmartInstantiationAwareBeanPostProcessor

determineCandidateConstructors  推断构造方法时调用
getEarlyBeanReference  提早暴露Bean时调用

通过对SpringIOC 生命周期的了解, 先看postProcessBeforeInstantiation 方法; 在父类  AbstractAutoProxyCreator中调用;

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			// advisedBeans中存的是当前这个bean需不需要代理
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}

			// 当前bean是否跳过代理
			//isInfrastructureClass 判断beanClass是否实现了Advisor 等接口
			//判断是否加了@Aspect 注解
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

	}

以上的代码逻辑,需要自己去跟一下。 总结为下图:扫描到所有的Advisor 后,判断当前BeanClass 是否应该跳过; 如果不跳过,再去判断 TargetSource ,是否提前生成代理对象;  这里一般都不会生成

 

2.getEarlyBeanReference(Object bean, String beanName)  提早暴露Bean;可用于解决循环依赖,在这里也可以提早进行AOP代理;

@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName); // beanName  aService
		// 判断
		this.earlyProxyReferences.put(cacheKey, bean);

		return wrapIfNecessary(bean, beanName, cacheKey);  //代理对象
	}

3.postProcessAfterInstantiation  什么都没做;

4.postProcessBeforeInitialization  什么都没做;

5.postProcessProperties 什么都没做;

6.postProcessAfterInitialization 正常进行AOP增强的地方,处于SpringIOC生命周期中 初始化完成以后的后置处理器调用逻辑;

@Override
	// 正常情况进行AOP的地方
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// earlyProxyReferences中存的是哪些提前进行了AOP的bean,beanName:AOP之前的对象
			// 注意earlyProxyReferences中并没有存AOP之后的代理对象  BeanPostProcessor
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 没有提前进行过AOP,则进行AOP
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		// 为什么不返回代理对象呢?
		return bean;   //
	}
wrapIfNecessary(bean, beanName, cacheKey);
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 在当前targetSourcedBeans中存在的bean,表示在实例化之前就产生了代理对象
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 当前这个bean不用被代理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}

		// 先判断当前bean是不是要进行AOP,比如当前bean的类型是Pointcut、Advice、Advisor等那就不需要进行AOP
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取当前beanClass所匹配的advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

		// 如果匹配的advisors不等于null,那么则进行代理,并返回代理对象
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 基于bean对象和Advisor创建代理对象
			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;
	}

前几步与实例化之前执行的逻辑大致相同,判断当前的BeanClass是否需要被增强;主要逻辑是

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		// 针对当前bean查找合格的Advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
findEligibleAdvisors(Class<?> beanClass, String beanName)
// 得到所有的Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 进行筛选
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

		// 提供给子类去额外的添加advisor
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 按order进行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}

		// 返回匹配的Advisor
		return eligibleAdvisors;
List<Advisor> candidateAdvisors = findCandidateAdvisors(); 与上面解析的逻辑完全相同,拿到当前BeanFactory中所有的Advisor,然后遍历Advisors 判断有没有对当前BeanClass合适的切点;可以理解为下图:

经过筛选之后,已经确定BeanClass需要被增强,那么就去创建代理对象;

创建代理对象

Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

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

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);	// 复制配置参数
		// 是否指定了必须用cglib进行代理
		if (!proxyFactory.isProxyTargetClass()) {
			// 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				// 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
				evaluateProxyInterfaces(beanClass, proxyFactory); // 判断beanClass有没有实现接口
			}
		}


		// 将commonInterceptors和specificInterceptors整合再一起
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

		proxyFactory.addAdvisors(advisors);	// 向ProxyFactory中添加advisor
		proxyFactory.setTargetSource(targetSource); // 被代理的对象
		customizeProxyFactory(proxyFactory);

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

		// 生成代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);  重新封装Advisor 为 DefaultPointcutAdvisor.class ;
设置到ProxyFactiry中,生成并返回代理对象;

proxyFactory.getProxy(getProxyClassLoader()); 代理对象使用JDK动态代理 或者 CGlib 生成;

如何选择动态代理的方式

@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// Spring到底何时使用cglib,何时使用jdk动态代理
		// 如果设置的targetClass是一个接口,会使用jdk动态代理
		// 默认情况下(optimize为false, isProxyTargetClass为false), ProxyFactory添加了接口时,也会使用jdk动态代理

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

依据以上代码可以得到结论:1.未实现接口时,使用Cglib代理。  2. 实现接口,未指定isProxyTargetClass=true 时 使用jdk动态代理; 3. 被代理对象是接口 或者 已经是一个代理对象时,使用jdk动态代理

4.指定isProxyTargetClass=true,无论是否实现接口 都使用Cglib动态代理;

以下是jdk动态代理生成代理类的逻辑;通过对jdk动态代理的了解,在进行方法调用时会调用InvocationHandler.invoke()方法。这里传入的是 this,再去追踪invoke方法;

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		// 获取生成代理对象所需要实现的接口
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

		// 判断这些接口中有没有定义equals方法,hashcode方法
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		// 针对所指定的接口生成代理对象,包括用户所添加的接口以及SpringProxy、Advised、DecoratingProxy
		// 所以生成的代理对象可以强制转换成任意一个接口类型
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		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;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget(); // targetSource分为两种:SingletonTargetSource、EmptyTargetSource
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// 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...
				MethodInvocation 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);
			}
		}
	}

个人理解invoke方法的主要学习点有几个

1. 在使用jdk动态代理时,如果在被代理的方法内,再调用本对象的其他方法,不会有增强效果; 此时就需要获得代理对象来调用方法;

//  暴露代理对象;
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

2.责任链的构建,会将所有的Advisor 转成MethodInterceptor类型;

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

3.递归调用责任链 retVal = invocation.proceed();  会走MethodInterceptor.invoke()方法。 具体细节去代码中看吧,逻辑不方便表示.


	@Override
	@Nullable
	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		//我们从一个索引-1开始,并提前递增。
		// 如果执行到最后一个拦截器了,就去执行原始方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//currentInterceptorIndex 默认= -1, 这里++currentInterceptorIndex, 就是取第0个
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			/*这里只有 在Advisor --> pointCut -->MethodMatcher.isRuntime= true 时才会走.*/

			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, 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);
		}
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值