1. 程式人生 > >Spring原始碼閱讀4.2-Aspecjt AOP之代理物件的建立

Spring原始碼閱讀4.2-Aspecjt AOP之代理物件的建立

  繼續上一篇的話題,在《Spring原始碼閱讀4.1-Aspecjt AOP之獲取Adivsor》,我們說獲取了所有的AspectJ以及其Advisor,其中每個Advisor都和其Aspectj類的表示式一起快取到了陣列中,以便後續直接使用。在這裡要補充一下InstantiationModelAwarePointcutAdvisorImpl物件的初始化。只上原始碼:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
			MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

		this.declaredPointcut = ajexp;
		this.method = method;
		this.atAspectJAdvisorFactory = af;
		this.aspectInstanceFactory = aif;
		this.declarationOrder = declarationOrderInAspect;
		this.aspectName = aspectName;

		if (aif.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut =
					Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
			this.lazy = true;
		}
		else {
			// A singleton aspect.
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
			this.pointcut = declaredPointcut;
			this.lazy = false;
		}
	}
在instantiateAdivice方法中,根據不同的型別建立了不同的Advice物件。
@Override
	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
			MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

		Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;

		switch (aspectJAnnotation.getAnnotationType()) {
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
				break;
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrderInAspect);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();
		return springAdvice;
	}
我們回到AspectJAwareAdvisorAutoProxyCreator的父類AbstractAdvisorAutoProxyCreator的findEligibleAdvisors方法上來
/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
在上文中我們已經說過了所有候選Advisor的獲取,下面就要從這些增強中獲取可以適用到目標物件的Advisor,跟蹤下原始碼:
	/**
	 * Search the given candidate Advisors to find all Advisors that
	 * can apply to the specified bean.
	 * @param candidateAdvisors the candidate Advisors
	 * @param beanClass the target's bean class
	 * @param beanName the target's bean name
	 * @return the List of applicable Advisors
	 * @see ProxyCreationContext#getCurrentProxiedBeanName()
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
  ProxyCreationContext.setCurrentProxiedBeanName(beanName);設定了beanName,這裡使用了ThreadLocal,用執行緒物件做key,只可以儲存一個值。使用AopUtiles獲取適用的Advisor,我們布深究其實現方法,到這裡適用的Advisor已經獲取到,直接建立代理物件。
protected Object createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

		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);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}

		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

		return proxyFactory.getProxy(getProxyClassLoader());
	}
回到wrapIfNecessary方法:// 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;
  }
	/**
	 * Create a new proxy according to the settings in this factory.
	 * <p>Can be called repeatedly. Effect will vary if we've added
	 * or removed interfaces. Can add and remove interceptors.
	 * <p>Uses the given class loader (if necessary for proxy creation).
	 * @param classLoader the class loader to create the proxy with
	 * (or {@code null} for the low-level proxy facility's default)
	 * @return the proxy object
	 */
	public Object getProxy(ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

這裡使用了DefaultAopProxyFactory物件來返回代理工具物件,簡單來說,就是根據條件決定返回JdkDynamicAopProxy還是ObjenesisCglibAopProxy
@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);
		}
	}

然後用返回的代理工具類去例項化目標代理類。先看下JDK代理型別,呼叫其getProxy方法
	@Override
	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is "
					+ this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

相關推薦

Spring原始碼閱讀4.2-Aspecjt AOP代理物件建立

  繼續上一篇的話題,在《Spring原始碼閱讀4.1-Aspecjt AOP之獲取Adivsor》,我們說獲取了所有的AspectJ以及其Advisor,其中每個Advisor都和其Aspectj類的表示式一起快取到了陣列中,以便後續直接使用。在這裡要補充一下Instan

spring原始碼閱讀2)-aopjdk動態代理深入解析

續spring原始碼閱讀(2)-aop之j動態代理 我們從需求作為動態代理髮展的切入吧 現在有5個已經投產了的run100m的實現,我們新的需求需要監控不同實現的執行效能,如果我們針對這五個實現分別去新增效能監控的程式碼,如此就造成兩個問題: 一個是已經穩定的程式碼需要

spring原始碼閱讀2)-aop原始碼解析篇

經過一個aop術語介紹和動態代理的深入講解,我們終於可以來看aop的原始碼了,下面跟著博主一點點剖析spring aop原始碼的實現吧 我們知道spring使用中我們只要做好相關的配置,spring自動幫我們做好了代理的相關工作。 我們從三個方面入手吧 1、配置 2、

spring 2.5 AOP代理類基礎理解

JDK或者第三方控制元件動態生成代理物件的位元組碼, 使用jdk的代理類(Proxy)建立代理物件, Proxy代理類使用前提:目標物件面向介面 //建立代理物件 public Class JDKProxyFactory implement

