最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot源碼 TargetSource解析

 更新時間:2019年08月27日 08:22:27   作者:TheGir1  
這篇文章主要介紹了Springboot源碼 TargetSource解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

摘要:

其實我第一次看見這個東西的時候也是不解,代理目標源不就是一個class嘛還需要封裝干嘛。。。

其實proxy代理的不是target,而是TargetSource,這點非常重要,一定要分清楚?。。?/p>

通常情況下,一個代理對象只能代理一個target,每次方法調用的目標也是唯一固定的target。但是,如果讓proxy代理TargetSource,可以使得每次方法調用的target實例都不同(當然也可以相同,這取決于TargetSource實現)。這種機制使得方法調用變得靈活,可以擴展出很多高級功能,如:單利,原型,本地線程,目標對象池、運行時目標對象熱替換目標源等等。

Spring內置的TargetSource

SingletonTargetSource

 public class SingletonTargetSource implements TargetSource, Serializable {
 
 /** Target cached and invoked using reflection. */
 private final Object target;
 //省略無關代碼......
 @Override
 public Object getTarget() {
  return this.target;
 }
 //省略無關代碼......
 }

從這個目標源取得的目標對象是單例的,成員變量target緩存了目標對象,每次getTarget()都是返回這個對象。

PrototypeTargetSource

 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);
 }
 //省略無關代碼......
 }

每次getTarget()將生成prototype類型的bean,即其生成的bean并不是單例的,因而使用這個類型的TargetSource時需要注意,封裝的目標bean必須是prototype類型的。

PrototypeTargetSource繼承了AbstractBeanFactoryBasedTargetSource擁有了創(chuàng)建bean的能力。

 public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
 
 //省略無關代碼......
 /**
 * 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);
  }
  }
 }
 
 //省略無關代碼......
 
 }

可以看到,PrototypeTargetSource的生成prototype類型bean的方式主要是委托給BeanFactory進行的,因為BeanFactory自有一套生成prototype類型的bean的邏輯,因而PrototypeTargetSource也就具有生成prototype類型bean的能力,這也就是我們要生成的目標bean必須聲明為prototype類型的原因。

ThreadLocalTargetSource

 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<Object> targetInThread =
  new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'");
 
 /**
 * Set of managed targets, enabling us to keep track of the targets we've created.
 */
 private final Set<Object> targetSet = new HashSet<>();
 
 //省略無關代碼......
 /**
 * Implementation of abstract getTarget() method.
 * We look for a target held in a ThreadLocal. If we don't find one,
 * we create one and bind it to the thread. No synchronization is required.
 */
 @Override
 public Object getTarget() throws BeansException {
  ++this.invocationCount;
  Object target = this.targetInThread.get();
  if (target == null) {
  if (logger.isDebugEnabled()) {
  logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
   "creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
  }
  // Associate target with ThreadLocal.
  target = newPrototypeInstance();
  this.targetInThread.set(target);
  synchronized (this.targetSet) {
  this.targetSet.add(target);
  }
  }
  else {
  ++this.hitCount;
  }
  return target;
 }
 
 /**
 * Dispose of targets if necessary; clear ThreadLocal.
 * @see #destroyPrototypeInstance
 */
 @Override
 public void destroy() {
  logger.debug("Destroying ThreadLocalTargetSource bindings");
  synchronized (this.targetSet) {
  for (Object target : this.targetSet) {
  destroyPrototypeInstance(target);
  }
  this.targetSet.clear();
  }
  // Clear ThreadLocal, just in case.
  this.targetInThread.remove();
 }
 //省略無關代碼......
 }

ThreadLocalTargetSource也就是和線程綁定的TargetSource,可以理解,其底層實現必然使用的是ThreadLocal。既然使用了ThreadLocal,也就是說我們需要注意兩個問題:

目標對象必須聲明為prototype類型,因為每個線程都會持有一個不一樣的對象;
目標對象必須是無狀態(tài)的,因為目標對象是和當前線程綁定的,而Spring是使用的線程池處理的請求,因而每個線程可能處理不同的請求,因而為了避免造成問題,目標對象必須是無狀態(tài)的。

