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

Spring注解驅(qū)動(dòng)之BeanPostProcessor后置處理器講解

 更新時(shí)間:2022年09月30日 10:01:00   作者:融極  
這篇文章主要介紹了Spring注解驅(qū)動(dòng)之BeanPostProcessor后置處理器講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

概述

在學(xué)習(xí)Spring的時(shí)候,在了解基本用法的時(shí)候,如果有時(shí)間一定要深入源碼了解Spring的底層原理,這樣在做一些適配工作、寫(xiě)一些輪子的時(shí)候就會(huì)比較容易,否則會(huì)很難,甚至一頭霧水,無(wú)法完成工作。

吃透Spring的原理和源碼,往往可以拉開(kāi)人們之間的差距,當(dāng)前只要是使用Java技術(shù)棧開(kāi)發(fā)的Web項(xiàng)目,幾乎都會(huì)使用Spring框架。

而且目前各招聘網(wǎng)站上對(duì)于Java開(kāi)發(fā)的要求幾乎清一色的都是熟悉或者精通Spring,所以,你很有必要學(xué)習(xí)Spring的細(xì)節(jié)知識(shí)點(diǎn)。

BeanPostProcessor后置處理器概述

首先,看下BeanPostProcessor的源碼。

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

public interface BeanPostProcessor {
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

從源碼可以看出,BeanPostProcessor是一個(gè)接口,其中有兩個(gè)方法:

postProcessBeforeInitialization和postProcessAfterInitialization這兩個(gè)方法分別是在Spring容器中的bean初始化前后執(zhí)行,所以Spring容器中的每個(gè)bean對(duì)象初始化前后,都會(huì)執(zhí)行BeanPostProcessor接口的兩個(gè)方法。

也就是說(shuō),postProcessBeforeInitialization方法會(huì)在bean實(shí)例化和屬性設(shè)置之后,自定義初始化方法之前被調(diào)用,而postProcessAfterInitialization方法會(huì)在自定義初始化方法之后被調(diào)用。當(dāng)容器中存在多個(gè)BeanPostProcessor的實(shí)現(xiàn)類時(shí),會(huì)按照它們?cè)谌萜髦凶?cè)的順序執(zhí)行。對(duì)于自定義的BeanPostProcessor實(shí)現(xiàn)類,還可以讓其實(shí)現(xiàn)Ordered接口自定義排序。

因此我們可以在每個(gè)bean對(duì)象初始化前后,加上自己的邏輯。實(shí)現(xiàn)方式是自定義一個(gè)BeanPostProcessor接口的實(shí)現(xiàn)類,例如MyBeanPostProcessor,然后在該類的postProcessBeforeInitialization和postProcessAfterInitialization這兩個(gè)方法寫(xiě)上自定義邏輯。

BeanPostProcessor后置處理器實(shí)例

我們創(chuàng)建一個(gè)MyBeanPostProcessor類,實(shí)現(xiàn)BeanPostProcessor接口,如下所示。

package com.meimeixia.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component // 將后置處理器加入到容器中,這樣的話,Spring就能讓它工作了,否則無(wú)法工作
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
		return bean;
	}
}

接下來(lái),我們應(yīng)該是要編寫(xiě)測(cè)試用例來(lái)進(jìn)行測(cè)試了。

package com.meimeixia.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import com.meimeixia.bean.Car;

@ComponentScan("com.meimeixia.bean")
@Configuration
public class MainConfigOfLifeCycle {

	@Bean(initMethod="init", destroyMethod="destroy")
	public Car car() {
		return new Car();
	}	
}

第二處改動(dòng)是將Cat類上添加的@Scope(“prototype”)注解給注釋掉,因?yàn)樵蹅冎白鰷y(cè)試的時(shí)候,也是將Cat對(duì)象設(shè)置成多實(shí)例bean了。

package com.meimeixia.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

// @Scope("prototype")
@Component
public class Cat implements InitializingBean, DisposableBean {
	
