亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

關于spring的aop攔截的問題 protected方法代理

系統 1868 0

之前一論壇朋友問的,復制保存下。 原文地址。

?

問題

貌似不能攔截私有方法??
試了很多次,都失敗了,是不是不行?。?

我想了一下,因為aop底層是代理,?
jdk是代理接口,私有方法必然不會存在在接口里,所以就不會被攔截到;?
cglib是子類,private的方法照樣不會出現在子類里,也不能被攔截。?

我不是類內部直接調用方法,而是通過維護一個自身實例的代理?

execution(* test.aop.ServiceA.*(..))?

Java代碼?? 收藏代碼
  1. public ? class ?ServiceA?{??
  2. ??
  3. ???? private ?ServiceA??self;??
  4. ??
  5. ???? public ? void ?setSelf(ServiceA?self)?{??
  6. ???????? this .self?=?self;??
  7. ????}??
  8. ??
  9. ???? public ?String?methodA(String?str)?{??
  10. ????????System.out.println( "methodA:?args=" ?+?str);??
  11. ????????self.methodB( "b" );??
  12. ???????? return ? "12345" ?+?str;??
  13. ????}??
  14. ??
  15. ???? private ?String?methodB(String?str)?{??
  16. ????????System.out.println( "methodB:?args=" ?+?str);??
  17. ????????self.methodC( "c" );??
  18. ???????? return ? "12345" ?+?str;??
  19. ????}??
  20. ??
  21. ???? public ?String?methodC(String?str)?{??
  22. ????????System.out.println( "methodC:?args=" ?+?str);??
  23. ???????? return ? "12345" ?+?str;??
  24. ????}??
  25. }??



如果外部調用methodA,那么methodA和methodC會被攔截到,methodB不行?

是不是這么回事??
但是stackoverflow上,有人說 it works fine?
http://stackoverflow.com/questions/4402009/aspectj-and-catching-private-or-inner-methods?

execution( public ?* test.aop.ServiceA.*(..))?
還有個奇怪的現象,execution里如果不寫權限,那么public protected package的方法都能被攔截到?
如果寫了public,那就只攔截public方法這個沒問題,?
如果寫了protected,他就什么事情都不做,連protected的方法也不攔截。

?

分析

private方法 在Spring使用純Spring AOP(只能攔截public/protected/包)都是無法被攔截的 因為子類無法覆蓋;包級別能被攔截的原因是,如果子類和父類在同一個包中是能覆蓋的。?

在cglib代理情況下, execution(* *(..)) 可以攔截 public/protected/包級別方法(即這些方法都是能代理的)。?

Java代碼?? 收藏代碼
  1. private ? static ? boolean ?isOverridable(Method?method,?Class?targetClass)?{??
  2. ???????? if ?(Modifier.isPrivate(method.getModifiers()))?{??
  3. ???????????? return ? false ;??
  4. ????????}??
  5. ???????? if ?(Modifier.isPublic(method.getModifiers())?||?Modifier.isProtected(method.getModifiers()))?{??
  6. ???????????? return ? true ;??
  7. ????????}??
  8. ???????? return ?getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));??
  9. ????}??




如果想要實現攔截private方法的 可以使用 原生 AspectJ 編譯期/運行期織入。?


引用
如果寫了protected,他就什么事情都不做,連protected的方法也不攔截;這個應該不會


原因基本分析明白了:?

是否能應用增強的判斷代碼如下(org.springframework.aop.support.AopUtils):?

