日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring源码学习之路---深入AOP(终)

發布時間:2025/4/14 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring源码学习之路---深入AOP(终) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? ? ? ? ? ?作者:zuoxiaolong8810(左瀟龍),轉載請注明出處,特別說明:本博文來自博主原博客,為保證新博客中博文的完整性,特復制到此留存,如需轉載請注明新博客地址即可。

? ? ? ? ? ??? ? 上一章和各位一起看了一下springAOP的工作流程,當我們給出AOP相關的配置以后,直接從IOC容器中拿出來的就是已經加強過的bean。這說明spring在這個過程中一定做了什么。

? ? ? ? ? ? ? ? 本章我們就一起來看一下spring是如何完成對bean的增強的,首先我們來看一下,FactoryBean接口中一個方法的定義。

public interface FactoryBean<T> {/*** Return an instance (possibly shared or independent) of the object* managed by this factory.* <p>As with a {@link BeanFactory}, this allows support for both the* Singleton and Prototype design pattern.* <p>If this FactoryBean is not fully initialized yet at the time of* the call (for example because it is involved in a circular reference),* throw a corresponding {@link FactoryBeanNotInitializedException}.* <p>As of Spring 2.0, FactoryBeans are allowed to return <code>null</code>* objects. The factory will consider this as normal value to be used; it* will not throw a FactoryBeanNotInitializedException in this case anymore.* FactoryBean implementations are encouraged to throw* FactoryBeanNotInitializedException themselves now, as appropriate.* @return an instance of the bean (can be <code>null</code>)* @throws Exception in case of creation errors* @see FactoryBeanNotInitializedException*/T getObject() throws Exception;

? ? ? ? ? ? ? ? ?getObject這個方法,就是用來獲取被這個factorybean加強后的對象的,上一章測試的過程中,最終就是調用了這個方法,來完成了對bean的加強。我們來跟蹤一下上一次測試的代碼,看看到底是在什么地方調用的。這里再次貼出來上次測試的代碼,方便解釋。

public class TestAOP {public static void main(String[] args) {ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");TestTarget target = (TestTarget) applicationContext.getBean("testAOP");target.test();System.out.println("------無敵分割線-----");target.test2();}}

其實整個過程也就兩行代碼,第一行代碼,是我們對IOC容器的初始化,這時其實并沒有發生對bean的增強,原因就是這個時候只是完成了對ProxyFactoryBean的初始化,也就是相當于我們已經new出來了一個ProxyFactoryBean,但是此時并沒有調用接口方法,去獲得加強后的bean。

? ? ? ? ?下面我們去跟進第二行獲取testAOP的代碼,來看一下究竟。首先我們會找到AbstractApplicationContext中的getBean方法,但是這個類并不負責bean的實例化工作,而是交給了bean工廠,我們跟蹤bean工廠的方法,能找到上述第二行其實是調用了如下這個方法。

@SuppressWarnings("unchecked")protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dependsOnBean : dependsOn) {getBean(dependsOnBean);registerDependentBean(dependsOnBean, beanName);}}// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory() {public Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName);throw ex;}}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, new ObjectFactory() {public Object getObject() throws BeansException {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; " +"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}// Check if required type matches the type of the actual bean instance.if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return (T) bean;}

這是一個重載方法,后面三個參數兩個為null,一個為false。下面注意,在這面這一行的時候,我們已經獲取到了實例。

Object sharedInstance = getSingleton(beanName);

? ? ? ? ? ? 所以分支在碰到第一個if判斷時,會直接進入if塊而不是else塊,在這里提醒一下,這個是獲取的單例的bean實例,而這個sharedInstance并不是TestTarget,而是ProxyFactoryBean的實例。好了,接下來相信你已經明白了,我們該進入getObjectForBeanInstance這個方法了,來看這個方法。

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {// Don't let calling code try to dereference the factory if the bean isn't a factory.if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());}// Now we have the bean instance, which may be a normal bean or a FactoryBean.// If it's a FactoryBean, we use it to create a bean instance, unless the// caller actually wants a reference to the factory.if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}Object object = null;if (mbd == null) {object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.FactoryBean factory = (FactoryBean) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;}

方法的剛開始是兩個衛語句,第一個判斷如果是想獲得factorybean本身,卻又不是factorybean則拋出異常,第二個則是正常的獲得factorybean。但是我們都不屬于這兩種情況。所以在經過getCachedObjectForFactoryBean獲取無果和getCachedObjectForFactoryBean獲取到bean定義以后,就進入了getObjectFromFactoryBean方法。

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {synchronized (getSingletonMutex()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}return (object != NULL_OBJECT ? object : null);}}else {return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);}}

進入以后,由于proxyFactorybean是單例bean,所以會進入到if塊不是else塊,接下來系統再次嘗試從cache中獲得,自然是無果。接下來依然會進入到和else一樣的方法doGetObjectFromFactoryBean,先不說這個方法,看后面,獲得以后就會放入cache,然后直接將對象返回。所以如果重復調用,下一次就會從cache當中取出來直接返回。好了,接下來我們進去doGetObjectFromFactoryBean方法。

private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName, final boolean shouldPostProcess)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {public Object run() throws Exception {return factory.getObject();}}, acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {object = factory.getObject();}}catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());}catch (Throwable ex) {throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);}// Do not accept a null value for a FactoryBean that's not fully// initialized yet: Many FactoryBeans just return null then.if (object == null && isSingletonCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");}if (object != null && shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);}}return object;}