	public Cat() {
		System.out.println("cat constructor...");
	}

	/**
	 * 會(huì)在容器關(guān)閉的時(shí)候進(jìn)行調(diào)用
	 */
	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat destroy...");
	}

	/**
	 * 會(huì)在bean創(chuàng)建完成,并且屬性都賦好值以后進(jìn)行調(diào)用
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat afterPropertiesSet...");
	}
}

好了,現(xiàn)在咱們就可以編寫(xiě)測(cè)試用例來(lái)進(jìn)行測(cè)試了。

可喜的是,我們也不用再編寫(xiě)一個(gè)測(cè)試用例了,直接運(yùn)行IOCTest_LifeCycle類中的test01()方法就行,該方法的代碼如下所示。

@Test
public void test01() {
    // 1. 創(chuàng)建IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器創(chuàng)建完成");
    // 關(guān)閉容器
    applicationContext.close();
}

此時(shí),運(yùn)行IOCTest_LifeCycle類中的test01()方法,輸出的結(jié)果信息如下所示。

可以看到,postProcessBeforeInitialization方法會(huì)在bean實(shí)例化和屬性設(shè)置之后,自定義初始化方法之前被調(diào)用,而postProcessAfterInitialization方法會(huì)在自定義初始化方法之后被調(diào)用。

當(dāng)然了,也可以讓我們自己寫(xiě)的MyBeanPostProcessor類來(lái)實(shí)現(xiàn)Ordered接口自定義排序,如下所示。

package com.meimeixia.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 后置處理器,在初始化前后進(jìn)行處理工作
 * @author liayun
 *
 */
@Component // 將后置處理器加入到容器中,這樣的話,Spring就能讓它工作了
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
		return bean;
	}

	@Override
	public int getOrder() {
		return 3;
	}
}

BeanPostProcessor后置處理器作用

后置處理器可用于bean對(duì)象初始化前后進(jìn)行邏輯增強(qiáng)。

Spring提供了BeanPostProcessor接口的很多實(shí)現(xiàn)類,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的實(shí)現(xiàn),AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的動(dòng)態(tài)代理等等。

除此之外,我們還可以自定義BeanPostProcessor接口的實(shí)現(xiàn)類,在其中寫(xiě)入咱們需要的邏輯。

bean的初始化和銷毀流程

我們知道BeanPostProcessor的postProcessBeforeInitialization()方法是在bean的初始化之前被調(diào)用;而postProcessAfterInitialization()方法是在bean初始化的之后被調(diào)用。

并且bean的初始化和銷毀方法我們可以通過(guò)如下方式進(jìn)行指定。

1. 通過(guò)@Bean指定init-method和destroy-method

@Bean(initMethod="init", destroyMethod="destroy")

2. 通過(guò)讓bean實(shí)現(xiàn)InitializingBean和DisposableBean這倆接口

@Componentpublic class Cat implements InitializingBean, DisposableBean {}

3. 使用JSR-250規(guī)范里面定義的@PostConstruct和@PreDestroy這倆注解

  • @PostConstruct:在bean創(chuàng)建完成并且屬性賦值完成之后,來(lái)執(zhí)行初始化方法
  • @PreDestroy:在容器銷毀bean之前通知我們進(jìn)行清理工作

4. 通過(guò)讓bean實(shí)現(xiàn)BeanPostProcessor接口

@Component // 將后置處理器加入到容器中,這樣的話,Spring就能讓它工作了
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {}

通過(guò)以上四種方式就可以對(duì)bean的整個(gè)生命周期進(jìn)行控制:

  • bean的實(shí)例化:調(diào)用bean的構(gòu)造方法,我們可以在bean的無(wú)參構(gòu)造方法中執(zhí)行相應(yīng)的邏輯。
  • bean的初始化:在初始化時(shí)可以通過(guò)BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法進(jìn)行攔截,執(zhí)行自定義的邏輯。通過(guò)@PostConstruct注解、InitializingBean和init-method來(lái)指定bean初始化前后執(zhí)行的方法,在該方法中可以執(zhí)行自定義的邏輯。
  • bean的銷毀:可以通過(guò)@PreDestroy注解、DisposableBean和destroy-method來(lái)指定bean在銷毀前執(zhí)行的方法,在方法中可以執(zhí)行自定義的邏輯。

