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

springBoot中動(dòng)態(tài)加載jar包的完整指南

 更新時(shí)間:2025年10月16日 09:47:44   作者:湯姆yu  
這篇文章主要為大家詳細(xì)介紹了springBoot中動(dòng)態(tài)加載jar包的相關(guān)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

一、概述

1、背景

目前數(shù)據(jù)治理服務(wù)中有眾多治理任務(wù),當(dāng)其中任一治理任務(wù)有改動(dòng)需要升級(jí)或新增一個(gè)治理任務(wù)時(shí),都需要將數(shù)據(jù)治理服務(wù)重啟,會(huì)影響其他治理任務(wù)的正常運(yùn)行。

2、目標(biāo)

  • 能夠動(dòng)態(tài)啟動(dòng)、停止任一治理任務(wù)
  • 能夠動(dòng)態(tài)升級(jí)、添加治理任務(wù)
  • 啟動(dòng)、停止治理任務(wù)或升級(jí)、添加治理任務(wù)不能影響其他任務(wù)

3、方案

為了支持業(yè)務(wù)代碼盡量的解耦,把部分業(yè)務(wù)功能通過(guò)動(dòng)態(tài)加載的方式加載到主程序中,以滿足可插拔式的加載、組合式的部署。

配合xxl-job任務(wù)調(diào)度框架,將數(shù)據(jù)治理任務(wù)做成xxl-job任務(wù)的方式注冊(cè)到xxl-job中,方便統(tǒng)一管理。

二、動(dòng)態(tài)加載

1、自定義類加載器

URLClassLoader 是一種特殊的類加載器,可以從指定的 URL 中加載類和資源。它的主要作用是動(dòng)態(tài)加載外部的 JAR 包或者類文件,從而實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)展應(yīng)用程序的功。為了便于管理動(dòng)態(tài)加載的jar包,自定義類加載器繼承URLClassloader。

/**
 * 自定義類加載器
 *
 * @author lijianyu
 * @date 2023/04/03 17:54
 **/
