Quellcode enthüllt! Das Prinzip der AOP-Programmierung im Frühling! (4) Fertigstellung

Machen Sie es sich zur Gewohnheit, gemeinsam zu schreiben! Dies ist der 10. Tag meiner Teilnahme an der „Nuggets Daily New Plan · April Update Challenge“, klicken Sie hier, um die Details der Veranstaltung anzuzeigen .

Source Code Revealing Series|Inhaltsverzeichnis

Quellcode enthüllt! Autowired Annotation von Spring IOC!
Quellcode enthüllt! Das Prinzip des Bean-Scannens in Spring! Quellcode enthüllt! Das Prinzip der
Spring- und Mybatis-Integration!
Quellcode enthüllt! Das Prinzip der AOP-Programmierung in Spring
! Das Prinzip der Programmierung Implementierung! (2) Der Quellcode des Registrierungsprozesses der Advice-Klasse wird
enthüllt! Das Prinzip der AOP-Programmierung in Spring! (3) Der Erstellungsprozess der Aspektklasse (1)

Vorwort

Im vorherigen Kapitel gibt die postProcessBeforeInstantiation-Methode nach Ausführung dieser Methode eine Null zurück. Da es sich um einen PostProcessor handelt, gibt es eine Before- und eine After-Methode.

Offiziell beginnen

Geben Sie hier die postProcessAfterInitialization-Methode ein, um einen Blick darauf zu werfen.

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
复制代码

An diesem Punkt wurde die Init-Methode der Bean ausgeführt, also wird zu diesem Zeitpunkt If eintreten. getCachekey gibt schließlich BeanName zurück.

Das Entfernen von cacheKey in der Eigenschaft „earlyProxyReferences“ erhält eine Null, sodass zu diesem Zeitpunkt auch das interne „If“ eingegeben und „warpIfNecessary“ aufgerufen wird. Was die Methode macht, weiß ich hier nicht, und dann nach unten schauen.

Interpretation der warpIfNecessary-Methode

Schauen wir uns zunächst die Parameter der Methode an.

Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
复制代码

Hier sind drei formale Parameter, sehen Sie den Namen und die Bedeutung, also werde ich nicht mehr erklären. Schauen Sie sich einfach das erste Stück Code an. Bild.pngNach der Eingabe können Sie mehrere If sehen, die Sie nacheinander analysieren können:
das erste IF

if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
   return bean;
}
复制代码

先是判断了Beanname,然后去targetsourcedBeans中判断是否有该值,按我说,我没讲过这个属性,应该是empty的。 Bild.png 断点查看一下,果然如此,所以继续下一个If

第二个IF

if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
   return bean;
}
复制代码

在这个If中,可以看到拿着cacheKey去advisedBeans中获取,然后和False比较。这里犹豫我们当前的Bean是被切入类,所以此时不在此容器中存在,所以不为空。

第三个IF

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}
复制代码

这个If和after中的代码一样,可以直接跳过,因为不会进入,此处返回false。

后续的代码逻辑

Bild.png 这里先简单阅读一下当前的代码,通过bean,拿到了切入点的一个集合。
随后判断切入点集合是否为空,不为Null进入代理逻辑。
随后像advisedBeans中打入一个标记,最后返回Bean。

此处阅读的重点有两个,一个是getAdvicesAndAdvisorsForBean方法,另外一个是createProxy方法。这里一个一个看

getAdvicesAndAdvisorsForBean 方法

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}
复制代码

这里的方法很简单,主要实现逻辑在findEligibleAdvisors方法中,接着往下追。 Bild.png 看到上方的代码块,有两个List,大致可以猜出是做什么用的。第一个List是获取当前Spring中的所有的切入点。第二个集合是经过过滤的,只有当前类的切入点的一个集合。

findCandidateAdvisors方法我们在before方法中,有涉足到,这里就不讲了,原理其实就是把Spring中的所有Bean遍历一遍,找出所有切入类,然后根据类再找出所有切入点。我们暂时先看一下第二个方法。

findAdvisorsThatCanApply

Bild.png 这里方法,明眼人都可以看出来,关键在于中间那行代码,其他的看方法就知道是往上下文中塞入一些东西,我们不管他,接着往下追。

Bild.png 这里先看第一段代码,在这个里面,遍历了candiadateAdvisors,在其中去判断是否instanceof于IntroductionAdvisor,我们这里的Advisor(切入点)都是InstantiationModelAwarePointcutAdvisorImpl,所以不继承自这个接口,此处不会走。

Bild.png 在这一段代码中,有一个成员变量,hasIntroductions,由于刚刚的eligibleAdvisors集合中并没有添加值,所以此时他是Empty的,取反即为false。
随后判断candidate是否继承自introductionAdvisor。此时不继承,接着判断,调用canApply方法,由此可见关键方法在于此方法中,我们接着往下追。

Bild.png 查看这里的代码比较简单,两个判断调用不同的方法,看到这里很明显,会进入第二个If中去,想一下我们刚刚提到的,我们Advisor的类型。InstantiationModelAwarePointcutAdvisorImpl,毋庸置疑会进入第二个。我们追进去查看。

Bild.png 进入方法后,我们引来第一个判断,通过pc获取到classFilter,然后matches当前要注册的Class。还记得Pc是什么吗,切入点。 Bild.png 这里通过Debug帮诸位回顾一下。这个If很明显就是根据表达式来判断当前类是否为切入类。不是的话直接放回false。我们这里接着往下看。

Bild.png 这个If,讲真的我没太看明白他是做什么的,不过可以大致看出来,是用来做方法匹配的。有一个行注释,这里要翻译一下