Java代碼?? 收藏代碼
  1. public ? static ? boolean ?canApply(Pointcut?pc,?Class?targetClass,? boolean ?hasIntroductions)?{??
  2. ???? if ?(!pc.getClassFilter().matches(targetClass))?{??
  3. ???????? return ? false ;??
  4. ????}??
  5. ??
  6. ????MethodMatcher?methodMatcher?=?pc.getMethodMatcher();??
  7. ????IntroductionAwareMethodMatcher?introductionAwareMethodMatcher?=? null ;??
  8. ???? if ?(methodMatcher? instanceof ?IntroductionAwareMethodMatcher)?{??
  9. ????????introductionAwareMethodMatcher?=?(IntroductionAwareMethodMatcher)?methodMatcher;??
  10. ????}??
  11. ??
  12. ????Set?classes?=? new ?HashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass));??
  13. ????classes.add(targetClass);??
  14. ???? for ?(Iterator?it?=?classes.iterator();?it.hasNext();)?{??
  15. ????????Class?clazz?=?(Class)?it.next();??
  16. ????????Method[]?methods?=?clazz.getMethods();??
  17. ???????? for ?( int ?j?=? 0 ;?j?<?methods.length;?j++)?{??
  18. ???????????? if ?((introductionAwareMethodMatcher?!=? null ?&&??
  19. ????????????????????introductionAwareMethodMatcher.matches(methods[j],?targetClass,?hasIntroductions))?||??
  20. ????????????????????methodMatcher.matches(methods[j],?targetClass))?{??
  21. ???????????????? return ? true ;??
  22. ????????????}??
  23. ????????}??
  24. ????}??
  25. ??
  26. ???? return ? false ;??
  27. }??



此處Method[] methods = clazz.getMethods();只能拿到public方法。。?

場景1:execution(* *(..))?

Java代碼?? 收藏代碼
  1. public ? class ?Impl2??{??
  2. ??????
  3. ???? protected / public ?String?testAop2()?{??
  4. ????????System.out.println( "234" );??
  5. ???????? return ? "1233" ;??
  6. ????}??
  7. }??


因為切入點沒有訪問修飾符,即可以是任意,因此canApply方法能拿到如wait這種public方法,即可以實施代理。?

場景2:execution(public * *(..))?

Java代碼?? 收藏代碼
  1. public ? class ?Impl2??{??
  2. ??????
  3. ???? public ?String?testAop2()?{??
  4. ????????System.out.println( "234" );??
  5. ???????? return ? "1233" ;??
  6. ????}??
  7. }??


因為攔截public的,因此canApply方法能拿到如wait這種public方法,即可以實施代理。?


場景3:execution(protected * *(..))?

Java代碼?? 收藏代碼
  1. public ? class ?Impl2??{??
  2. ??????
  3. ???? protected ?String?testAop2()?{??
  4. ????????System.out.println( "234" );??
  5. ???????? return ? "1233" ;??
  6. ????}??
  7. }??


還記得之前說過,在canApply方法中 的 Method[] methods = clazz.getMethods();只能拿到public方法的,因此跟protected訪問修飾符是無法匹配的,所以如果“execution(protected * *(..))” 是 無法代理的。?

這就是為什么execution(protected * *(..))在純Spring AOP環境下不行的原因。?

注,@Transactional注解事務的特殊情況:?

引用
方法的可見度和 @Transactional?
在使用代理的時候,@Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,系統也不會報錯, 但是這個被注解的方法將不會執行已配置的事務設置。如果你非要注解非公共方法的話,請參考使用AspectJ?



關于spring切入點語法可以參考我的博客 【 http://jinnianshilongnian.iteye.com/blog/1420691

?

?

wangyu1221 寫道

?

非常感謝您的回帖~canApply方法是不是用于判斷某個切點能否應用于某個類上,只要這個類里面有一個方法能夠和切點匹配,就返回true,從整個邏輯來看,就是這個類可以/需要被代理。?

實際運行時在方法攔截的時候,如果某個類不需要被代理,就直接調用這個類實例的方法,而不是這個類的代理的方法,?
如果需要代理,再匹配方法名和修飾符??

對于上面這個帖子里,之所以protected方法能被無訪問修修飾符的execution攔截,是因為這個類里面其他public方法被execution匹配了,導致spring認為這個類可以被代理,而不是protected的方法本身被execution匹配?



引用

?