所以,通過(guò)上述4種方式,我們可以控制Spring中bean的整個(gè)生命周期。

BeanPostProcessor源碼解析

如果想深刻理解BeanPostProcessor的工作原理,那么就不得不看下相關(guān)的源碼,我們可以在MyBeanPostProcessor類的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法這兩處打上斷點(diǎn)來(lái)進(jìn)行調(diào)試,如下所示。 

public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization" + ",beanName:"+beanName + ",bean=>" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization" + ",beanName:"+beanName + ",bean=>" + bean);
        return bean;
    }

    @Override
    public int getOrder() {
        return 3;
    }
}

通過(guò)斷點(diǎn)調(diào)試,我們可以看到,在applyBeanPostProcessorBeforeInitialization()方法中,會(huì)遍歷所有BeanPostProcessor對(duì)象,然后依次執(zhí)行所有BeanPostProcessor對(duì)象的postProcessorBeforeInitialization()方法,一旦BeanPostProcessor對(duì)象的postProcessBeforeInitialization()方法返回null以后,則后面的BeanPostProcessor對(duì)象便不再執(zhí)行了,而是直接退出for循環(huán)。這些都是我們看源碼看到的。

看Spring源碼,我們還看到一個(gè)細(xì)節(jié),在Spring中調(diào)用initializeBean()方法之前,還調(diào)用了populateBean()方法來(lái)為bean的屬性賦值。

經(jīng)過(guò)一系列的跟蹤源碼分析,我們可以將關(guān)鍵代碼的調(diào)用過(guò)程使用如下偽代碼表述出來(lái)。

populateBean(beanName, mbd, instanceWrapper); // 給bean進(jìn)行屬性賦值
initializeBean(beanName, exposedObject, mbd)
{
	applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd); // 執(zhí)行自定義初始化
	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

也就是說(shuō),在Spring中,調(diào)用initializeBean()方法之前,調(diào)用了populateBean()方法為bean的屬性賦值,為bean的屬性賦好值之后,再調(diào)用initializeBean()方法進(jìn)行初始化。

在initializeBean()中,調(diào)用自定義的初始化方法(即invokeInitMethods())之前,調(diào)用了applyBeanPostProcessorsBeforeInitialization()方法,而在調(diào)用自定義的初始化方法之后,又調(diào)用了applyBeanPostProcessorsAfterInitialization()方法。至此,整個(gè)bean的初始化過(guò)程就這樣結(jié)束了。

BeanPostProcessor接口在Spring底層的應(yīng)用案例

ApplicationContextAwareProcessor類

org.springframework.context.support.ApplicationContextAwareProcessor是BeanPostProcessor接口的一個(gè)實(shí)現(xiàn)類,這個(gè)類的作用是可以向組件中注入IOC容器,大致的源碼如下。

注意:我這里的Spring版本為4.3.12.RELEASE。

那具體如何使用ApplicationContextAwareProcessor類向組件中注入IOC容器呢?

如果需要向組件中注入IOC容器,那么可以讓組件實(shí)現(xiàn)ApplicationContextAware接口。

例如,我們創(chuàng)建一個(gè)創(chuàng)建一個(gè)Dog類,使其實(shí)現(xiàn)ApplicationContextAware接口,此時(shí),我們需要實(shí)現(xiàn)ApplicationContextAware接口中的setApplicationContext()方法,在setApplicationContext()方法中有一個(gè)ApplicationContext類型的參數(shù),這個(gè)就是IOC容器對(duì)象,我們可以在Dog類中定義一個(gè)ApplicationContext類型的成員變量,然后在setApplicationContext()方法中為這個(gè)成員變量賦值,此時(shí)就可以在Dog類中的