No need to iterate the methods if we're matching any method anyway...
如果我们仍然匹配任何方法,则无需迭代方法......

看这个翻译就明白是什么意思了。那我们接着往下看代码。

Bild.png 随后创建了个一个方法匹配器,想来是用来做迭代方法用的了。

Bild.png 到这里就知道了,最后是通过反射,获取到类中的所有方法,遍历Method对象,用方法匹配器去判断是否为有效的。最终一路返回true,回到FindAdvisorsThatCanApply方法。 Bild.png 最终加入到了eligibleAdvisors中,返回了回去。最终回到了warpIfNecessary方法中,我们接着往下看。

warpIfNecessary方法后续

Bild.png 接下来也就是正式的,创建代理的环节了。

由于我们这里刚刚拿到切入点集合,所以这里不为null,会进入If。想advisedBeans中打入了一个标记,这里的value有一点变化,是为True。
后续进入了CreateProxy方法。

createProxy方法解读

看方法前,先看方法的入参。此时方法进入,给定了四个参数。

  1. beanClass
  2. beanName
  3. specificInterceptors 切入点集合
  4. tagetSouce new了一个targetsource,把执行完init方法的Bean作为入参传了进去

Bild.png 方法一进入,迎面而来一个If,这个If是会进入的,因为我们一开始创建的工厂是DefaultListableBeanFactory看名字就是同类。但是里面做了什么讲真的,我不是没搞懂,在里面设置了一个attr > originalTargetClass,可能后面有用到吧,这里先跳过。

Bild.png 再看第二段代码,这里开头创建了一个proxyFacotry,也就是说,后面可能会使用这个代理工厂来创建代理对象。随后进入了一个If判断,我点进去查看后直接返回了false。所以进入else代码,此处调用了shouldProxyTargetClass方法。 Bild.png 这里代码追进去后,发现是与xml中的属性进行equals判断,很明显我没有设置该属性,返回false,这里也进入Else环节调用了evaluateProxyInterfaces方法。 Bild.png 最近去查看,发现就是普通的根据Class获取继承的接口,随后像ProxyFactory中添加了接口,这里猜测,这个接口后面要应用到创建Proxy对象中的。

Bild.png 在这一段代码中,根据传入进来切入点集合,又再次了build了切入点,随后给ProxyFactory放了一些配置。至于customerProxyFactory,点击进去看了,是个模板方法。

Bild.png 在这最后一段代码中,getProxy了,所以此时我们继续往里追。 Bild.png 看到这里,先去创建一个aopProxy。所以此时需要去看一下是如何创建的。往里追代码。 Bild.png 看到这里就明了了,为什么人们常说,AOP的实现方式有哪些,一种是CGLIB,一种是JDK了。这里有个点值得注意,看当前的方法写,是这样的。如果原来的class是接口,或者原来的class是代理class,再或者是lambda的话,就算配置了cglib他还是会用jdk的动态代理。

Bild.png 好的,我们回到这里,AopProxy已经创建完毕,接下来就getProxy了。

Bild.png 我们这里默认是JDK模式,看这个方法是直接调用JDK的实例化方法了。

Einige Leute mögen hier neugierig sein, wie er vor und nach der Hinrichtung von Bean eingegriffen hat. Das Prinzip ist eigentlich ganz einfach. Wenn die Methode zum Aufrufen einer Klasse durch Reflexion über die invoke-Methode erfolgt, beachten Sie hier, dass beim Aufrufen der newProxyInstance-Methode die dritte Methode ein this übergibt. Nachdem Sie darauf geklickt haben, stellt sich heraus, dass diese Methode eine Schnittstelle erfordert, also offensichtlich, Unser aktueller JdkDynamicAopProxy implementiert diese Schnittstelle, indem er sich eine Aufrufmethode in dieser Schnittstelle ansieht. Dann ist an dieser Stelle klar, dass wir die Aufrufmethode direkt lokalisieren.

Bild.pngDurch die Endkontrolle befindet sich der Code hier, und eine Reihe von Ketten werden durch die Zielklasse erhalten, die die Klasse des Agenten selbst ist. Das ist die Verantwortungskette. Kapseln Sie dann eine Reihe von Verantwortungsketten in der MethodInvocation-Klasse. Dann wird seine Methode "Process" aufgerufen, und wir verfolgen weiter. Bild.pngNachdem Sie hier gejagt haben, besteht eine hohe Wahrscheinlichkeit, dass es hier ist, und der Code des Einstiegspunkts wird hier ausgeführt.

Komm zu einem Ende

Dieser Artikel endet hier. Dies ist das AOP-Schlußkapitel. Ich weiß nicht, ob es Ihnen nach dem Lesen zugute kommen wird. Wenn Sie sich für den Registrierungsprozess auf der CGLib-Seite interessieren, können Sie versuchen, ihn selbst zu lesen.

Ich habe das gesehen, bitte gib einen Daumen nach oben und geh, Schatz~

Abschließende Bemerkungen

Das Verfassen von Artikeln dient der Festigung Ihres Wissens. Im Kommentarbereich können Sie auf Schlechtes oder Falsches hinweisen. Wenn Sie den Artikel lesen und denken, dass er für Sie hilfreich ist, können Sie ihm einen Daumen nach oben geben. Wenn Sie einige Fragen finden, die Zweifel haben, oder wenn Sie nicht verstehen, können Sie kommentieren und mich auf WeChat hinzufügen, und Sie müssen alles wissen. Natürlich hoffe ich auch, mich mit allen anzufreunden und voneinander zu lernen.

Ich denke du magst

Origin juejin.im/post/7085437712420831245
Empfohlen
Rangfolge