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

Spring?cloud負(fù)載均衡@LoadBalanced?&?LoadBalancerClient

 更新時(shí)間:2023年11月16日 11:34:29   作者:福  
由于Spring?cloud2020之后移除了Ribbon,直接使用Spring?Cloud?LoadBalancer作為客戶端負(fù)載均衡組件,我們討論Spring負(fù)載均衡以Spring?Cloud2020之后版本為主,學(xué)習(xí)Spring?Cloud?LoadBalance

LoadBalance vs Ribbon

由于Spring cloud2020之后移除了Ribbon,直接使用Spring Cloud LoadBalancer作為客戶端負(fù)載均衡組件,我們討論Spring負(fù)載均衡以Spring Cloud2020之后版本為主,學(xué)習(xí)Spring Cloud LoadBalance,暫不討論Ribbon。

兩者有什么區(qū)別、Spring Cloud為什么移除了Ribbon轉(zhuǎn)向了Spring Cloud LoadBalancer,改日研究。

回顧

上篇文章我們學(xué)習(xí)了Spring Cloud LoadBalance負(fù)載均衡底層原理中的:

@LoadBalanced注解的使用:與@Bean一起作用在RestTemplate上:

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

可以實(shí)現(xiàn):在注入RestTemplate對(duì)象到Spring IoC容器的同時(shí),啟用Spring的負(fù)載均衡機(jī)制。

  • @LoadBalanced注解的底層原理:在LoadBalancerAutoConfiguration初始化的過(guò)程中,創(chuàng)建攔截器LoadBalancerInterceptor,對(duì)請(qǐng)求進(jìn)行攔截從而實(shí)現(xiàn)負(fù)載均衡。
  • LoadBalancerInterceptor攔截器在執(zhí)行請(qǐng)求前調(diào)用其intercept方法,intercept負(fù)責(zé)負(fù)載均衡的實(shí)現(xiàn)(具體的實(shí)現(xiàn)邏輯尚未研究)

其中第3點(diǎn),intercept方法是怎么實(shí)現(xiàn)負(fù)載均衡的,我們還沒有深入研究,這是我們今天這篇文章的主要目的。

Spring Cloud負(fù)載均衡原理

LoadBalancerClient及ReactorLoadBalancer初始化

LoadBalancerInterceptor攔截器的intercept方法究竟是怎么實(shí)現(xiàn)負(fù)載均衡的?

攔截方法intercept中會(huì)通過(guò)LoadBalancerClient對(duì)象(從Spring IoC容器中獲?。?shí)現(xiàn)負(fù)載均衡,LoadBalancerClient對(duì)象的注入以及攔截原理這個(gè)過(guò)程稍微復(fù)雜一點(diǎn),所以我們先用簡(jiǎn)單的方式描述其實(shí)現(xiàn)邏輯,然后再?gòu)脑创a角度進(jìn)行跟蹤。

我們?cè)谏弦黄恼轮姓f(shuō)過(guò)的spring-cloud-commons包下的自動(dòng)配置類(如圖):

比如對(duì)@LoadBalanced注解的解析、LoadBalancerInterceptor的注入等等,就是上面自動(dòng)配置類LoadBalancerAutoConfiguration完成的。

Spring cloud有兩個(gè)名字一樣的自動(dòng)配置類LoadBalancerAutoConfiguration,位于不同的包下,上面一個(gè)是在spring-cloud-commes包下,下面還要提到的一個(gè)是在spring-cloud-loadbalancer包下。

spring-cloud-loadbalancer包下的自動(dòng)配置類LoadBalancerAutoConfiguration負(fù)責(zé)注入LoadBalancerClientFactory對(duì)象,LoadBalancerClientFactory負(fù)責(zé)創(chuàng)建子容器(SpringCloud通過(guò)子容器來(lái)隔離各微服務(wù)的訪問參數(shù)、負(fù)載均衡策略等)。創(chuàng)建LoadBalancerClientFactory對(duì)象的過(guò)程中將LoadBalancerClientConfiguration設(shè)置給他的defaultConfigType屬性,在子容器初始化的過(guò)程中將LoadBalancerClientConfiguration注冊(cè)為配置類,從而通過(guò)LoadBalancerClientConfiguration配置類完成ReactorLoadBalancer的創(chuàng)建并注入子容器中。ReactorLoadBalancer是負(fù)載均衡策略接口,默認(rèn)的負(fù)載均衡策略為RoundRobinLoadBalancer。