publicclassMyClassLoaderextendsURLClassLoader{

    private Map<String, Class<?>> loadedClasses = new ConcurrentHashMap<>();

    public Map<String, Class<?>> getLoadedClasses() {
        return loadedClasses;
    }

    publicMyClassLoader(URL[] urls, ClassLoader parent){
        super(urls, parent);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 從已加載的類集合中獲取指定名稱的類
        Class<?> clazz = loadedClasses.get(name);
        if (clazz != null) {
            return clazz;
        }
        try {
            // 調(diào)用父類的findClass方法加載指定名稱的類
            clazz = super.findClass(name);
            // 將加載的類添加到已加載的類集合中
            loadedClasses.put(name, clazz);
            return clazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            returnnull;
        }
    }

    publicvoidunload(){
        try {
            for (Map.Entry<String, Class<?>> entry : loadedClasses.entrySet()) {
                // 從已加載的類集合中移除該類
                String className = entry.getKey();
                loadedClasses.remove(className);
                try{
                    // 調(diào)用該類的destory方法,回收資源
                    Class<?> clazz = entry.getValue();
                    Method destory = clazz.getDeclaredMethod("destory");
                    destory.invoke(clazz);
                } catch (Exception e ) {
                    // 表明該類沒有destory方法
                }
            }
            // 從其父類加載器的加載器層次結(jié)構(gòu)中移除該類加載器
            close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

自定義類加載器中,為了方便類的卸載,定義一個(gè)map保存已加載的類信息。key為這個(gè)類的ClassName,value為這個(gè)類的類信息。

同時(shí)定義了類加載器的卸載方法,卸載方法中,將已加載的類的集合中移除該類。由于此類可能使用系統(tǒng)資源或調(diào)用線程,為了避免資源未回收引起的內(nèi)存溢出,通過(guò)反射調(diào)用這個(gè)類中的destroy方法,回收資源。

最后調(diào)用close方法。

2、動(dòng)態(tài)加載

由于此項(xiàng)目使用spring框架,以及xxl-job任務(wù)的機(jī)制調(diào)用動(dòng)態(tài)加載的代碼,因此要完成以下內(nèi)容:

  • 將動(dòng)態(tài)加載的jar包讀到內(nèi)存中
  • 將有spring注解的類,通過(guò)注解掃描的方式,掃描并手動(dòng)添加到spring容器中。
  • 將@XxlJob注解的方法,通過(guò)注解掃描的方式,手動(dòng)添加到xxljob執(zhí)行器中。
/**
 * @author lijianyu
 * @date 2023/04/29 13:18
 **/
@Component
publicclassDynamicLoad{

    privatestatic Logger logger = LoggerFactory.getLogger(DynamicLoad.class);

    @Autowired
    private ApplicationContext applicationContext;

    private Map<String, MyClassLoader> myClassLoaderCenter = new ConcurrentHashMap<>();

    @Value("${dynamicLoad.path}")
    private String path;

    /**
     * 動(dòng)態(tài)加載指定路徑下指定jar包
     * @param path
     * @param fileName
     * @param isRegistXxlJob  是否需要注冊(cè)xxljob執(zhí)行器,項(xiàng)目首次啟動(dòng)不需要注冊(cè)執(zhí)行器
     * @return map<jobHander, Cron> 創(chuàng)建xxljob任務(wù)時(shí)需要的參數(shù)配置
     */
    publicvoidloadJar(String path, String fileName, Boolean isRegistXxlJob)throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        File file = new File(path +"/" + fileName);
        Map<String, String> jobPar = new HashMap<>();
        // 獲取beanFactory
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        // 獲取當(dāng)前項(xiàng)目的執(zhí)行器
        try {
            // URLClassloader加載jar包規(guī)范必須這么寫
            URL url = new URL("jar:file:" + file.getAbsolutePath() + "!/");
            URLConnection urlConnection = url.openConnection();
            JarURLConnection jarURLConnection = (JarURLConnection)urlConnection;
            // 獲取jar文件
            JarFile jarFile = jarURLConnection.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();

            // 創(chuàng)建自定義類加載器,并加到map中方便管理
            MyClassLoader myClassloader = new MyClassLoader(new URL[] { url }, ClassLoader.getSystemClassLoader());
            myClassLoaderCenter.put(fileName, myClassloader);
            Set<Class> initBeanClass = new HashSet<>(jarFile.size());
            // 遍歷文件
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                if (jarEntry.getName().endsWith(".class")) {
                    // 1. 加載類到j(luò)vm中
                    // 獲取類的全路徑名
                    String className = jarEntry.getName().replace('/', '.').substring(0, jarEntry.getName().length() - 6);
                    // 1.1進(jìn)行反射獲取
                    myClassloader.loadClass(className);
                }
            }
            Map<String, Class<?>> loadedClasses = myClassloader.getLoadedClasses();
            XxlJobSpringExecutor xxlJobExecutor = new XxlJobSpringExecutor();
            for(Map.Entry<String, Class<?>> entry : loadedClasses.entrySet()){
                String className = entry.getKey();
                Class<?> clazz = entry.getValue();
                // 2. 將有@spring注解的類交給spring管理
                // 2.1 判斷是否注入spring
                Boolean flag = SpringAnnotationUtils.hasSpringAnnotation(clazz);
                if(flag){
                    // 2.2交給spring管理
                    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
                    AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
                    // 此處beanName使用全路徑名是為了防止beanName重復(fù)
                    String packageName = className.substring(0, className.lastIndexOf(".") + 1);
                    String beanName = className.substring(className.lastIndexOf(".") + 1);
                    beanName = packageName + beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
                    // 2.3注冊(cè)到spring的beanFactory中
                    beanFactory.registerBeanDefinition(beanName, beanDefinition);
                    // 2.4允許注入和反向注入
                    beanFactory.autowireBean(clazz);
                    beanFactory.initializeBean(clazz, beanName);
                    /*if(Arrays.stream(clazz.getInterfaces()).collect(Collectors.toSet()).contains(InitializingBean.class)){
                        initBeanClass.add(clazz);
                    }*/
                    initBeanClass.add(clazz);
                }

                // 3. 帶有XxlJob注解的方法注冊(cè)任務(wù)
                // 3.1 過(guò)濾方法
                Map<Method, XxlJob> annotatedMethods = null;
                try {
                    annotatedMethods = MethodIntrospector.selectMethods(clazz,
                            new MethodIntrospector.MetadataLookup<XxlJob>() {
                                @Override
                                public XxlJob inspect(Method method){
                                    return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                                }
                            });
                } catch (Throwable ex) {
                }
                // 3.2 生成并注冊(cè)方法的JobHander
                for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                    Method executeMethod = methodXxlJobEntry.getKey();
                    // 獲取jobHander和Cron
                    XxlJobCron xxlJobCron = executeMethod.getAnnotation(XxlJobCron.class);
                    if(xxlJobCron == null){
                        thrownew CustomException("500", executeMethod.getName() + "(),沒有添加@XxlJobCron注解配置定時(shí)策略");
                    }
                    if (!CronExpression.isValidExpression(xxlJobCron.value())) {
                        thrownew CustomException("500", executeMethod.getName() + "(),@XxlJobCron參數(shù)內(nèi)容錯(cuò)誤");
                    }
                    XxlJob xxlJob = methodXxlJobEntry.getValue();
                    jobPar.put(xxlJob.value(), xxlJobCron.value());
                    if (isRegistXxlJob) {
                        executeMethod.setAccessible(true);
                        // regist
                        Method initMethod = null;
                        Method destroyMethod = null;
                        xxlJobExecutor.registJobHandler(xxlJob.value(), new CustomerMethodJobHandler(clazz, executeMethod, initMethod, destroyMethod));
                    }
                }

            }
            // spring bean實(shí)際注冊(cè)
            initBeanClass.forEach(beanFactory::getBean);
        } catch (IOException e) {
            logger.error("讀取{} 文件異常", fileName);
            e.printStackTrace();
            thrownew RuntimeException("讀取jar文件異常: " + fileName);
        }
    }
}