實現自定義的TargetSource

 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 {
 
 }
 }

實現自定義TargetSource主要有兩個點要注意,一個是getTarget()方法,該方法中需要實現獲取目標對象的邏輯,另一個是isStatic()方法,這個方法告知Spring是否需要緩存目標對象,在非單例的情況下一般是返回false。

小結

本文主要首先講解了Spring是如果在源碼層面支持TargetSource的,然后講解了TargetSource的使用原理,接著對Spring提供的常見`TargetSource`進行了講解,最后使用一個自定義的TargetSource講解了其使用方式。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 解決idea 拉取代碼出現的 “ Сannot Run Git Cannot identify version of git executable: no response“的問題

    解決idea 拉取代碼出現的 “ Сannot Run Git Cannot identify version of

    這篇文章主要介紹了解決idea 拉取代碼出現的 “ Сannot Run Git Cannot identify version of git executable: no response“的問題,需要的朋友可以參考下
    2020-08-08
  • Java列出2到100之間所有素數的方法

    Java列出2到100之間所有素數的方法

    這篇文章主要介紹了Java列出2到100之間所有素數的方法,涉及java數值運算的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • java使用字符畫一個海綿寶寶

    java使用字符畫一個海綿寶寶

    這篇文章主要為大家詳細介紹了java使用字符畫一個海綿寶寶,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Intellij IDEA實現SpringBoot項目多端口啟動的兩種方法

    Intellij IDEA實現SpringBoot項目多端口啟動的兩種方法

    有時候使用springboot項目時遇到這樣一種情況,用一個項目需要復制很多遍進行測試,除了端口號不同以外,沒有任何不同。遇到這種情況怎么辦呢?這時候可以使用Intellij IDEA解決
    2018-06-06
  • Springboot使用thymeleaf動態(tài)模板實現刷新

    Springboot使用thymeleaf動態(tài)模板實現刷新

    這篇文章主要介紹了Springboot使用thymeleaf動態(tài)模板實現刷新,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • Java 根據url下載網絡資源

    Java 根據url下載網絡資源

    這篇文章主要介紹了Java 根據url下載網絡資源的示例代碼,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-11-11
  • SpringBoot自動裝配原理解析

    SpringBoot自動裝配原理解析

    Spring Boot自動裝配是指在Spring Boot應用啟動時,根據類路徑下的jar包依賴、Bean定義、各種配置文件等信息,自動配置Spring應用上下文的Bean,本文給大家詳細解析了SpringBoot自動裝配原理,需要的朋友可以參考下
    2024-11-11
  • SpringBoot整合Mybatis-Plus分頁失效的解決

    SpringBoot整合Mybatis-Plus分頁失效的解決

    本文主要介紹了SpringBoot整合Mybatis-Plus分頁失效的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • SpringBoot+Kotlin中使用GRPC實現服務通信的示例代碼

    SpringBoot+Kotlin中使用GRPC實現服務通信的示例代碼

    本文主要介紹了SpringBoot+Kotlin中使用GRPC實現服務通信的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • 基于@AllArgsConstructor與@Value共用的問題解決

    基于@AllArgsConstructor與@Value共用的問題解決

    這篇文章主要介紹了基于@AllArgsConstructor與@Value共用的問題解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評論

手游| 岑溪市| 娱乐| 徐水县| 金门县| 成安县| 营山县| 乌鲁木齐市| 两当县| 金寨县| 彰武县| 东乡| 宜君县| 鹿泉市| 眉山市| 开化县| 汪清县| 铅山县| 宜春市| 新邵县| 兴安县| 永春县| 金寨县| 台东市| 邹平县| 桂林市| 莆田市| 竹山县| 称多县| 汤原县| 天水市| 丹棱县| 嘉禾县| 黄龙县| 绥芬河市| 沂源县| 高密市| 清水河县| 琼海市| 宜宾市| 莒南县|