欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java動(dòng)態(tài)獲取實(shí)現(xiàn)類(lèi)的方式詳解

 更新時(shí)間:2024年01月04日 11:08:47   作者:Java個(gè)體戶  
這篇文章主要介紹了Java動(dòng)態(tài)獲取實(shí)現(xiàn)類(lèi)的方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧

應(yīng)用場(chǎng)景

支付的時(shí)候,有不同的渠道,比如微信還是支付寶?

這個(gè)時(shí)候,就需要根據(jù)渠道類(lèi)型,選擇走哪個(gè)渠道。

先來(lái)看下讀

/**
 * 根據(jù)接口和注解@SupportCodes的值,獲取接口實(shí)現(xiàn)類(lèi)
 *
 * @param interfaceClass 接口
 * @param sopportCode 接口實(shí)現(xiàn)類(lèi)的注解@SupportCodes的值
 * @return 接口實(shí)現(xiàn)類(lèi)
 */
public static <T> T getServiceImpl(Class<T> interfaceClass, String sopportCode)
{
  // 如果沒(méi)有初始化,則初始化
  if (null == serviceImplFactoryMap.get(interfaceClass)) {
    // 初始化
    init(interfaceClass);
    if (null == serviceImplFactoryMap) {
      return null;
    }
  }
  // 如果初始化后,還是沒(méi)有,則返回null
  if (null == serviceImplFactoryMap.get(interfaceClass)) {
    return null;
  }
  // 返回接口實(shí)現(xiàn)類(lèi)
  return (T)((Map)serviceImplFactoryMap.get(interfaceClass)).get(sopportCode);
}

為什么要先看讀?讀是需求,因?yàn)橛凶x的需求,才需要實(shí)現(xiàn)寫(xiě)的功能。

重點(diǎn)來(lái)看入?yún)?,任何功能,無(wú)非是入?yún)⒑统鰠ⅰ?/p>

入?yún)ⅲ航涌诤颓来a。
出參:渠道實(shí)現(xiàn)類(lèi)。

那具體怎么實(shí)現(xiàn)呢?

類(lèi)似這種需求,基本上都是map。key是渠道代碼,value實(shí)現(xiàn)類(lèi)。

大概的實(shí)現(xiàn)思路,基本上就是這樣。存儲(chǔ)用到的數(shù)據(jù)結(jié)構(gòu)是map。

寫(xiě)

剛才看了讀方法,再來(lái)看下寫(xiě)。

讀,無(wú)非是從map讀。寫(xiě),也一樣,無(wú)非是把數(shù)據(jù)寫(xiě)到map。

那具體怎么寫(xiě)呢?直接看代碼

/**
 * 初始化
 *
 * @param interfaceClass 接口
 * @author javaself
 */
protected static <T> void init(Class<T> interfaceClass) {
  log.info("begin to init " + interfaceClass);
  synchronized (FactoryUtil.class) {
    try {
      // 如果已經(jīng)初始化,則返回
      if (null != serviceImplFactoryMap.get(interfaceClass)) {
        return;
      }
      
      Map<String, Object> serviceMap = new HashMap();
      // 獲取所有實(shí)現(xiàn)類(lèi)
      Map<String, T> beans = appContext.getBeansOfType(interfaceClass); //實(shí)現(xiàn)類(lèi)名字作為key,實(shí)現(xiàn)類(lèi)實(shí)例作為value
      Set<Entry<String, T>> entrySet = beans.entrySet();
      Iterator<Entry<String, T>> iterator = entrySet.iterator();
      // 遍歷所有實(shí)現(xiàn)類(lèi),獲取注解@SupportCodes的值,作為key,實(shí)現(xiàn)類(lèi)實(shí)例作為value
      while (iterator.hasNext()) {
        Object interfaceServiceImpl = ((Entry)iterator.next()).getValue();
        SupportCodes annotationValue = (SupportCodes)interfaceServiceImpl.getClass().getAnnotation(SupportCodes.class);
        if (null != annotationValue) {
          for (String flag : annotationValue.value()) { //可能有多個(gè)注解值,所以遍歷
            //寫(xiě)到map: key=注解值,value=實(shí)現(xiàn)類(lèi)實(shí)例
            serviceMap.put(flag, interfaceServiceImpl); 
            log.info(flag + "=>" + interfaceServiceImpl.getClass());
          }
        }
      }
      
      //寫(xiě)到map: key=接口,value=上面的map
      serviceImplFactoryMap.put(interfaceClass, serviceMap);
    } catch (Exception e) {
      log.error("init failed", e);
      throw new RuntimeException(e);
    }
  }
  log.info(interfaceClass + "inited");
}