canApply方法是不是用于判斷某個切點能否應用于某個類上,只要這個類里面有一個方法能夠和切點匹配,就返回true,從整個邏輯來看,就是這個類可以/需要被代理。


是的。?

引用

?

實際運行時在方法攔截的時候,如果某個類不需要被代理,就直接調用這個類實例的方法,而不是這個類的代理的方法,?
如果需要代理,再匹配方法名和修飾符?



這個只看Cglib2AopProxy吧:?

Java代碼?? 收藏代碼
  1. public ? int ?accept(Method?method)?{??
  2. ???????????? if ?(AopUtils.isFinalizeMethod(method))?{??
  3. ????????????????logger.debug( "Found?finalize()?method?-?using?NO_OVERRIDE" );??
  4. ???????????????? return ?NO_OVERRIDE;??
  5. ????????????}??
  6. ???????????? if ?(! this .advised.isOpaque()?&&?method.getDeclaringClass().isInterface()?&&??
  7. ????????????????????method.getDeclaringClass().isAssignableFrom(Advised. class ))?{??
  8. ???????????????? if ?(logger.isDebugEnabled())?{??
  9. ????????????????????logger.debug( "Method?is?declared?on?Advised?interface:?" ?+?method);??
  10. ????????????????}??
  11. ???????????????? return ?DISPATCH_ADVISED;??
  12. ????????????}??
  13. ???????????? //?We?must?always?proxy?equals,?to?direct?calls?to?this. ??
  14. ???????????? if ?(AopUtils.isEqualsMethod(method))?{??
  15. ????????????????logger.debug( "Found?'equals'?method:?" ?+?method);??
  16. ???????????????? return ?INVOKE_EQUALS;??
  17. ????????????}??
  18. ???????????? //?We?must?always?calculate?hashCode?based?on?the?proxy. ??
  19. ???????????? if ?(AopUtils.isHashCodeMethod(method))?{??
  20. ????????????????logger.debug( "Found?'hashCode'?method:?" ?+?method);??
  21. ???????????????? return ?INVOKE_HASHCODE;??
  22. ????????????}??
  23. ????????????Class?targetClass?=? this .advised.getTargetClass();??
  24. ???????????? //?Proxy?is?not?yet?available,?but?that?shouldn't?matter. ??
  25. ????????????List?chain?=? this .advised.getInterceptorsAndDynamicInterceptionAdvice(method,?targetClass);??
  26. ???????????? boolean ?haveAdvice?=?!chain.isEmpty();??
  27. ???????????? boolean ?exposeProxy?=? this .advised.isExposeProxy();??
  28. ???????????? boolean ?isStatic?=? this .advised.getTargetSource().isStatic();??
  29. ???????????? boolean ?isFrozen?=? this .advised.isFrozen();??
  30. ???????????? if ?(haveAdvice?||?!isFrozen)?{??
  31. ???????????????? //?If?exposing?the?proxy,?then?AOP_PROXY?must?be?used. ??
  32. ???????????????? if ?(exposeProxy)?{??
  33. ???????????????????? if ?(logger.isDebugEnabled())?{??
  34. ????????????????????????logger.debug( "Must?expose?proxy?on?advised?method:?" ?+?method);??
  35. ????????????????????}??
  36. ???????????????????? return ?AOP_PROXY;??
  37. ????????????????}??
  38. ????????????????String?key?=?method.toString();??
  39. ???????????????? //?Check?to?see?if?we?have?fixed?interceptor?to?serve?this?method. ??
  40. ???????????????? //?Else?use?the?AOP_PROXY. ??
  41. ???????????????? if ?(isStatic?&&?isFrozen?&&? this .fixedInterceptorMap.containsKey(key))?{??
  42. ???????????????????? if ?(logger.isDebugEnabled())?{??
  43. ????????????????????????logger.debug( "Method?has?advice?and?optimisations?are?enabled:?" ?+?method);??
  44. ????????????????????}??
  45. ???????????????????? //?We?know?that?we?are?optimising?so?we?can?use?the ??
  46. ???????????????????? //?FixedStaticChainInterceptors. ??
  47. ???????????????????? int ?index?=?((Integer)? this .fixedInterceptorMap.get(key)).intValue();??
  48. ???????????????????? return ?(index?+? this .fixedInterceptorOffset);??
  49. ????????????????}??
  50. ???????????????? else ?{??
  51. ???????????????????? if ?(logger.isDebugEnabled())?{??
  52. ????????????????????????logger.debug( "Unable?to?apply?any?optimisations?to?advised?method:?" ?+?method);??
  53. ????????????????????}??
  54. ???????????????????? return ?AOP_PROXY;??
  55. ????????????????}??
  56. ????????????}??
  57. ???????????? else ?{??
  58. ???????????????? //?See?if?the?return?type?of?the?method?is?outside?the?class?hierarchy ??
  59. ???????????????? //?of?the?target?type.?If?so?we?know?it?never?needs?to?have?return?type ??
  60. ???????????????? //?massage?and?can?use?a?dispatcher. ??
  61. ???????????????? //?If?the?proxy?is?being?exposed,?then?must?use?the?interceptor?the ??
  62. ???????????????? //?correct?one?is?already?configured.?If?the?target?is?not?static?cannot ??
  63. ???????????????? //?use?a?Dispatcher?because?the?target?can?not?then?be?released. ??
  64. ???????????????? if ?(exposeProxy?||?!isStatic)?{??
  65. ???????????????????? return ?INVOKE_TARGET;??
  66. ????????????????}??
  67. ????????????????Class?returnType?=?method.getReturnType();??
  68. ???????????????? if ?(targetClass?==?returnType)?{??
  69. ???????????????????? if ?(logger.isDebugEnabled())?{??
  70. ????????????????????????logger.debug( "Method?" ?+?method?+??
  71. ???????????????????????????????? "has?return?type?same?as?target?type?(may?return?this)?-?using?INVOKE_TARGET" );??
  72. ????????????????????}??
  73. ???????????????????? return ?INVOKE_TARGET;??
  74. ????????????????}??
  75. ???????????????? else ? if ?(returnType.isPrimitive()?||?!returnType.isAssignableFrom(targetClass))?{??
  76. ???????????????????? if ?(logger.isDebugEnabled())?{??
  77. ????????????????????????logger.debug( "Method?" ?+?method?+??
  78. ???????????????????????????????? "?has?return?type?that?ensures?this?cannot?be?returned-?using?DISPATCH_TARGET" );??
  79. ????????????????????}??
  80. ???????????????????? return ?DISPATCH_TARGET;??
  81. ????????????????}??
  82. ???????????????? else ?{??
  83. ???????????????????? if ?(logger.isDebugEnabled())?{??
  84. ????????????????????????logger.debug( "Method?" ?+?method?+??
  85. ???????????????????????????????? "has?return?type?that?is?assignable?from?the?target?type?(may?return?this)?-?" ?+??
  86. ???????????????????????????????? "using?INVOKE_TARGET" );??
  87. ????????????????????}??
  88. ???????????????????? return ?INVOKE_TARGET;??
  89. ????????????????}??
  90. ????????????}??
  91. ????????}??


