重慶分公司,新征程啟航
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊(cè)、服務(wù)器等服務(wù)
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊(cè)、服務(wù)器等服務(wù)
這篇文章將為大家詳細(xì)講解有關(guān)Springboot中TargetSource的作用是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
在柯橋等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需制作網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷推廣,成都外貿(mào)網(wǎng)站制作,柯橋網(wǎng)站建設(shè)費(fèi)用合理。
其實(shí)proxy
代理的不是target
,而是TargetSource
,這點(diǎn)非常重要,一定要分清楚!!!
通常情況下,一個(gè)代理對(duì)象只能代理一個(gè)target,每次方法調(diào)用的目標(biāo)也是唯一固定的target。但是,如果讓proxy代理TargetSource,可以使得每次方法調(diào)用的target實(shí)例都不同(當(dāng)然也可以相同,這取決于TargetSource實(shí)現(xiàn))。這種機(jī)制使得方法調(diào)用變得靈活,可以擴(kuò)展出很多高級(jí)功能,如:單利,原型,本地線程,目標(biāo)對(duì)象池、運(yùn)行時(shí)目標(biāo)對(duì)象熱替換目標(biāo)源等等。
public class SingletonTargetSource implements TargetSource, Serializable { /** Target cached and invoked using reflection. */ private final Object target; //省略無(wú)關(guān)代碼...... @Override public Object getTarget() { return this.target; } //省略無(wú)關(guān)代碼...... }
從這個(gè)目標(biāo)源取得的目標(biāo)對(duì)象是單例的,成員變量target緩存了目標(biāo)對(duì)象,每次getTarget()
都是返回這個(gè)對(duì)象。
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource { /** * Obtain a new prototype instance for every call. * @see #newPrototypeInstance() */ @Override public Object getTarget() throws BeansException { return newPrototypeInstance(); } /** * Destroy the given independent instance. * @see #destroyPrototypeInstance */ @Override public void releaseTarget(Object target) { destroyPrototypeInstance(target); } //省略無(wú)關(guān)代碼...... }
每次getTarget()
將生成prototype
類型的bean,即其生成的bean并不是單例的,因而使用這個(gè)類型的TargetSource
時(shí)需要注意,封裝的目標(biāo)bean必須是prototype類型的。PrototypeTargetSource
繼承了AbstractBeanFactoryBasedTargetSource
擁有了創(chuàng)建bean的能力。
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource { //省略無(wú)關(guān)代碼...... /** * Subclasses should call this method to create a new prototype instance. * @throws BeansException if bean creation failed */ protected Object newPrototypeInstance() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'"); } return getBeanFactory().getBean(getTargetBeanName()); } /** * Subclasses should call this method to destroy an obsolete prototype instance. * @param target the bean instance to destroy */ protected void destroyPrototypeInstance(Object target) { if (logger.isDebugEnabled()) { logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'"); } if (getBeanFactory() instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target); } else if (target instanceof DisposableBean) { try { ((DisposableBean) target).destroy(); } catch (Throwable ex) { logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex); } } } //省略無(wú)關(guān)代碼...... }
可以看到,PrototypeTargetSource
的生成prototype類型bean的方式主要是委托給BeanFactory
進(jìn)行的,因?yàn)锽eanFactory自有一套生成prototype類型的bean的邏輯,因而PrototypeTargetSource
也就具有生成prototype類型bean的能力,這也就是我們要生成的目標(biāo)bean必須聲明為prototype類型的原因。
public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource implements ThreadLocalTargetSourceStats, DisposableBean { /** * ThreadLocal holding the target associated with the current * thread. Unlike most ThreadLocals, which are static, this variable * is meant to be per thread per instance of the ThreadLocalTargetSource class. */ private final ThreadLocal
ThreadLocalTargetSource
也就是和線程綁定的TargetSource
,可以理解,其底層實(shí)現(xiàn)必然使用的是ThreadLocal。既然使用了ThreadLocal
,也就是說(shuō)我們需要注意兩個(gè)問(wèn)題:
目標(biāo)對(duì)象必須聲明為prototype類型,因?yàn)槊總€(gè)線程都會(huì)持有一個(gè)不一樣的對(duì)象;
目標(biāo)對(duì)象必須是無(wú)狀態(tài)的,因?yàn)槟繕?biāo)對(duì)象是和當(dāng)前線程綁定的,而Spring是使用的線程池處理的請(qǐng)求,因而每個(gè)線程可能處理不同的請(qǐng)求,因而為了避免造成問(wèn)題,目標(biāo)對(duì)象必須是無(wú)狀態(tài)的。
package com.github.dqqzj.springboot.target; import org.springframework.aop.TargetSource; import org.springframework.util.Assert; import java.lang.reflect.Array; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; /** * @author qinzhongjian * @date created in 2019-08-25 12:43 * @description: TODO * @since JDK 1.8.0_212-b10z */ public class DqqzjTargetSource implements TargetSource { private final AtomicInteger idx = new AtomicInteger(); private final Object[] target;; public DqqzjTargetSource(Object[] target) { Assert.notNull(target, "Target object must not be null"); this.target = target; } @Override public Class> getTargetClass() { return target.getClass(); } @Override public boolean isStatic() { return false; } @Override public Object getTarget() throws Exception { return this.target[this.idx.getAndIncrement() & this.target.length - 1]; } @Override public void releaseTarget(Object target) throws Exception { } }
實(shí)現(xiàn)自定義TargetSource主要有兩個(gè)點(diǎn)要注意,一個(gè)是getTarget()
方法,該方法中需要實(shí)現(xiàn)獲取目標(biāo)對(duì)象的邏輯,另一個(gè)是isStatic()
方法,這個(gè)方法告知Spring是否需要緩存目標(biāo)對(duì)象,在非單例的情況下一般是返回false
。
關(guān)于Springboot中TargetSource的作用是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。