Spring源码分析--AOP

与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护。AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。一般用于日志记录、权限验证、效率检查、事务管理。

五、AOP实现

实现AOP方式有两种,Aspectj和spring aop。我们这里主要了解spring aop,而spring aop的实现也有两种,借鉴aspectj来实现的,一种是自己本身api。我们常用的就是借鉴aspectj来实现的,然后有xml配置和注解配置方式。

  


  
    
   
         
        
    
       
        
    


我们前面学到,特定的标签都有相应的命名空间解析类解析,即AopNamespaceHandler

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
	 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
	 * and '{@code scoped-proxy}' tags.
	 */
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

}

 

1、注解方式

在AspectJAutoProxyBeanDefinitionParser类的parse方法中会注册 AnnotationAwareAspectJAutoProxyCreator到是spring容器中,父类实现了InstantiationAwareBeanPostProcessor后置处理器。

public BeanDefinition parse(Element element, ParserContext parserContext) {
		// 注册   AnnotationAwareAspectJAutoProxyCreator
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		// 对注解中子类的处理
		extendBeanDefinition(element, parserContext);
		return null;
	}

在bean初始化的时候会第一次后置处理器调用,执行父类AbstractAutoProxyCreator的postProcessBeforeInstantiation中会去解析注解@Aspect

//判断是否是Advisor、Advice、AopInfrastructureBean
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}

进入到AspectJAwareAdvisorAutoProxyCreator.shouldSkip

protected boolean shouldSkip(Class beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		List candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

通过findCandidateAdvisors方法来获取所有的候选 advisor

protected List findCandidateAdvisors() {
		// 获得 Advisor 实现类
		List advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
            //处理@Aspect注解类, 解析成Advisor
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

创建advisor的逻辑发生在扩展接口中的postProcessBeforeInstantiation,实例化之前执行,如果有自定义的TargetSource指定类,则直接生成代理类,这种情况使用不多,常规代理类还是在中postProcessAfterInitialization创建。

现在我们重点看父类AbstractAutoProxyCreator的postProcessAfterInitialization方法。该方法的主要作用也就是将所有拥有advice的bean重新包装为proxy,会在bean初始化的时候第八次调用后置处理器执行。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		// AOP代理逻辑实现
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

我们现在看一下bean如何被包装为proxy

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;
		}
		// 如果是aop基础类或配置不需要代理 直接返回
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		//判断这个Bean是否匹配要生成代理
		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;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

可以看到Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))就是去创建相应的AOP代理类。

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,proxy的创建主要在这工厂类实现
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		//将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

		//调用getProxy获取bean对应的proxy
		return proxyFactory.getProxy(getProxyClassLoader());
	}

在具体看proxyFactory.getProxy(getProxyClassLoader())创建的是什么代理对象,JDKProxy或者CGLIBProxy。这需要根据我们配置的来选择,默认是JDK代理对象。进入JdkDynamicAopProxy.getProxy去生成代理对象

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);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

接下来我们看JDKProxy代理对象,我们可以看到JdkDynamicAopProxy实现InvocationHandler,所以创建代理对象传的是本身this,那么看本类的invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		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();
			Class targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			//会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法得chain是Empty而已
			//获取Advice集合,获取作用在这个方法上的所有拦截器链
			List 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...
				//使用ReflectiveMethodInvocation来返回具体对象
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 此处会执行所有的拦截器链  交给AOP的MethodInvocation去处理,执行前置加强、后置加强等等逻辑
				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);
			}
		}
	} 
  

而拦截的方法真正调用的是执行了invocation.proceed()。

 

2、XML方式

会去创建ConfigBeanDefinitionParser来解析config的标签

public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);

		configureAutoProxyCreator(parserContext, element);

		List childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			}
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}

可以看到pointcut、advisor、aspect都有相应的方法去解析,都会把配置信息封装到类中。

在parseAdvisor(elt, parserContext)中会创建AdvisorBeanDefinition并把信息封装在类中。

AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext)
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
		// 根据通知类型的不同,分别创建对应的BeanDefinition对象
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(advisorElement));

		String adviceRef = advisorElement.getAttribute(ADVICE_REF);
		if (!StringUtils.hasText(adviceRef)) {
			parserContext.getReaderContext().error(
					"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
		}
		else {
			// 为不同的增强通知类,添加统一的属性值
			advisorDefinition.getPropertyValues().add(
					ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
		}

		// 为不同的增强通知类,添加对应的属性值
		if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
		}

		return advisorDefinition;
	}

可以知道根据切入方式的不同,分别创建对应的BeanDefinition对象。
before对应AspectJMethodBeforeAdvice、After对应AspectJAfterAdvice、after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice、around对应AspectJAroundAdvice。

而跟前面一样AopNamespaceHandler初始化的时候会创建AspectJAutoProxyBeanDefinitionParser,后面的逻辑跟注解方式一样去生成代理对象。

 

3、原生Spring AOP实现

通过配置工厂类来实现aop



        
        
        
            
                xxx
            
        
    

我们知道工厂类返回的对象是调用getObject方法

public Object getObject() throws BeansException {
		initializeAdvisorChain();
		if (isSingleton()) {
			return getSingletonInstance();
		}
		else {
			if (this.targetName == null) {
				logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			}
			return newPrototypeInstance();
		}
	}

在initializeAdvisorChain方法会根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。

之后会去创建代理对象

getProxy(copy.createAopProxy())

创建代理对象会有两种选择,jdk或者cglib

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// JDK动态代理和Cglib的选择
		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);
		}
	}

配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。

你可能感兴趣的:(spring)