寫(xiě)方法的入?yún)⑹牵航涌凇?/p>

也就是說(shuō),根據(jù)接口,可以獲取不同實(shí)現(xiàn)類(lèi)。具體是基于spring的獲取bean的功能。

拿到不同實(shí)現(xiàn)類(lèi)之后,再根據(jù)注解代碼,組裝成key/value寫(xiě)到map。key是注解代碼,value是實(shí)現(xiàn)類(lèi)。

注解代碼是干嘛用的?就是前面的渠道代碼。屬于業(yè)務(wù)代碼。具體是基于自定義注解實(shí)現(xiàn)。自定義注解用的時(shí)候,有幾步,首先,是自定義注解,其次,注解到類(lèi)上面去,最后,讀注解的值的時(shí)候直接使用spring提供的工具類(lèi)即可。

到這里其實(shí)基本上已經(jīng)寫(xiě)完了,核心思路就是怎么玩弄渠道代碼和渠道實(shí)現(xiàn)類(lèi)。

何時(shí)寫(xiě)?

讀的時(shí)候,寫(xiě)。也就是說(shuō),第一次用到的時(shí)候,寫(xiě)。而不是啟動(dòng)項(xiàng)目的時(shí)候,寫(xiě)。

只需要寫(xiě)一次即可,也就是說(shuō),只在第一次用到的時(shí)候,才寫(xiě)。后面直接用即可。

寫(xiě)的時(shí)候,注意并發(fā)問(wèn)題。類(lèi)似這種只寫(xiě)一次,但是又需要注意并發(fā)問(wèn)題的情況,一般直接使用同步關(guān)鍵字即可。

何時(shí)讀?

支付系統(tǒng)里面根據(jù)接口和渠道代碼,決定走哪個(gè)渠道實(shí)現(xiàn)類(lèi)

IGetPayInstructionService payService = FactoryUtil.getServiceImpl(IGetPayInstructionService.class, channelCode);

渠道代碼的值,從哪里來(lái)?網(wǎng)關(guān)入口會(huì)判斷。具體的話,用微信還是支付寶掃碼的時(shí)候,可以根據(jù)請(qǐng)求頭判斷是哪個(gè)app。

完整代碼

工具類(lèi)

package com.xxx.commons.factory;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.stereotype.Component;

/**
 * 工廠工具類(lèi):用于獲取接口實(shí)現(xiàn)類(lèi)
 *
 * ---
 * 應(yīng)用場(chǎng)景:當(dāng)一個(gè)接口有多個(gè)實(shí)現(xiàn)類(lèi)時(shí),通過(guò)該工具類(lèi)獲取對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)。
 * 不同實(shí)現(xiàn)類(lèi),通過(guò)注解@SupportCodes來(lái)區(qū)分。獲取的時(shí)候,也是通過(guò)@SupportCodes的值來(lái)獲取。
 *
 * ---
 * 舉例說(shuō)明
 *
 * 不同渠道的支付接口,都實(shí)現(xiàn)了IPayService接口,如下:微信支付、支付寶支付
 *
 * @author javaself
 */