其他方法中使用ApplicationContext對(duì)象了,如下所示。

package com.meimeixia.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * ApplicationContextAwareProcessor這個(gè)類的作用是可以幫我們?cè)诮M件里面注入IOC容器,
 * 怎么注入呢?我們想要IOC容器的話,比如我們這個(gè)Dog組件,只需要實(shí)現(xiàn)ApplicationContextAware接口就行
 * 
 */
@Component
public class Dog implements ApplicationContextAware {
	
	private ApplicationContext applicationContext;

	public Dog() {
		System.out.println("dog constructor...");
	}
	
	// 在對(duì)象創(chuàng)建完成并且屬性賦值完成之后調(diào)用
	@PostConstruct
	public void init() { 
		System.out.println("dog...@PostConstruct...");
	}
	
	// 在容器銷毀(移除)對(duì)象之前調(diào)用
	@PreDestroy
	public void destory() {
		System.out.println("dog...@PreDestroy...");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 在這兒打個(gè)斷點(diǎn)調(diào)試一下
		// TODO Auto-generated method stub
		this.applicationContext = applicationContext;
	}	
}

看到這里,相信不少小伙伴們都有一種很熟悉的感覺(jué),沒(méi)錯(cuò),我之前也在項(xiàng)目中使用過(guò)!是的,這就是BeanPostProcessor在Spring底層的一種使用場(chǎng)景。至于上面的案例代碼為何會(huì)在setApplicationContext()方法中獲取到ApplicationContext對(duì)象,這就是ApplicationContextAwareProcessor類的功勞了!

接下來(lái),我們就深入分析下ApplicationContextAwareProcessor類。

我們先來(lái)看下ApplicationContextAwareProcessor類中對(duì)于postProcessBeforeInitialization()方法的實(shí)現(xiàn),如下所示。

在bean初始化之前,首先對(duì)當(dāng)前bean的類型進(jìn)行判斷,如果當(dāng)前bean的類型不是EnvironmentAware,不是EmbeddedValueResolverAware,不是ResourceLoaderAware,不是ApplicationEventPublisherAware,不是MessageSourceAware,也不是ApplicationContextAware,那么直接返回bean。

如果是上面類型中的一種類型,那么最終會(huì)調(diào)用invokeAwareInterfaces()方法,并將bean傳遞給該方法。

invokeAwareInterfaces()方法又是個(gè)什么呢?我們繼續(xù)看invokeAwareInterfaces()方法的源碼,如下所示。

可以看到invokeAwareInterfaces()方法的源碼比較簡(jiǎn)單,就是判斷當(dāng)前bean屬于哪種接口類型,然后將bean強(qiáng)轉(zhuǎn)為哪種接口類型的對(duì)象,接著調(diào)用接口中的方法,將相應(yīng)的參數(shù)傳遞到接口的方法中。

我們可以看到,此時(shí)會(huì)將this.applicationContext傳遞到ApplicationContextAware接口的setApplicationContext()方法中。所以,我們?cè)贒og類的setApplicationContext()方法中就可以直接接收到ApplicationContext對(duì)象了。

BeanValidationPostProcessor類

org.springframework.validation.beanvalidation.BeanValidationPostProcessor類注意是用來(lái)為bean進(jìn)行校驗(yàn)操作的,當(dāng)我們創(chuàng)建bean,并為bean賦值后,我們可以通過(guò)BeanValidationPostProcessor類為bean進(jìn)行校驗(yàn)操作。BeanValidationPostProcessor類源碼如下:

這里,我們也來(lái)看看postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法的實(shí)現(xiàn),如下所示。

InitDestroyAnnotationBeanPostProcessor類

org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor類主要用來(lái)處理@PostConstruct注解和@PreDestroy注解。