此處判斷了一下當前是否設置了安全管理器,我們并沒有設置,所以將直接調用ProxyFactoryBean的getObject方法,也就是對bean增強的地方。下面我們著重來看一下是如何對bean進行增強的。首先我們進入到ProxyFactoryBean的getObject方法來看一下。

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

此處主要是先初始化了一下通知器鏈,然后就會根據是否單例做相應的動作,我們看一下初始化通知器鏈的進行。

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {if (this.advisorChainInitialized) {return;}if (!ObjectUtils.isEmpty(this.interceptorNames)) {if (this.beanFactory == null) {throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));}// Globals can't be last unless we specified a targetSource using the property...if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {throw new AopConfigException("Target required after globals");}// Materialize interceptor chain from bean names.for (String name : this.interceptorNames) {if (logger.isTraceEnabled()) {logger.trace("Configuring advisor or advice '" + name + "'");}if (name.endsWith(GLOBAL_SUFFIX)) {if (!(this.beanFactory instanceof ListableBeanFactory)) {throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");}addGlobalAdvisor((ListableBeanFactory) this.beanFactory,name.substring(0, name.length() - GLOBAL_SUFFIX.length()));}else {// If we get here, we need to add a named interceptor.// We must check if it's a singleton or prototype. Object advice;if (this.singleton || this.beanFactory.isSingleton(name)) {// Add the real Advisor/Advice to the chain.advice = this.beanFactory.getBean(name);}else {// It's a prototype Advice or Advisor: replace with a prototype.// Avoid unnecessary creation of prototype bean just for advisor chain initialization.advice = new PrototypePlaceholderAdvisor(name);}addAdvisorOnChainCreation(advice, name);}}}this.advisorChainInitialized = true;}

可以看到,其中針對我們配置的interpretorNames進行了循環,我們并非是配置的全局通知器,所以會進入else塊,然后因為我們配置的testAdvisor默認是單例的,所以會從bean工廠中去獲取這個實例,此時TestAdvisor已經實例化完成的,我們只是去取一下而已。然后就會進入addAdvisorOnChainCreation方法。這個方法不再一一貼進來,各位有興趣的可以自己去看一下,就是把通知器加到了通知鏈當中。

? ? ? ? ? ? ? 值得注意的是在這個過程中,觸發了一個這樣的方法this.advisorAdapterRegistry.wrap(next)。這個方法就是用來包裝通知器的,如果不是advisor而是advice,就會包裝一下返回。

? ? ? ? ? ? ? 好了,接著剛才的過程,初始化通知器鏈完成以后,就會進入getSingletonInstance方法,這是用來獲取單例實例的,而真正的加強也是在這里發生的,我們來看一下。

private synchronized Object getSingletonInstance() {if (this.singletonInstance == null) {this.targetSource = freshTargetSource();if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {// Rely on AOP infrastructure to tell us what interfaces to proxy.Class targetClass = getTargetClass();if (targetClass == null) {throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");}setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));}// Initialize the shared singleton instance.super.setFrozen(this.freezeProxy);this.singletonInstance = getProxy(createAopProxy());}return this.singletonInstance;}

此時第一次獲取,單例實例為null,所以會進入if塊,首先刷新targetSource,因為我們的Target類沒有實現targetSource接口,所以會由spring幫我們產生一個targetSource適配,這里是使用的適配器的模式,有興趣可以進去看一下,我們此處不關注這個。接下來,會去判斷代理接口,并且設置代理接口,但是我們的target未實現任何接口,所以此處interfaces仍然為空的,所以最后一步createAopProxy時,會幫我們創建cglib的proxy。最終由cglib生成代理返回。

執行下國際慣例,說完以后總要稍微總結一下,主要說幾點:

1.在IOC容器初始化的過程中,并沒有發生增強的動作,而是初始化了proxyFactoryBean。

2.如果配置中不指定,所有bean默認都是單例和非延遲加載的,也就是說所有的bean都將在第一次IOC容器初始化時全部實例化,所以上一章中所配置的三個bean都是在IOC容器初始化時進行的實例化。

3.springAOP代理有兩種方式,一種是JDK提供的動態代理,一種是cglib字節碼生成的技術,當要代理的類有實現的接口的時候,就會針對接口進行代理,否則就會采用cglib直接生成字節碼產生子類。

?

? ? ? ? ? ? ? 到此處,我們已經基本上完全跟了一遍整個bean增強的過程,也大概了解了springAOP的大概原理,相信各位心中應該有個大概的印象了,其實springAOP增強的原理已經浮現出來了,接下來再研究下去,可能會收獲甚微,還是要結合平時的應用和自己的興趣去體會,始終不贊同一頭扎進去就埋頭苦干的作風。

? ? ? ? ? ? ? 好了,spring源碼學習之路就圓滿結束了,雖說時間不長,但收獲甚大。各位如果有興趣,相信現在也完全有能力自己去看源碼了,以后有問題,不要找度娘了,找源碼吧。

?

?

?

?

?

轉載于:https://www.cnblogs.com/zuoxiaolong/p/spring7.html

總結

以上是生活随笔為你收集整理的spring源码学习之路---深入AOP(终)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。