@Component
public class FactoryUtil
  implements ApplicationContextAware
{
  private static Log log = LogFactory.getLog(FactoryUtil.class);
  private static Map<Class<?>, Map<String, Object>> serviceImplFactoryMap = new HashMap();
  private static AbstractApplicationContext appContext;

  /**
   * 根據(jù)接口和注解@SupportCodes的值,獲取接口實(shí)現(xiàn)類(lèi)
   *
   * @param interfaceClass 接口
   * @param sopportCode 接口實(shí)現(xiàn)類(lèi)的注解@SupportCodes的值
   * @return 接口實(shí)現(xiàn)類(lèi)
   */
  public static <T> T getServiceImpl(Class<T> interfaceClass, String sopportCode)
  {
    // 如果沒(méi)有初始化,則初始化
    if (null == serviceImplFactoryMap.get(interfaceClass)) {
      // 初始化
      init(interfaceClass);
      if (null == serviceImplFactoryMap) {
        return null;
      }
    }
    // 如果初始化后,還是沒(méi)有,則返回null
    if (null == serviceImplFactoryMap.get(interfaceClass)) {
      return null;
    }
    // 返回接口實(shí)現(xiàn)類(lèi)
    return (T)((Map)serviceImplFactoryMap.get(interfaceClass)).get(sopportCode);
  }

  /**
   * 初始化
   *
   * @param interfaceClass 接口
   * @author javaself
   */
  protected static <T> void init(Class<T> interfaceClass) {
    log.info("begin to init " + interfaceClass);
    synchronized (FactoryUtil.class) {
      try {
        // 如果已經(jīng)初始化,則返回
        if (null != serviceImplFactoryMap.get(interfaceClass)) {
          return;
        }

        Map<String, Object> serviceMap = new HashMap();
        // 獲取所有實(shí)現(xiàn)類(lèi)
        Map<String, T> beans = appContext.getBeansOfType(interfaceClass); //實(shí)現(xiàn)類(lèi)名字作為key,實(shí)現(xiàn)類(lèi)實(shí)例作為value
        Set<Entry<String, T>> entrySet = beans.entrySet();
        Iterator<Entry<String, T>> iterator = entrySet.iterator();
        // 遍歷所有實(shí)現(xiàn)類(lèi),獲取注解@SupportCodes的值,作為key,實(shí)現(xiàn)類(lèi)實(shí)例作為value
        while (iterator.hasNext()) {
          Object interfaceServiceImpl = ((Entry)iterator.next()).getValue();
          SupportCodes annotationValue = (SupportCodes)interfaceServiceImpl.getClass().getAnnotation(SupportCodes.class);
          if (null != annotationValue) {
            for (String flag : annotationValue.value()) { //可能有多個(gè)注解值,所以遍歷
              //寫(xiě)到map: key=注解值,value=實(shí)現(xiàn)類(lèi)實(shí)例
              serviceMap.put(flag, interfaceServiceImpl);
              log.info(flag + "=>" + interfaceServiceImpl.getClass());
            }
          }
        }

        //寫(xiě)到map: key=接口,value=上面的map
        serviceImplFactoryMap.put(interfaceClass, serviceMap);
      } catch (Exception e) {
        log.error("init failed", e);
        throw new RuntimeException(e);
      }
    }
    log.info(interfaceClass + "inited");
  }
  
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
  {
    appContext = (AbstractApplicationContext)applicationContext;
  }
}

注解類(lèi)

package com.xxx.commons.factory;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportCodes
{
  String[] value();
}

接口實(shí)現(xiàn)類(lèi)

/**
 * 微信公眾號(hào)支付
 * 
 */
@SupportCodes("WeChatPay")
@Service
public class WeChatPayService implements IGetPayInstructionService {

以上就是Java動(dòng)態(tài)獲取實(shí)現(xiàn)類(lèi)的方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Java動(dòng)態(tài)獲取實(shí)現(xiàn)類(lèi)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java類(lèi)加載器和類(lèi)加載機(jī)制實(shí)例分析