以下是判斷該類是否有spring注解的工具類

apublic classSpringAnnotationUtils{

    privatestatic Logger logger = LoggerFactory.getLogger(SpringAnnotationUtils.class);
    /**
     * 判斷一個(gè)類是否有 Spring 核心注解
     *
     * @param clazz 要檢查的類
     * @return true 如果該類上添加了相應(yīng)的 Spring 注解;否則返回 false
     */
    publicstaticbooleanhasSpringAnnotation(Class<?> clazz){
        if (clazz == null) {
            returnfalse;
        }
        //是否是接口
        if (clazz.isInterface()) {
            returnfalse;
        }
        //是否是抽象類
        if (Modifier.isAbstract(clazz.getModifiers())) {
            returnfalse;
        }

        try {
            if (clazz.getAnnotation(Component.class) != null ||
            clazz.getAnnotation(Repository.class) != null ||
            clazz.getAnnotation(Service.class) != null ||
            clazz.getAnnotation(Controller.class) != null ||
            clazz.getAnnotation(Configuration.class) != null) {
                returntrue;
            }
        }catch (Exception e){
            logger.error("出現(xiàn)異常:{}",e.getMessage());
        }
        returnfalse;
    }
}

注冊(cè)xxljob執(zhí)行器的操作是仿照的xxljob中的XxlJobSpringExecutor的注冊(cè)方法。

3、動(dòng)態(tài)卸載

動(dòng)態(tài)卸載的過(guò)程,就是將動(dòng)態(tài)加載的代碼,從內(nèi)存,spring以及xxljob中移除。

代碼如下:

/**
 * 動(dòng)態(tài)卸載指定路徑下指定jar包
 * @param fileName
 * @return map<jobHander, Cron> 創(chuàng)建xxljob任務(wù)時(shí)需要的參數(shù)配置
 */
