Spring原始碼學習之AOP
我們都站在巨人的肩膀上
宣告:參考《spring原始碼深度解析》
1.Spring AOP主要採用動態代理實現,而動態代理分為兩種:
- JDK動態代理:其代理物件必須是某個介面的實現,它是通過在執行時期建立一個介面的實現類來完成對目標物件的代理。
- CGLIB代理:實現原理類似於JDK動態代理,只是他在執行期間生產的代理物件是針對目標類擴充套件的子類。CGLIB是高效的程式碼生成包,底層依靠ASM操作位元組碼實現,效能比JDK強。
2.建立代理主要包含兩步驟:
1. 獲取增強方法或者增強器
2. 根據獲取的增強器進行代理
- 首先來看Spring如何獲取增強器:
- 獲取所有的beanName,這一步驟中所有的在beanFacotry中註冊的Bean都會被提取出來。
- 遍歷所有的beanName,並找出宣告AspectJ註解的類,進行進一步的處理。
- 對標記為AspectJ註解的類進行增強器的提取。
- 將提取結果加入快取。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
//獲取所有的beanName
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
//迴圈找出所有beanName的增強方法
for (String beanName : beanNames) {
//不合法的bean則略過,由子類定義規則,預設返回true
if (!isEligibleBean(beanName)) {
continue;
}
//獲取對應的bean的型別
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//如果存在Aspect註解
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);
//解析標記AspectJ註解中的增強方法
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
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 LinkedList<Advisor>();
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;
}
核心提取方法getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
//獲取標記為AspectJ的類
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
//獲取標記為AspectJ的name
final String aspectName = maaif.getAspectMetadata().getAspectName();
//驗證
validate(aspectClass);
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(maaif);
final List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
//如果尋找的增強器不為空而且又配置了增強延遲初始化那麼需求在首位加入同步例項化增強器
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
//獲取DeclareParent註解
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
Spring會根據註解型別不同封裝不同的增強器
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 (!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;
}
- 尋找匹配的增強器
前面提取的增強器並不一定符合所有的bean,我們還會配置萬用字元的增強器
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply 函式主要功能是尋找所有增強器中適用於當前class的增強器。引介增強與普通的增強是處理不一樣的,所以分開處理。真正的匹配在canApply中實現。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
- 建立代理
獲取到所有對應的bean的增強器後,可以進行代理的建立了。
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
//獲取當前類中相關屬性
proxyFactory.copyFrom(this);
//決定對於給定的bean是否應該使用targetClass而不是他的介面代理
//檢查proxyTargeClass設定以及preserveTargetClass屬性
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);
//用來控制代理工廠被配置之後,是否允許修改通知
//預設值為false(即在代理被配置之後,不允許修改代理的配置)
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
對於代理類的建立及處理,Spring委託給了ProxyFactory去處理,而在此函式中主要是對ProxyFactory的初始化操作,進而對真正的建立代理做準備,這些初始化操作包括如下內容。
1. 獲取當前類中的屬性
2. 新增代理介面
3. 封裝Advisor並加入到ProxyFactory中
4. 設定要代理的類
5. 當然在Spring中還為子類提供了定製的函式customizeProxyFactory,子類可以在此函式中進行對ProxyFactory的進一步封裝
6. 進行獲取代理操作
而真正在建立代理的是createAopProxy,如下:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//建立代理
return getAopProxyFactory().createAopProxy(this);
}
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()) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JdkDynamicAopProxy繼承了InvocationHandler,核心程式碼寫在了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;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
相關推薦
Spring原始碼學習之AOP
我們都站在巨人的肩膀上 宣告:參考《spring原始碼深度解析》 1.Spring AOP主要採用動態代理實現,而動態代理分為兩種: JDK動態代理:其代理物件必須是某個介面的實現,它是通過在執行時期建立一個介面的實現類來完成對目標物件的代理。 CG
Spring原始碼學習之路---深入AOP(終)
原文地址:https://blog.csdn.net/zuoxiaolong8810/article/details/8962353 上一章和各位一起看了一下springAOP的工作流程,當我們給出AOP相關的配置以後,直接從IOC容器中拿出來的就是已經加強過的bean
spring原始碼解析之AOP原理
一、準備工作 在這裡我先簡單記錄下如何實現一個aop: AOP:【動態代理】 指在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式; 1、匯入aop模組;Spring AOP:(spring-aspects) 2、定義一個業務邏輯類(
spring原始碼學習之路---IOC容器初始化要義之bean定義載入(四)
上章說到要帶各位去看看bean定義載入的要義,其實就是loadBeanDefinitions這個方法的具體實現步驟,下面我們跟隨這個方法去看下它到底是如何載入bean定義的。 上面是我擷取的實現了loadBeanDefinitions的類級別截圖,loadBeanDefinit
spring原始碼學習之路---深度分析IOC容器初始化過程(三)
分析FileSystemXmlApplicationContext的建構函式,到底都做了什麼,導致IOC容器初始化成功。 public FileSystemXmlApplicationContext(String[] configLocations, boolean ref
spring原始碼學習之路---IOC實現原理(二)
上一章我們已經初步認識了BeanFactory和BeanDefinition,一個是IOC的核心工廠介面,一個是IOC的bean定義介面,上章提到說我們無法讓BeanFactory持有一個Map package org.springframework.beans.factory.supp
spring原始碼學習之路---IOC初探(一)
首先把spring原始碼匯入,怎麼匯入百度下。 首先我們來說一下IOC,IOC是spring最核心的理念,包括AOP也要屈居第二,那麼IOC到底是什麼呢,四個字,控制反轉。 網上有不少是這麼解釋IOC的,說IOC是將物件的建立和依賴關係交給容器,這句話我相信不少人都知道,在我個人的理解
Spring原始碼學習之容器的功能擴充套件
我們都站在巨人的肩膀上 宣告:參考《Spring原始碼深度解析》 ApplicationContext和BeanFactory區別: Application提供了更多的擴充套件功能,簡單來說,就是:Application包含了BeanFactory的所
SPRING原始碼學習之路(一)
結合《Spring技術內幕:深入解析SPRING架構與設計原理》這本書開啟Spring學習之路。 ps:之前其實已經看過一部分了,但是也就是看過,一看而過了。o(╯□╰)o 結合FileSystemXmlApplicationContext來分析 具體實現如下: /
Spring原始碼學習之IOC實現原理(二)-ApplicationContext
一.Spring核心元件結構 總的來說Spring共有三個核心元件,分別為Core,Context,Bean.三大核心元件的協同工作主要表現在 :Bean是包裝我們應用程式自定義物件Object的,Object中存有資料,而Context就是為了這些資料存放提供一個生存環境,儲存各個 bean之間的
Spring原始碼學習之IOC容器實現原理(一)-DefaultListableBeanFactory
從這個繼承體系結構圖來看,我們可以發現DefaultListableBeanFactory是第一個非抽象類,非介面類。實際IOC容器。所以這篇部落格以DefaultListableBeanFactoryIOC容器為基準進行IOC原理解析。 一.兩個重要介面 前面已經分析了BeanFactor,它的三個直接子
Spring原始碼學習之BeanFactory體系結構
public interface AutowireCapableBeanFactory extends BeanFactory { /** * Constant that indicates no externally defined autowiring. Note that
Spring原始碼學習之BeanFactory和FactoryBean
今天在學習Spring原始碼的時候,發現了spring中不僅僅有BeanFactory,還有FactoryBean,突然覺得分不清這兩者之間有什麼不同,難道僅僅是名字嗎?但是從名字上我們也能看出一些端
SPRING原始碼學習之路(二)
上一篇,已經對IOC容器的初始化過程有個大體認識,接著看IOC容器的依賴注入。 依賴注入的觸發是在使用者第一次向容器索要Bean時才觸發,當然也可以設定lazy-init讓容器提前完成Bean的預例項化,預例項化是在初始化過程中完成 我
Spring原始碼學習之路---IOC實現原理(三)
原文地址:https://blog.csdn.net/zuoxiaolong8810/article/details/8548478 上一章我們已經初步認識了BeanFactory和BeanDefinition,一個是IOC的核心工廠介面,一個是IOC的be
Spring原始碼學習之BeanFactory介面簡述
BeanFactory介面中定義如下: BeanFactory.class介面中定義的只是一下介面,通過實現這一系列介面,可以使用不同的bean的檢索方法(獲取不同的bean),很方便的從ioc容器中獲取需要的bean,從而忽略ioc的具體實現。 下面大致介紹一下這幾個介
spring原始碼學習之六 元素處理過程
概述: </property-placeholder> 主要用來讀取配置資訊替換Bean中的${}佔位符, 常用配置如下: <context:property-placeholder ignore-resource-not-found="
spring原始碼學習之整合Mybatis原理分析
開發十年,就只剩下這套架構體系了! >>>
Spring原始碼分析之AOP從解析到呼叫
正文: 在上一篇,我們對IOC核心部分流程已經分析完畢,相信小夥伴們有所收穫,從這一篇開始,我們將會踏上新的旅程,即Spring的另一核心:AOP! 首先,為了讓大家能更有效的理解AOP,先帶大家過一下AOP中的術語: - **切面(Aspect)**:指關注點模組化,這個關注點可能會橫切多個物件。事務
Spring原始碼學習【八】SpringMVC之DispatcherServlet
目錄 一、前言 三、總結 一、前言 Web環境是Spring框架的重要應用場景,而SpringMVC又是Web開發中一個常用的框架,因此我們有必要學習一下SpringMVC的實現原理。 回到Web專案的配置檔案web.xml中,在使用SpringMV