List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); ?
即如果此方法有對應的advice就走代理。?

//getInterceptorsAndDynamicInterceptionAdvice代碼如下所示:?

Java代碼?? 收藏代碼
  1. public ?List?getInterceptorsAndDynamicInterceptionAdvice(Method?method,?Class?targetClass)?{??
  2. ????MethodCacheKey?cacheKey?=? new ?MethodCacheKey(method);??
  3. ????List?cached?=?(List)? this .methodCache.get(cacheKey);??
  4. ???? if ?(cached?==? null )?{??
  5. ????????cached?=? this .advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(??
  6. ???????????????? this ,?method,?targetClass);? //轉調DefaultAdvisorChainFactory ??
  7. ???????? this .methodCache.put(cacheKey,?cached);??
  8. ????}??
  9. ???? return ?cached;??
  10. }??



也就是說需要一次切入點的匹配,即如果方法有切入點就走代理方法 否則目標方法。?


再來看CglibMethodInvocation(cglib的 DynamicAdvisedInterceptor使用):?

引用

?

public Object proceed() throws Throwable {?
// We start with an index of -1 and increment early.?
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {?
return invokeJoinpoint();?
}?

Object interceptorOrInterceptionAdvice =?
??? this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);?
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {?
// Evaluate dynamic method matcher here: static part will already have?
// been evaluated and found to match.?
InterceptorAndDynamicMethodMatcher dm =?
??? (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;?
if (dm.methodMatcher.matches(this.method, this.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);?
}?
}?

???????????????? /**?
* Gives a marginal performance improvement versus using reflection to?
* invoke the target when invoking public methods.?
*/?
protected Object invokeJoinpoint() throws Throwable {?
if (this.protectedMethod) {?
return super.invokeJoinpoint();?
}?
else {?
return this.methodProxy.invoke(this.target, this.arguments);?
}?
}?
}?