spring-cloud-loadbalancer包下的另外一個(gè)自動(dòng)配置類BlockingLoadBalancerClientAutoConfiguration負(fù)責(zé)注入攔截器中的LoadBalancerClient,實(shí)際注入的是BlockingLoadBalancerClient對(duì)象,BlockingLoadBalancerClient會(huì)持有LoadBalancerClientFactory對(duì)象。

LoadBalancerInterceptor的intercept方法會(huì)轉(zhuǎn)交給BlockingLoadBalancerClient處理,BlockingLoadBalancerClient通過(guò)LoadBalancerClientFactory對(duì)象向子容器(子容器不存在的話首先創(chuàng)建子容器)獲取相關(guān)配置以及負(fù)載均衡策略RoundRobinLoadBalancer,最終通過(guò)RoundRobinLoadBalancer實(shí)現(xiàn)負(fù)載均衡。

需要注意,子容器不是在系統(tǒng)初始化過(guò)程中創(chuàng)建的,而是在處理請(qǐng)求的過(guò)程中創(chuàng)建的。

下面分析源碼。

LoadBalancerClient

從應(yīng)用層入手分析,先看上一篇文章的案例中的orderServicede的代碼:

@Service
public class OrderService {
    @Autowired
    private RestTemplate restTemplate;
    public String getOrder(){
        //通過(guò)userService獲取user信息
        String url="http://userservice/user/getUser";
        System.out.println("url"+url);
        User user=restTemplate.getForObject(url,User.class);
        System.out.println(user);
        return user.getName();
    }
}

restTemplate.getForObject最終會(huì)調(diào)用到LoadBalancerInterceptor的intercept方法:

private LoadBalancerClient loadBalancer;
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        final URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        return this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

調(diào)用loadBalancer的execute方法,而loadBalancer是LoadBalancerClient 對(duì)象、是LoadBalancerInterceptor初始化過(guò)程中通過(guò)方法參數(shù)從SpringIoC容器中注入進(jìn)來(lái)的。

前面提到過(guò),自動(dòng)配置類BlockingLoadBalancerClientAutoConfiguration負(fù)責(zé)注入攔截器中的LoadBalancerClient,實(shí)際注入的是BlockingLoadBalancerClient對(duì)象。為了不影響可讀性,我們稍后再看這部分源碼。

繼續(xù)跟蹤loadBalancer的execute方法。首先看一下LoadBalancerClient 的類結(jié)構(gòu);

接口LoadBalancerClient繼承自接口ServiceInstanceChooser,接口定義了choose方法及execute方法(包括其重載方法)。其中execute是調(diào)用入口、也是模板方法:根據(jù)請(qǐng)求的服務(wù)serviceId(比如userService)通過(guò)調(diào)用choose方法獲取到最終要調(diào)用的服務(wù)實(shí)例serviceInstance,最終調(diào)用到服務(wù)實(shí)例所提供的服務(wù):

@Override
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        String hint = getHint(serviceId);
        LoadBalancerRequestAdapter<T, TimedRequestContext> lbRequest = new LoadBalancerRequestAdapter<>(request,
                buildRequestContext(request, hint));
        Set<LoadBalancerLifecycle> supportedLifecycleProcessors = getSupportedLifecycleProcessors(serviceId);
        supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
        ServiceInstance serviceInstance = choose(serviceId, lbRequest);
        if (serviceInstance == null) {
            supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(
                    new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, new EmptyResponse())));
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        return execute(serviceId, serviceInstance, lbRequest);
    }

繼續(xù)跟蹤choose方法,是在BlockingLoadBalancerClient類中實(shí)現(xiàn)的。

BlockingLoadBalancerClient

我們已經(jīng)知道注入到Spring Ioc容器中的LoadBalancerClient其實(shí)是BlockingLoadBalancerClient對(duì)象,所以繼續(xù)跟蹤BlockingLoadBalancerClient的choose方法:

@Override
    public <T> ServiceInstance choose(String serviceId, Request<T> request) {
        ReactiveLoadBalancer<ServiceInstance> loadBalancer = loadBalancerClientFactory.getInstance(serviceId);
        if (loadBalancer == null) {
            return null;
        }
        Response<ServiceInstance> loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();
        if (loadBalancerResponse == null) {
            return null;
        }
        return loadBalancerResponse.getServer();
    }

我們需要重點(diǎn)關(guān)注的是兩個(gè)方法:

第一個(gè)是LoadBalancerClientFactory的getInstance方法:通過(guò)serviceId從子容器中拿到ReactiveLoadBalancer,參數(shù)serviceId(服務(wù)Id),指的就是我們注冊(cè)到Eureka注冊(cè)中心的服務(wù)Id,比如前面案例中的userService。