publicvoidunloadJar(String fileName)throws IllegalAccessException, NoSuchFieldException {
    // 獲取加載當(dāng)前jar的類加載器
    MyClassLoader myClassLoader = myClassLoaderCenter.get(fileName);

    // 獲取jobHandlerRepository私有屬性,為了卸載xxljob任務(wù)
    Field privateField = XxlJobExecutor.class.getDeclaredField("jobHandlerRepository");
    // 設(shè)置私有屬性可訪問(wèn)
    privateField.setAccessible(true);
    // 獲取私有屬性的值jobHandlerRepository
    XxlJobExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
    Map<String, IJobHandler> jobHandlerRepository = (ConcurrentHashMap<String, IJobHandler>) privateField.get(xxlJobSpringExecutor);
    // 獲取beanFactory,準(zhǔn)備從spring中卸載
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
    Map<String, Class<?>> loadedClasses = myClassLoader.getLoadedClasses();

    Set<String> beanNames = new HashSet<>();
    for (Map.Entry<String, Class<?>> entry: loadedClasses.entrySet()) {
        // 1. 將xxljob任務(wù)從xxljob執(zhí)行器中移除
        // 1.1 截取beanName
        String key = entry.getKey();
        String packageName = key.substring(0, key.lastIndexOf(".") + 1);
        String beanName = key.substring(key.lastIndexOf(".") + 1);
        beanName = packageName + beanName.substring(0, 1).toLowerCase() + beanName.substring(1);

        // 獲取bean,如果獲取失敗,表名這個(gè)類沒有加到spring容器中,則跳出本次循環(huán)
        Object bean = null;
        try{
            bean = applicationContext.getBean(beanName);
        }catch (Exception e){
            // 異常說(shuō)明spring中沒有這個(gè)bean
            continue;
        }

        // 1.2 過(guò)濾方法
        Map<Method, XxlJob> annotatedMethods = null;
        try {
            annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                    new MethodIntrospector.MetadataLookup<XxlJob>() {
                        @Override
                        public XxlJob inspect(Method method){
                            return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                        }
                    });
        } catch (Throwable ex) {
        }
        // 1.3 將job從執(zhí)行器中移除
        for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
            XxlJob xxlJob = methodXxlJobEntry.getValue();
            jobHandlerRepository.remove(xxlJob.value());
        }
        // 2.0從spring中移除,這里的移除是僅僅移除的bean,并未移除bean定義
        beanNames.add(beanName);
        beanFactory.destroyBean(beanName, bean);
    }
    // 移除bean定義
    Field mergedBeanDefinitions = beanFactory.getClass()
            .getSuperclass()
            .getSuperclass().getDeclaredField("mergedBeanDefinitions");
    mergedBeanDefinitions.setAccessible(true);
    Map<String, RootBeanDefinition> rootBeanDefinitionMap = ((Map<String, RootBeanDefinition>) mergedBeanDefinitions.get(beanFactory));
    for (String beanName : beanNames) {
        beanFactory.removeBeanDefinition(beanName);
        // 父類bean定義去除
        rootBeanDefinitionMap.remove(beanName);
    }

    // 卸載父任務(wù),子任務(wù)已經(jīng)在循環(huán)中卸載
    jobHandlerRepository.remove(fileName);
    // 3.2 從類加載中移除
    try {
        // 從類加載器底層的classes中移除連接
        Field field = ClassLoader.class.getDeclaredField("classes");
        field.setAccessible(true);
        Vector<Class<?>> classes = (Vector<Class<?>>) field.get(myClassLoader);
        classes.removeAllElements();
        // 移除類加載器的引用
        myClassLoaderCenter.remove(fileName);
        // 卸載類加載器
        myClassLoader.unload();
    } catch (NoSuchFieldException e) {
        logger.error("動(dòng)態(tài)卸載的類,從類加載器中卸載失敗");
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        logger.error("動(dòng)態(tài)卸載的類,從類加載器中卸載失敗");
        e.printStackTrace();
    }
    logger.error("{} 動(dòng)態(tài)卸載成功", fileName);

}

4、動(dòng)態(tài)配置

使用動(dòng)態(tài)加載時(shí),為了避免服務(wù)重新啟動(dòng)后丟失已加載的任務(wù)包,使用動(dòng)態(tài)配置的方式,加載后動(dòng)態(tài)更新初始化加載配置。

以下提供了兩種自己實(shí)際操作過(guò)的配置方式。

1.動(dòng)態(tài)修改本地yml

動(dòng)態(tài)修改本地yml配置文件,需要添加snakeyaml的依賴

依賴引入

<dependency>
<groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.29</version>
</dependency>

工具類

讀取指定路徑下的配置文件,并進(jìn)行修改。

/**
 * 用于動(dòng)態(tài)修改bootstrap.yml配置文件
 * @author lijianyu
 * @date 2023/04/18 17:57
 **/
@Component
publicclassConfigUpdater{

    publicvoidupdateLoadJars(List<String> jarNames)throws IOException {
        // 讀取bootstrap.yml
        Yaml yaml = new Yaml();
        InputStream inputStream = new FileInputStream(new File("src/main/resources/bootstrap.yml"));
        Map<String, Object> obj = yaml.load(inputStream);
        inputStream.close();

        obj.put("loadjars", jarNames);

        // 修改
        FileWriter writer = new FileWriter(new File("src/main/resources/bootstrap.yml"));
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        options.setPrettyFlow(true);
        Yaml yamlWriter = new Yaml(options);
        yamlWriter.dump(obj, writer);
    }
}

2.動(dòng)態(tài)修改nacos配置