使用了@PostConstruct注解和@PreDestroy注解來(lái)標(biāo)注方法,Spring怎么就知道什么時(shí)候執(zhí)行@PostConstruct注解標(biāo)注的方法,什么時(shí)候執(zhí)行@PreDestroy注解標(biāo)注的方法呢?這就要?dú)w功于InitDestroyAnnotationBeanPostProcessor類了。

接下來(lái),我們也通過(guò)Debug的方式來(lái)跟進(jìn)下代碼的執(zhí)行流程。首先,在Dog類的initt()方法上打上一個(gè)斷點(diǎn),如下所示。

在InitDestroyAnnotationBeanPostProcessor類的postProcessBeforeInitialization()方法中,首先會(huì)找到bean中有關(guān)生命周期的注解,比如@PostConstruct注解等,找到這些注解之后,則將這些信息賦值給LifecycleMetadata類型的變量metadata,之后調(diào)用metadata的invokeInitMethods()方法,通過(guò)反射來(lái)調(diào)用標(biāo)注了@PostConstruct注解的方法。

這就是為什么標(biāo)注了@PostConstruct注解的方法會(huì)被Spring執(zhí)行的原因。

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
		}
		return bean;
	}

AutowiredAnnotationBeanPostProcessor類

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor類主要是用于處理標(biāo)注了@Autowired注解的變量或方法。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Bean的包掃描的實(shí)現(xiàn)方法

    Spring Bean的包掃描的實(shí)現(xiàn)方法

    這篇文章主要介紹了Spring Bean的包掃描的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • java版微信公眾平臺(tái)消息接口應(yīng)用示例

    java版微信公眾平臺(tái)消息接口應(yīng)用示例

    這篇文章主要介紹了java版微信公眾平臺(tái)消息接口應(yīng)用,結(jié)合實(shí)例形式對(duì)比分析了PHP與java應(yīng)用微信公眾平臺(tái)接口的相關(guān)調(diào)用與操作技巧,需要的朋友可以參考下
    2017-07-07
  • Spring Boot Logback配置日志過(guò)程解析

    Spring Boot Logback配置日志過(guò)程解析

    這篇文章主要介紹了Spring Boot Logback配置日志過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java報(bào)錯(cuò):UnsupportedOperationException in Collections的解決方案

    Java報(bào)錯(cuò):UnsupportedOperationException in Collection

    在Java編程中,UnsupportedOperationException是一種常見(jiàn)的運(yùn)行時(shí)異常,通常在試圖對(duì)不支持的操作執(zhí)行修改時(shí)發(fā)生,它表示當(dāng)前操作不被支持,本文將深入探討UnsupportedOperationException的產(chǎn)生原因,并提供具體的解決方案和最佳實(shí)踐,需要的朋友可以參考下
    2024-06-06
  • Java內(nèi)存溢出實(shí)現(xiàn)原因及解決方案

    Java內(nèi)存溢出實(shí)現(xiàn)原因及解決方案

    這篇文章主要介紹了Java內(nèi)存溢出實(shí)現(xiàn)原因及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Struts2截取字符串代碼介紹

    Struts2截取字符串代碼介紹

    這篇文章主要介紹了Struts2截取字符串代碼介紹,介紹了基本的截取方法,以及截取帶html標(biāo)簽字符串的方法,需要的朋友可以了解下。
    2017-09-09
  • java設(shè)計(jì)模式之代理模式(Porxy)詳解

    java設(shè)計(jì)模式之代理模式(Porxy)詳解

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式之代理模式Porxy的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • idea連接數(shù)據(jù)庫(kù)的操作方法

    idea連接數(shù)據(jù)庫(kù)的操作方法

    這篇文章主要介紹了idea如何連接數(shù)據(jù)庫(kù),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • 淺談Java常見(jiàn)的排序算法

    淺談Java常見(jiàn)的排序算法

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java常見(jiàn)的排序算法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 利用Java實(shí)現(xiàn)文件鎖定功能

    利用Java實(shí)現(xiàn)文件鎖定功能

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)文件鎖定功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08

最新評(píng)論