第二個(gè)是ReactiveLoadBalancer的choose方法:根據(jù)不同的負(fù)載均衡策略,從服務(wù)隊(duì)列中拿到serviceInstance。Spring cloud提供了兩種負(fù)載均衡策略:隨機(jī)策略RandomLoadBalancer和循環(huán)策略RoundRobinLoadBalancer。

我們先來(lái)看第一步:從子容器中獲取ReactiveLoadBalancer對(duì)象。

子容器的創(chuàng)建

如果是首次調(diào)用、子容器不存在的情況下,LoadBalancerClientFactory負(fù)責(zé)創(chuàng)建子容器。

LoadBalancerClientFactory是reactiveLoadBalancer.Factory<ServiceInstance>的實(shí)現(xiàn)類,繼承自虛擬類NamedContextFactory,創(chuàng)建子容器的大部分代碼都在NamedContextFactory類中。

我們首先看一下這個(gè)LoadBalancerClientFactory是怎么初始化的Spring IoC容器中的。其實(shí)前面已經(jīng)說(shuō)過(guò)了,是通過(guò)spring-cloud-loadbalancer包下的自動(dòng)配置類LoadBalancerAutoConfiguration負(fù)責(zé)注入。

我們從源碼角度驗(yàn)證一下,LoadBalancerAutoConfiguration源碼:

@ConditionalOnMissingBean
    @Bean
    public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) {
        LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
        clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
        return clientFactory;
    }

看一下LoadBalancerClientFactory的構(gòu)造方法:

public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
        super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
        this.properties = properties;
    }

父類的構(gòu)造方法:

public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
        this.defaultConfigType = defaultConfigType;
        this.propertySourceName = propertySourceName;
        this.propertyName = propertyName;
    }

可以看到LoadBalancerClientFactory創(chuàng)建的時(shí)候?qū)oadBalancerClientConfiguration.class賦值給他的父類NamedContextFactory的defaultConfigType屬性,在創(chuàng)建子容器的時(shí)候LoadBalancerClientConfiguration類會(huì)被注冊(cè)為子容器的配置類、從而通過(guò)LoadBalancerClientConfiguration完成ReactorLoadBalancer對(duì)象的注入(注入到子容器中)。

NamedContextFactory

先對(duì)LoadBalancerClientFactory做一個(gè)簡(jiǎn)單的認(rèn)識(shí)。

LoadBalancerClientFactory繼承自虛擬類NamedContextFactory,實(shí)現(xiàn)了接口DisposableBean和ApplicationContextAware,這兩個(gè)接口我們并不陌生,在Spring生命周期回調(diào)的學(xué)習(xí)過(guò)程中中我們了解過(guò)這兩個(gè)接口,Spring會(huì)在容器創(chuàng)建完成后通過(guò)ApplicationContextAware的setApplicationContext方法把ApplicationContext送回來(lái)、在容器銷毀的時(shí)候回調(diào)DisposableBean接口的destroy方法。LoadBalancerClientFactory實(shí)現(xiàn)了這兩個(gè)接口,所以LoadBalancerClientFactory就可以獲取到Spring IoC根容器的applicationContext:

@Override
    public void setApplicationContext(ApplicationContext parent) throws BeansException {
        this.parent = parent;
    }

檢查NamedContextFactory的setApplicatonContext方法,發(fā)現(xiàn)他把Spring IoC容器設(shè)置為自己的父容器了:這也很好理解,從NamedContextFactory類名稱判斷,這個(gè)類的目的就是要?jiǎng)?chuàng)建“Named”容器、也就是命名容器,其實(shí)我們后面會(huì)發(fā)現(xiàn)就是用serviceId命名的容器,比如我們有userservice,那就會(huì)創(chuàng)建一個(gè)名字叫userservice的容器。通過(guò)ApplicationContextAware回調(diào)setApplicationContext方法將Spring Ioc容器設(shè)置為命名容器的“父容器”。

繼續(xù)跟蹤LoadBalancerClientFactory的getInstance方法,調(diào)用到父類NamedContextFactory的getInstance:

@Override
    public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
        return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
    }
    public <T> T getInstance(String name, Class<T> type) {
        AnnotationConfigApplicationContext context = getContext(name);
        try {
            return context.getBean(type);
        }
        catch (NoSuchBeanDefinitionException e) {
            // ignore
        }
        return null;
    }

最終是向Spring的ApplicationContext獲取類型為ReactorServiceInstanceLoadBalancer的bean。其中ApplicationContext通過(guò)getContext方法獲?。?/p>