Spring Cloud Alibaba Nacos組件完全支持在運(yùn)行時(shí)通過(guò)代碼動(dòng)態(tài)修改配置,還提供了一些API供開發(fā)者在代碼里面實(shí)現(xiàn)動(dòng)態(tài)修改配置。在每次動(dòng)態(tài)加載或卸載數(shù)據(jù)治理任務(wù)jar包時(shí),執(zhí)行成功后都會(huì)進(jìn)行動(dòng)態(tài)更新nacos配置。

@Configuration
publicclassNacosConfig{
    @Value("${spring.cloud.nacos.server-addr}")
    private String serverAddr;

    @Value("${spring.cloud.nacos.config.namespace}")
    private String namespace;

    public ConfigService configService()throws NacosException {
        Properties properties = new Properties();
        properties.put("serverAddr", serverAddr);
        properties.put("namespace", namespace);
        return NacosFactory.createConfigService(properties);
    }
}
/**
 * nacos配置中,修改sjzl-loadjars.yml
 *
 * @author lijianyu
 * @date 2023/04/19 17:59
 **/
@Component
publicclassNacosConfigUtil{

    privatestatic Logger logger = LoggerFactory.getLogger(NacosConfigUtil.class);

    @Autowired
    private NacosConfig nacosConfig;

    private String dataId = "sjzl-loadjars.yml";

    @Value("${spring.cloud.nacos.config.group}")
    private String group;

    /**
     * 從nacos配置文件中,添加初始化jar包配置
     * @param jarName 要移除的jar包名
     * @throws Exception
     */
    publicvoidaddJarName(String jarName)throws Exception {
        ConfigService configService = nacosConfig.configService();
        String content = configService.getConfig(dataId, group, 5000);
        // 修改配置文件內(nèi)容
        YAMLMapper yamlMapper = new YAMLMapper();
        ObjectMapper jsonMapper = new ObjectMapper();
        Object yamlObject = yamlMapper.readValue(content, Object.class);

        String jsonString = jsonMapper.writeValueAsString(yamlObject);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        List<String> loadjars;
        if (jsonObject.containsKey("loadjars")) {
            loadjars = (List<String>) jsonObject.get("loadjars");
        }else{
            loadjars = new ArrayList<>();
        }
        if (!loadjars.contains(jarName)) {
            loadjars.add(jarName);
        }
        jsonObject.put("loadjars" , loadjars);

        Object yaml = yamlMapper.readValue(jsonMapper.writeValueAsString(jsonObject), Object.class);
        String newYamlString = yamlMapper.writeValueAsString(yaml);
        boolean b = configService.publishConfig(dataId, group, newYamlString);

        if(b){
            logger.info("nacos配置更新成功");
        }else{
            logger.info("nacos配置更新失敗");
        }
    }
}

三、分離打包