    Java類(lèi)加載器和類(lèi)加載機(jī)制實(shí)例分析

    這篇文章主要介紹了Java類(lèi)加載器和類(lèi)加載機(jī)制,結(jié)合實(shí)例形式分析了java類(lèi)加載器與類(lèi)加載機(jī)制原理、實(shí)現(xiàn)方法及相關(guān)操作技巧,需要的朋友可以參考下
    2019-07-07
  • Mockito 結(jié)合 Springboot 進(jìn)行應(yīng)用測(cè)試的方法詳解

    Mockito 結(jié)合 Springboot 進(jìn)行應(yīng)用測(cè)試的方法詳解

    這篇文章主要介紹了Mockito 結(jié)合 Springboot 進(jìn)行應(yīng)用測(cè)試的方法詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • java基于反射得到對(duì)象屬性值的方法

    java基于反射得到對(duì)象屬性值的方法

    這篇文章主要介紹了java基于反射得到對(duì)象屬性值的方法,結(jié)合實(shí)例形式分析了java基于反射獲取對(duì)象屬性值的相關(guān)實(shí)現(xiàn)方法與操作技巧,需要的朋友可以參考下
    2017-03-03
  • idea2022創(chuàng)建javaweb項(xiàng)目步驟(超詳細(xì))

    idea2022創(chuàng)建javaweb項(xiàng)目步驟(超詳細(xì))

    本文主要介紹了idea2022創(chuàng)建javaweb項(xiàng)目步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • idea springboot遠(yuǎn)程debug的操作方法

    idea springboot遠(yuǎn)程debug的操作方法

    這篇文章主要介紹了idea springboot遠(yuǎn)程debug的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 四個(gè)實(shí)例超詳細(xì)講解Java?貪心和枚舉的特點(diǎn)與使用

    四個(gè)實(shí)例超詳細(xì)講解Java?貪心和枚舉的特點(diǎn)與使用

    貪心算法是指,在對(duì)問(wèn)題求解時(shí),總是做出在當(dāng)前看來(lái)是最好的選擇。也就是說(shuō),不從整體最優(yōu)上加以考慮,他所做出的是在某種意義上的局部最優(yōu)解,枚舉法的本質(zhì)就是從所有候選答案中去搜索正確的解,枚舉算法簡(jiǎn)單粗暴,他暴力的枚舉所有可能,盡可能地嘗試所有的方法
    2022-04-04
  • Java多線程之原子類(lèi)解析

    Java多線程之原子類(lèi)解析

    這篇文章主要介紹了Java多線程之原子類(lèi)解析,Java原子類(lèi)是一種多線程編程中常用的工具,用于實(shí)現(xiàn)線程安全的操作,它們提供了一種原子性操作的機(jī)制,確保多個(gè)線程同時(shí)訪問(wèn)共享變量時(shí)的數(shù)據(jù)一致性,需要的朋友可以參考下
    2023-10-10
  • JavaSE-面向?qū)ο?方法重寫(xiě))

    JavaSE-面向?qū)ο?方法重寫(xiě))

    子類(lèi)在調(diào)用父類(lèi)的私有方法中不能直接調(diào)用,但是可以通過(guò)get方法進(jìn)行調(diào)用,修改屬性的值可以通過(guò)set方法進(jìn)行修改。而子類(lèi)想要修改父類(lèi)中的方法可以使用方法重寫(xiě)進(jìn)行操作。
    2021-08-08
  • 詳解SpringBoot?Start組件開(kāi)發(fā)之記錄接口日志信息

    詳解SpringBoot?Start組件開(kāi)發(fā)之記錄接口日志信息

    這篇文章主要為大家介紹了SpringBoot-Start組件開(kāi)發(fā)之記錄接口日志信息詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Spring?Boot中的max-http-header-size配置方式

    Spring?Boot中的max-http-header-size配置方式

    這篇文章主要介紹了Spring?Boot中的max-http-header-size配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評(píng)論