private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
    protected AnnotationConfigApplicationContext getContext(String name) {
        if (!this.contexts.containsKey(name)) {
            synchronized (this.contexts) {
                if (!this.contexts.containsKey(name)) {
                    this.contexts.put(name, createContext(name));
                }
            }
        }
        return this.contexts.get(name);
    }

首先從contexts查找,contexts是以serviceId為鍵值的ConcurrentHashMap,緩存創(chuàng)建的ApplicationContext,如果尚未創(chuàng)建,則調(diào)用createContext方法創(chuàng)建后緩存到contexts中。

這個(gè)名字為contexts的ConcurrentHashMap其實(shí)就是NamedContextFactory的核心:創(chuàng)建的ApplicationContext緩存在以serviceId為鍵值的HashMap中,獲取的時(shí)候以serviceId到contexts中去查找,查找到則直接返回、查找不到則創(chuàng)建后緩存。

createContext方法:

protected AnnotationConfigApplicationContext createContext(String name) {
        AnnotationConfigApplicationContext context;
        if (this.parent != null) {
            // jdk11 issue
            // https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
            // https://github.com/spring-cloud/spring-cloud-openfeign/issues/475
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            if (parent instanceof ConfigurableApplicationContext) {
                beanFactory.setBeanClassLoader(
                        ((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());
            }
            else {
                beanFactory.setBeanClassLoader(parent.getClassLoader());
            }
            context = new AnnotationConfigApplicationContext(beanFactory);
            context.setClassLoader(this.parent.getClassLoader());
        }
        else {
            context = new AnnotationConfigApplicationContext();
        }
        if (this.configurations.containsKey(name)) {
            for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
                context.register(configuration);
            }
        }
        for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
            if (entry.getKey().startsWith("default.")) {
                for (Class<?> configuration : entry.getValue().getConfiguration()) {
                    context.register(configuration);
                }
            }
        }
        //注意這里會(huì)注冊(cè)this.defaultConfigType到容器中
        context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
        context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,
                Collections.<String, Object>singletonMap(this.propertyName, name)));
        if (this.parent != null) {
            // Uses Environment from parent as well as beans
            context.setParent(this.parent);
        }
        context.setDisplayName(generateDisplayName(name));
        context.refresh();
        return context;
    }

代碼比較長(zhǎng)但是并不復(fù)雜,仔細(xì)看一下其實(shí)就是Spring IoC容器的初始化過(guò)程:

  • 創(chuàng)建DefaultListableBeanFactory
  • 創(chuàng)建AnnotationConfigApplicationContext
  • 加載屬于當(dāng)前serviceId的配置
  • 加載所有的“默認(rèn)”配置(也就是以default.開頭的配置項(xiàng))
  • 加載配置文件(從配置文件及環(huán)境變量中加載),注冊(cè)配置類 this.defaultConfigType,其實(shí)就是LoadBalancerClientConfiguration配置類
  • 設(shè)置父容器(Spring Ioc的主容器設(shè)置為父容器)
  • 刷新容器
  • 返回容器

一個(gè)需要關(guān)注的重點(diǎn)就是:子容器創(chuàng)建的過(guò)程中,將配置類LoadBalancerClientConfiguration注冊(cè)到容器中,在容器刷新的時(shí)候,這個(gè)配置類會(huì)被加載。

ReactorLoadBalancer & LoadBalancerClientConfiguration

子容器創(chuàng)建出來(lái)之后,我們還是返回到上面的NamedContextFactory的getInstance方法中:

@Override
    public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
        return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
    }

會(huì)向子容器獲取ReactorServiceInstanceLoadBalancer對(duì)象。

所以我們現(xiàn)在兩個(gè)任務(wù):第一個(gè)是了解一下ReactorServiceInstanceLoadBalancer類,第二個(gè)是要了解到注入到子容器中的ReactorServiceInstanceLoadBalancer究竟是個(gè)什么對(duì)象。

第一步:看一眼ReactorLoadBalancer的類結(jié)構(gòu):

ReactorServiceInstanceLoadBalancer接口繼承自ReactorLoadBalancer,Spring Cloud提供了他的兩個(gè)實(shí)現(xiàn)類:隨機(jī)策略類和輪詢策略類。

第二步,注入到子容器中的ReactorServiceInstanceLoadBalancer究竟是個(gè)什么對(duì)象?就需要研究一下ReactorLoadBalancer的初始化過(guò)程。

子容器通過(guò)配置類LoadBalancerClientConfiguration實(shí)現(xiàn)ReactorLoadBalancer的注入,默認(rèn)實(shí)現(xiàn)類是RoundRobinLoadBalancer:

@Bean
    @ConditionalOnMissingBean
    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RoundRobinLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }

OK!

真相大白了,默認(rèn)就是輪詢策略RoundRobinLoadBalancer。

負(fù)載均衡策略的配置

Spring Cloud默認(rèn)的負(fù)載均衡策略是RoundRobinLoadBalancer,我們可以通過(guò)配置調(diào)整負(fù)載均衡策略為隨機(jī)策略RandomLoadBalancer。

調(diào)整方法很簡(jiǎn)單,官網(wǎng)說(shuō)了:

余事以后再說(shuō)吧。

以上就是Spring cloud負(fù)載均衡@LoadBalanced &amp; LoadBalancerClient的詳細(xì)內(nèi)容,更多關(guān)于Spring cloud負(fù)載均衡@LoadBalanced LoadBalancerClient的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解springboot啟動(dòng)時(shí)是如何加載配置文件application.yml文件

    詳解springboot啟動(dòng)時(shí)是如何加載配置文件application.yml文件

    這篇文章主要介紹了詳解springboot啟動(dòng)時(shí)是如何加載配置文件application.yml文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • SpringMVC解析post請(qǐng)求參數(shù)詳解

    SpringMVC解析post請(qǐng)求參數(shù)詳解

    今天小編就為大家分享一篇解決SpringMVC接收不到ajaxPOST參數(shù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-08-08
  • 老生常談比較排序之歸并排序(遞歸)

    老生常談比較排序之歸并排序(遞歸)

    下面小編就為大家?guī)?lái)一篇老生常談比較排序之歸并排序(遞歸)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • GC算法實(shí)現(xiàn)垃圾優(yōu)先算法

    GC算法實(shí)現(xiàn)垃圾優(yōu)先算法

    為什么會(huì)存在那么多的垃圾回收算法呢?我想這個(gè)問題的答案可能是沒有任何一種內(nèi)存回收算法是完美的,所以在針對(duì)不同的情景需求下,不同的內(nèi)存回收算法有其獨(dú)特的優(yōu)勢(shì),所以最后就延續(xù)了多種回收算法
    2022-01-01
  • Java實(shí)現(xiàn)大文件的分片上傳與下載(springboot+vue3)

    Java實(shí)現(xiàn)大文件的分片上傳與下載(springboot+vue3)

    這篇文章主要為大家詳細(xì)介紹了java基于springboot+vue3如何大文件的分片上傳與下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2023-06-06
  • MyBatis入門學(xué)習(xí)教程-MyBatis快速入門

    MyBatis入門學(xué)習(xí)教程-MyBatis快速入門

    MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架,這篇文章主要給大家分享MyBatis的一篇快速入門教程
    2021-06-06
  • JavaWeb response完成重定向?qū)崿F(xiàn)過(guò)程詳解

    JavaWeb response完成重定向?qū)崿F(xiàn)過(guò)程詳解

    這篇文章主要介紹了JavaWeb response完成重定向?qū)崿F(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java結(jié)束進(jìn)程的實(shí)例代碼

    java結(jié)束進(jìn)程的實(shí)例代碼

    java結(jié)束程序進(jìn)程的方法很簡(jiǎn)單,只要一句代碼就行,大家參考使用吧
    2013-12-12
  • Java多線程中的concurrent簡(jiǎn)析

    Java多線程中的concurrent簡(jiǎn)析

    這篇文章主要介紹了Java多線程中的concurrent簡(jiǎn)析,java.util.concurrent包提供了很多有用的類,方便我們進(jìn)行并發(fā)程序的開發(fā),本文將會(huì)挑選其中常用的一些類來(lái)進(jìn)行大概的說(shuō)明,需要的朋友可以參考下
    2023-09-09
  • Java實(shí)現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子

    Java實(shí)現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子

    本文主要介紹了Java實(shí)現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07

最新評(píng)論

齐河县| 应用必备| 石门县| 青河县| 鄢陵县| 彰武县| 磐安县| 邹平县| 遂昌县| 洪洞县| 喜德县| 广德县| 乌拉特前旗| 新化县| 高安市| 兴隆县| 黄石市| 秦安县| 秦安县| 闸北区| 蒙自县| 龙海市| 丰都县| 明水县| 山丹县| 洱源县| 武强县| 阜阳市| 镇坪县| 乐安县| 京山县| 锡林郭勒盟| 富阳市| 岱山县| 渑池县| 台东县| 金堂县| 永胜县| 光山县| 梁平县| 开鲁县|