即如果有InterceptorAndDynamicMethodMatcher 這是動態切入點切入點匹配器:?

引用spring文檔?

引用

?

7.2.4.2. 動態切入點?
動態切入點比起靜態切入點在執行時要消耗更多的資源。它們同時計算方法參數和靜態信息。 這意味著它們必須在每次方法調用時都被計算;由于參數的不同,結果不能被緩存。?
動態切入點的主要例子是控制流切入點。?


這個在spring aop中只有一種情況:PerTargetInstantiationModelPointcut 這個切入點;這個可以參考《 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3? 》 pertarget。?

也就是說如果是?
靜態切入點代理:如果有匹配的advice就走代理;?
動態切入點代理:需要在運行時進行匹配。?


綜上所述:?
execution(* *(..)) 可以匹配public/protected的,因為public的有匹配的了,目標類就代理了,,,再進行切入點匹配時也是能匹配的,而且cglib方式能拿到包級別/protected方法,而且包級別/protected方法可以直接通過反射調用。?


引用

?


對于上面這個帖子里,之所以protected方法能被無訪問修修飾符的execution攔截,是因為這個類里面其他public方法被execution匹配了,導致spring認為這個類可以被代理,而不是protected的方法本身被execution匹配?


這個是因為protected 修飾符的切入點 無法匹配 Method[] methods = clazz.getMethods(); 這里的任何一個,因此無法代理的。?

關于spring的aop攔截的問題 protected方法代理問題


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 九九网| 97影院手机版 | 成人爱爱爱欧美日本视频 | 免费一级成人毛片 | 久久女同互慰一区二区三区 | 国产99视频精品免视看9 | 国产99在线| 你懂得在线网站 | 伊人97在线| 国内毛片视频 | julia中文字幕在线 | 国产精品久久福利新婚之夜 | 亚洲免费观看 | 国产国语一级毛片中文 | 第四色奇米影视 | 中国在线播放精品区 | 亚洲精品一线观看 | 免费爽视频| 亚洲欧美网 | 亚洲欧美日韩在线观看你懂的 | 国产成人精品免费视频网页大全 | 四虎在线免费播放 | 成人在线视频观看 | 青青久久精品国产免费看 | 天天干天天舔天天射 | 美女色片 | 中文字幕欧美日韩在线不卡 | 一级毛片大全 | 欧美国产日韩在线 | 成人精品久久 | 手机看片国产免费 | 免费高清在线爱做视频 | 中国大陆一级毛片 免费 | 国产毛片视频网站 | 日本在线观看不卡 | xxxx日本在线播放免费不卡 | 中文字幕在线免费看 | 老妇激情毛片免费 | 免费在线一级毛片 | 久久综合图区亚洲综合图区 | 亚洲综合爱爱久久网 |