分離打包時(shí),根據(jù)實(shí)際情況在pom.xml中修改以下配置

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <includes>
                                    <include>com/jy/job/demo/**</include>
                                </includes>
                            </filter>
                        </filters>
                        <finalName>demoJob</finalName>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

到此這篇關(guān)于springBoot中動(dòng)態(tài)加載jar包的完整指南的文章就介紹到這了,更多相關(guān)springBoot動(dòng)態(tài)加載jar包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis-Plus內(nèi)置接口方法的具體使用

    MyBatis-Plus內(nèi)置接口方法的具體使用

    java開發(fā)應(yīng)用程序與數(shù)據(jù)庫(kù)交互使用比較多的就是mybatisPlus接口,本文主要介紹了MyBatis-Plus內(nèi)置接口方法的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • nacos2.3.0實(shí)現(xiàn)接入pgsql或其他數(shù)據(jù)庫(kù)

    nacos2.3.0實(shí)現(xiàn)接入pgsql或其他數(shù)據(jù)庫(kù)

    這篇文章主要介紹了nacos2.3.0實(shí)現(xiàn)接入pgsql或其他數(shù)據(jù)庫(kù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2026-03-03
  • flyway實(shí)現(xiàn)java 自動(dòng)升級(jí)SQL腳本的問(wèn)題及解決方法

    flyway實(shí)現(xiàn)java 自動(dòng)升級(jí)SQL腳本的問(wèn)題及解決方法

    大家在平時(shí)開發(fā)自己寫SQL語(yǔ)句忘記在所有環(huán)境執(zhí)行,需要新增環(huán)境做數(shù)據(jù)遷移,那么遇到這樣的問(wèn)題該如何解決呢?本文通過(guò)場(chǎng)景分析給大家介紹java 自動(dòng)升級(jí)SQL腳本的策略,感興趣的朋友一起看看吧
    2021-07-07
  • 使用Java將Excel中的數(shù)字轉(zhuǎn)換為文本或?qū)⑽谋拘蛿?shù)字轉(zhuǎn)換為數(shù)字

    使用Java將Excel中的數(shù)字轉(zhuǎn)換為文本或?qū)⑽谋拘蛿?shù)字轉(zhuǎn)換為數(shù)字

    在 Excel 中,數(shù)字有時(shí)會(huì)以文本的形式存儲(chǔ),這可能會(huì)影響數(shù)據(jù)的計(jì)算、排序和處理,無(wú)論是將數(shù)字轉(zhuǎn)換為文本,還是將文本型數(shù)字轉(zhuǎn)換為數(shù)字,這兩種操作在處理 Excel 數(shù)據(jù)時(shí)都非常常見且重要,本文將介紹如何使用 Java 完成這兩個(gè)任務(wù),需要的朋友可以參考下
    2025-12-12
  • Kibana的安裝和配置全過(guò)程

    Kibana的安裝和配置全過(guò)程

    Kibana是一個(gè)開源的數(shù)據(jù)分析和可視化平臺(tái),它與Elasticsearch緊密集成,提供了一個(gè)直觀的Web界面,使您可以快速地搜索、分析和可視化數(shù)據(jù),在本文中,我們將介紹如何安裝和配置Kibana
    2024-12-12
  • 淺談java 中equals和==的區(qū)別

    淺談java 中equals和==的區(qū)別

    這篇文章主要介紹了java 中equals和==的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • IDEA多Module設(shè)置language level默認(rèn)級(jí)別方式

    IDEA多Module設(shè)置language level默認(rèn)級(jí)別方式

    文章介紹了在Java項(xiàng)目中遇到編譯錯(cuò)誤,源發(fā)行版8需要目標(biāo)發(fā)行版1.8的問(wèn)題,并提供了兩種解決方案:通過(guò)在出現(xiàn)問(wèn)題的module的pom文件中加入特定代碼,或者修改maven的setting.xml文件來(lái)全局設(shè)置languagelevel,作者為解決這個(gè)問(wèn)題提供了個(gè)人經(jīng)驗(yàn),并鼓勵(lì)讀者參考和支持
    2025-12-12
  • java如何根據(jù)用戶請(qǐng)求獲取ip地址并解析省市信息

    java如何根據(jù)用戶請(qǐng)求獲取ip地址并解析省市信息

    根據(jù)當(dāng)前用戶本地IP地址,查詢IP地址庫(kù),獲取IP所在的省市信息,目前有多種方式實(shí)現(xiàn)該功能,這篇文章主要給大家介紹了關(guān)于java如何根據(jù)用戶請(qǐng)求獲取ip地址并解析省市信息的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • 一文帶你回顧Java中的垃圾回收機(jī)制

    一文帶你回顧Java中的垃圾回收機(jī)制

    這篇文章主要給大家介紹了關(guān)于Java中垃圾回收機(jī)制的相關(guān)資料, Java 程序,內(nèi)存是托管于 JVM 的,即對(duì)象的創(chuàng)建和內(nèi)存的回收都是由 JVM 自行完成的,開發(fā)人員是無(wú)權(quán)干涉的,只能盡量去優(yōu)化,需要的朋友可以參考下
    2021-08-08
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之校園一卡通系統(tǒng)的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之校園一卡通系統(tǒng)的實(shí)現(xiàn)

    這是一個(gè)使用了java+Springboot+Maven+mybatis+Vue+mysql+wd開發(fā)的校園一卡通系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有校園一卡通系統(tǒng)該有的所有功能,感興趣的朋友快來(lái)看看吧
    2022-01-01

最新評(píng)論

大英县| 正阳县| 定远县| 慈溪市| 大同市| 澄迈县| 浑源县| 株洲县| 襄樊市| 邓州市| 华池县| 大竹县| 青浦区| 会东县| 富川| 荃湾区| 高要市| 仙桃市| 淳化县| 政和县| 富顺县| 无棣县| 吴桥县| 伊吾县| 东阿县| 吉木萨尔县| 金川县| 张家港市| 广德县| 钟祥市| 屏山县| 普陀区| 临潭县| 加查县| 颍上县| 禹州市| 凤台县| 洛浦县| SHOW| 沙坪坝区| 雷山县|