spring原始碼閱讀(1)- ioc依賴注入bean載入

還是先看下DefaultListableBeanFactory的類結構圖  我們從User user = (User) beanFactory.getBean("user");入手進入bean的載入管理流程。 這裡還是堅持走主線的流程,去掉無關的枝葉,儘量讓業務變得簡

Spring原始碼閱讀Bean載入(xml)1

先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactory是bean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了

Cartographer原始碼閱讀(4):Node和MapBuilder物件2

  MapBuilder的成員變數sensor::Collator sensor_collator_;   再次閱讀MapBuilder::AddTrajectoryBuilder方法。首先構造了mapping::GlobalTrajectoryBuilder例項,接著作為引數構造了CollatedTraj

4Spring原始碼分析4初始化Bean

1、記錄建立bean的ObjectFactory,目的是為了解決迴圈依賴 if (instanceWrapper == null)

Spring 原始碼閱讀 深入理解 finishBeanFactoryInitialization

原始碼入口 上篇博文中我們看到了將Spring環境中的 BeanPostProcessor找出來,新增到BeanFactory中的beanPostProcessors中,統一維護,本片博文繼續往下拓展,看下Spring如何例項化bean,以及如何實現在bean的例項化通過各種各樣的後置處理器完成bean的增強

spring原始碼閱讀筆記06:bean載入準備建立bean

  上文中我們學習了bean載入的整個過程,我們知道從spring容器中獲取單例bean時會先從快取嘗試獲取,如果快取中不存在已經載入的單例bean就需要從頭開始bean的建立,而bean的建立過程是非常複雜的,本文就開始研究bean載入這部分的原始碼。 1. bean建立流程分析   在Spring中bea

Android——4.2 - 3G移植 reference-ril .pppd 撥號上網 (三)

而且 init.rc nal null ann 源代碼分析 suggest cdma 初始化 Android的RIL機制中的 reference-ril.c 即為廠商提供的驅動接口。這個驅動源代碼各個廠商都是有提供的,網上也有下載。我如今用的就是huawe

Spring學習總結(2)- AOP

服務 win align schema 可重用性 ext 4.0 art 屬性表 一,什麽是AOP AOP(Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,

Spring原始碼解析(十三)——AOP原理——AnnotationAwareAspectJAutoProxyCreator註冊

 * 2、 AnnotationAwareAspectJAutoProxyCreator:  *         AnnotationAwareAspectJAutoProxyCreator &nbs

Swift 4.2語言參考宣告

 宣告 用於向你的程式引入新的名字或結構。例如,你可以使用宣告來引入函式和方法,引入變數和常量,還可以定義列舉,結構體,類,和協議型別。你還可以用宣告擴充套件命名型別的行為或在程式裡匯入其他地方定義的模組。 在 Swift 裡,大多數宣告在某種意義上也是定義,因為在定義的同時

Spring原始碼閱讀——ApplicationContext

Spring中提供了一個介面ApplicationContext,用於擴充套件BeanFactory中現有的功能。它提供了更多的功能。現在我們來看下它的實現: public ClassPathXmlApplicationContext(String[] configLocat

Spring原始碼閱讀——bean的載入過程解析

前言 在上一節中,我們已經瞭解過Spring對bean從XML中提取,並且以BeanDefinition型別解析註冊到Spring的DefaultListableBeanFactory中取了,那麼,接下來就應該來看下我們在Spring中獲取一個例項過程中,bean是如何載入成為我們需

Spring原始碼閱讀——BeanFactoryPostProcessor與BeanPostProcessor

摘要 Spring IoC容器允許BeanFactoryPostProcessor在容器例項化任何bean之前讀取bean的定義(配置元資料),並可以修改它。 BeanFactoryPostProcessor: BeanFactory的後置處理器(處理的物件是BeanFact

XSStrike原始碼閱讀2)——四種模式

1.bruteforcer模式 功能介紹 根據使用者提供的payloads檔案去暴力測試每一個引數,以此來確定是否存在xss漏洞(說起來也就是一個兩層迴圈)。 具體實現 XSStrike3.0 bruteforcer.py原始碼如下: import copy from

Spring原始碼學習【八】SpringMVCDispatcherServlet

目錄 一、前言 三、總結 一、前言 Web環境是Spring框架的重要應用場景,而SpringMVC又是Web開發中一個常用的框架,因此我們有必要學習一下SpringMVC的實現原理。 回到Web專案的配置檔案web.xml中,在使用SpringMV

Spring AOP代理設定模式

一.什麼是AOP Spring的AOP:即面向切面程式設計,其程式碼實質,即代理模式的應用。 二.三種代理設定模式(目標物件不願意做的事,代理物件給我們實現) 代理模式程式碼的主要特點是:不改變原有類的前提下,在原有類某些方法執行前後,插入任意程式碼。所以代理模