超实用的Spring bean工具类

2023-10-31

在这里插入图片描述

1、背景

我们在项目开发过程中,可能会遇到下面的场景:

(1)想在工具类中调用一个http接口请求数据,然后再调用spring容器中托管的service将请求结果保存到数据库

(2)想在工具类中使用spring容器中的环境变量(属性)信息

(3)在spring容器托管的service中只有一个方法需要调用另一个被spring容器托管的service

针对上面的场景,大伙一般会怎么处理呢?是不是也会像下面这样去处理?

/**
* 工具类
*/
@Component
public class AppUtil {
    
    @Autowired
    private OperateService operateService;
    // 注入spring容器中的属性信息
    @Value("${url")
    private String url;

    //调用外部接口并将信息入库
    public static boolean operate(){
        //业务。。。。
        URL url = new URL(url);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        .....
        ....
        //请求结果入库
        operateService.save(...);
    }
}
@Service
public class AppService{

    @Autowired
    private OperateService operateService;
    // 注入spring容器中的recordService实例
    @Autowired
    private RecordService recordService;

    //只有本方法会用到recordService
    public static boolean record(){
        //业务。。。。
        ....
        recordService.record(..);
    }
    ...
    其他方法
    ...
}

上面的方法虽然能解决问题,但是还是有些弊端的。比如:

(1)针对前两种场景,如果在工具类中使用spring容器中托管的信息(bean实例或属性配置信息),那么就要把工具类本身也要被spring容器托管,这样才能在工具类中注入bean实例或者一些属性配置信息。如果有一个工具类还好,那如果有多个呢?而且作为一个工具类,我们使用该工具类时都是直接调用工具类中的静态方法,虽然它(工具类)被托管在了spring容器中,但是并不会有别的bean实例来调用这个工具类对应的bean实例,因此这些工具类对应的bean实例们只会占用内存资源。

(2)针对第三种场景,AppService要依赖RecordService,将RecordService作为AppService类的成员变量而存在,会让人误以为这个变量的重要性很大,虽然它在AppService中只被调用了一次。当然这个也并不是重点。但是如果AppService和RecordService互相依赖,那么这就涉及到spring bean对象的循环依赖问题。考虑到springboot官方自spring boot 2.6.x起,就默认不支持循环依赖了,如果我们再通过这种方式互相注入依赖,也就并不合适了。

其实针对上面的问题,有更合适更优雅的处理办法~

2、功能实现

我们可以利用spring自身的特性,编写一个工具类,来帮我们处理以上的场景。实现代码如下:

package com.xk.spring.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * spring应用工具类
 * 可以获取spring容器中的bean实例以及环境变量信息
 * @author xk
 * @since 2023.05.10 8:34
 */
@Component
public class SpringApplicationUtil implements ApplicationContextAware, EnvironmentAware {

    private static ApplicationContext applicationContext;

    private static Environment environment;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringApplicationUtil.applicationContext = applicationContext;
    }

    @Override
    public void setEnvironment(Environment environment) {
        SpringApplicationUtil.environment = environment;
    }

    /**
     * 根据bean的类型从spring容器中获取bean实例
     * @param clazz bean的类型
     * @param <T>
     * @return 指定类型的bean实例
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 根据bean名称和bean的类型从spring容器中获取bean实例
     * @param name bean的名称
     * @param clazz bean的类型
     * @param <T>
     * @return 指定类型的bean实例
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    /**
     * 根据bean的名称从spring容器中获取bean实例
     * @param beanName bean的名称
     * @return
     */
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    /**
     * 判断spring容器中是否有指定bean名称的bean实例
     * @param name bean的名称
     * @return
     */
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }


    /**
     * 根据bean名称从spring容器中获取bean名称对应实例的类型
     * @param name bean的名称
     * @return
     * @throws NoSuchBeanDefinitionException
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getType(name);
    }

    /**
     * 根据配置项key的名称获取对应的配置项的值
     * 比如application.properties配置文件中有 url=www.baidu.com的配置,
     * 则getProperty("url")的值就是www.baidu.com
     * @param key 配置项的名称,比如url
     * @return
     */
    public static String getProperty(String key){
        return environment.getProperty(key);
    }

    /**
     * 根据配置项key的名称获取配置项的值,并将值转换为指定的类型
     * 比如application.properties配置文件中有age=18的配置项
     * 因为age的值是个整数,所以我们可以直接通过本方法获取整数的age值
     * getProperty("age",Integer.class)的结果就是整数18
     * @param key 配置项的名称
     * @param targetType 配置项对应的值的类型
     * @param <T>
     * @return 指定类型的配置项的值
     */
    public static <T> T getProperty(String key,Class<T> targetType) {
        return environment.getProperty(key,targetType);
    }
}

如以上代码所述,我们用工具类实现了ApplicationContextAware,实现这个接口是方便我们操作spring容器中的bean实例。而实现EnvironmentAware接口,是为了方便获取spring容器中的环境变量信息。最后,我们在工具类上面还加了@Component注解,让我们工具类由spring容器托管。针对我们之前的描述场景,我们就可以这么使用:

/**
* 工具类
*/
public class AppUtil {
    
    @Autowired
    private OperateService operateService;
  

    //调用外部接口并将信息入库
    public static boolean operate(){
        //业务。。。。
        //改动的代码
        String url = SpringApplicationUtil.getProperty("url");
        URL url = new URL(url);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        .....
        ....
        //请求结果入库
        operateService.save(...);
    }

}
@Service
public class AppService{

    @Autowired
    private OperateService operateService;


    //只有本方法会用到recordService
    public static boolean record(){
        //业务。。。。
        ....
        //改动的代码
        RecordService recordService = SpringApplicationUtil.getBean(RecordService.class);
        recordService.record(..);
    }
    ...
    其他方法
    ...

}

虽然我们将SpringApplicationUtil工具类托管到了spring容器中,但是我们只需要采用SpringApplicationUtil.getBean()的方式直接调用工具类的静态方法,来获取我们想要的数据。

3、实现原理

为啥这么写SpringApplicationUtil工具类,就能满足我们以上场景的需要了呢?这就得结合spring bean的生命周期和spring BeanPostProcessor的特性来说了。

首先我们要理解,如果我们想编码获取spring容器中的bean对象和环境配置信息,就需要拿到application对象和environment对象。我在之前写的“浅谈spring bean的生命周期”的文章中的2.3部分,提到了“初始化bean”的这一操作。在这一步有如下的描述:

(2)调用所有的BeanPostProcessor对象的postProcessBeforeInitialization方法
​ 获取spring容器中所有的BeanPostProcessor对象,循环执行各个beanPostProcessor的postProcessBeforeInitialization方法,如果出现postProcessBeforeInitialization返回的对象为null,则终止循环,返回上一个postProcessBeforeInitialization方法返回的对象,然后进入第(3)步。

(3)调用bean的初始化方法

另外Spring容器中有一个很重要的BeanPostProcessor对象,它就是ApplicationContextAwareProcessor对象,它专门用来为那些实现了EnvironmentAware接口和ApplicationContextAware接口的bean服务,能往这些bean中注入application对象和environment对象。它的实现如下(以spring 5.3.20版本为例):

class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}


	@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

}

可以看到,当初始化bean的时候,ApplicationContextAwareProcessor的postProcessBeforeInitialization方法就会被调用。

如果bean实现了EnvironmentAware接口,就会调用bean的setEnvironment方法,那么就会执行下面这行:

((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());

bean对象中的Environment类型的成员变量就有值了。

而如果bean实现了ApplicationContextAware接口,就会调用bean的setApplicationContext方法,也就会执行下面这行,

if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware)        bean).setApplicationContext(this.applicationContext);
 }

此时bean对象中的ApplicationContext类型的成员变量就有值了。

当然,前提是我们的bean对象(所属的类)中定义了ApplicationContext类型的成员变量和Environment类型的成员变量,而且要分别在setApplicationContext和setEnvironment方法中对它们赋值才行。另外,最重要的一点是:我们讲的是spring bean的初始化,那我们的SpringApplicationUtil工具类就要被托管(注册)到spring容器中才行,这也就是为什么在SpringApplicationUtil类上面加上@Component注解的原因,就是为了将工具类标记为spring的一个组件(记得要确保该组件能被spring识别)。当然啦,我们在配置类中使用@Bean的方式将工具类托管(注册)到spring容器中也是可以的。

4、知识补充

前面我们提到了ApplicationContextAwareProcessor这个后置处理器,spring容器初始化bean的时候,会从容器中拿到它来执行它内部的方法,那么它是什么时候被注入到spring容器中的呢?

我们再来看下spring容器启动过程中会调用到的AbstractApplicationContext.refresh方法,实现如下:

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}
			//省略后面的代码
			....
		}
	}

里面会调用prepareBeanFactory方法,我们来看下它内部实现:

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		//就是这里,ApplicationContextAwareProcessor对象被加到了bean工厂,后面初始化bean时会使用
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		//省略后面的代码
		。。。。。
	}

另外,refresh方法内部还调用了一个registerBeanPostProcessors(beanFactory);方法,其实这个方法就是对容器中的各种BeanPostProcessor进行一个优先级排序。

结束语

觉得有收获的朋友,麻烦点击下“关注”,或者进行分享或收藏,多谢支持~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

超实用的Spring bean工具类 的相关文章

  • 如何配置 Spring-WS 以使用 JAXB Marshaller?

    感谢您到目前为止对此的帮助 我正在更新问题 因为我没有显示我需要的所有内容 并显示了建议的更改 肥皂输出仍然不是我想要的 servlet xml
  • Java 读取大文本文件时出现 OutOfMemoryError

    我是 Java 新手 正在读取非常大的文件 需要一些帮助来理解问题并解决它 我们有一些遗留代码 必须对其进行优化才能正常运行 文件大小仅在 10mb 到 10gb 之间变化 只有当文件开始大小超过 800mb 时才会出现启动问题 Input
  • 尝试获取屏幕上绘制的每个随机圆圈的 x、y 坐标

    您好 我正在制作一款游戏 该游戏将在屏幕上创建随机圆圈 随机创建的圆圈的值为红色或绿色 我的问题是 我希望不仅能够确定用户何时单击其中一个圆圈 而且还能够确定他们最终单击的圆圈 红色或绿色 下面是我的代码 我的主要问题是试图找到将要绘制的圆
  • javax.persistence.RollbackException:提交事务时出错],根本原因是 java.lang.StackOverflowError:null

    我有一个使用 Spring Data REST 框架的 Spring Boot API 从 spring boot starter parent 2 1 0 RELEASE 继承的依赖项 我正在尝试执行 PUT 或 PATCH 请求来更新实
  • JTextField 和 JTextArea

    JTextField 和 JTextArea 有什么不同 是否可以在一个班级中使用这两个班级 总之 JTextField 是单行文本字段 而 JTextArea 可以跨越多行 文档中清楚地解释了这些差异 文本区 http docs orac
  • 具有 CRUD 功能的基于 Spring Web 的管理工具

    在 PHP Symfony 世界里有一个工具叫 Sonata Adminhttps sonata project org https sonata project org 基于 AdminLTE 模板 这是一款一体化管理工具 具有登录 菜单
  • 使用 JSch 分别为各个提示提供输入

    问题是 SSH 连接需要在常规登录后提供另一个用户 ID 和密码信息 我正在使用 JSch 连接到远程服务器 它接受以下形式的输入InputStream 和这个InputStream只能通过一次 由于会话是交互式的 这会导致问题 我尝试将输
  • 当 JMS Prod 位于辅助 POJO 类中时,如何在事务中包含 JMS Producer

    简短的问题 有没有办法强制无状态 EJB 调用的 POJO 存在于 EJB 的上下文中 以便事务和资源注入可以在 POJO 中工作 具体来说 在我想要做的事情的上下文中 如何在 EJB 的事务中包含 POJO JMS 生产者 该生产者在调用
  • 将现有 eclipse 项目导出到 war 文件时出现“模块名称无效”

    我正在尝试将现有 Eclipse 项目导出到 war 文件 但无论我在 WAR Export 对话框页面中输入什么 系统总是返回 模块名称无效 我不知道如何解决这个问题 谢谢您的帮助 我有同样的问题 我修复了它 请按照以下步骤操作 您可以创
  • 从 HttpClient 3 转换为 4

    我已经成功地对所有内容进行了更改 但以下内容除外 HttpClient client HttpPost method client new DefaultHttpClient method new HttpPost url InputStr
  • 更改 JComboBox 中滚动条的大小

    有谁知道如何手动更改 jComboBox 中的滚动条大小 我已经尝试了一大堆东西 但没有任何效果 好吧 我明白了 您可以实现 PopUpMenuListener 并使用它 public void popupMenuWillBecomeVis
  • 配置jmxremote时无法正常停止tomcat

    我添加了一个jmxremotecatalina bat中的配置 set JAVA OPTS Dcom sun management jmxremote port 9004 Dcom sun management jmxremote ssl
  • 在循环中按名称访问变量

    我正在开发一个 Android 项目 并且有很多可绘制对象 这些绘图的名称都类似于icon 0 png icon 1 png icon 100 png 我想将这些可绘制对象的所有资源 ID 添加到整数 ArrayList 中 对于那些不了解
  • Java和手动执行finalize

    如果我打电话finalize 在我的程序代码中的一个对象上 JVM当垃圾收集器处理这个对象时仍然再次运行该方法吗 这是一个大概的例子 MyObject m new MyObject m finalize m null System gc 是
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • android 中的 java.net.URL ..新手问题

    我是java新手 正在尝试android开发 以下代码生成 malformedURLException 有人可以帮助我识别异常吗 任何提示都会非常有帮助 package com example helloandroid import and
  • java中的预增量/后增量

    有人可以帮助我理解为什么 int i 1 int j 1 int k 1 int l 1 System out println i i System out println j j System out println k k System
  • Spring中什么时候触发ContextRefreshedEvent?

    我知道当 ApplicationContext 完全加载时它会被触发一次 但是之后在运行时怎么办 Refreshed 一词意味着它将在刷新时触发 但我想知道 Spring 是否符合 ApplicationContext 刷新的资格 跟进问题
  • 使用自定义比较器在 Java 中创建 SortedMap

    我想创建一个TreeMap在 Java 中具有自定义排序顺序 排序后的键是字符串 需要根据第二个字符进行排序 这些值也是字符串 示例地图 Za FOO Ab Bar 您可以像这样使用自定义比较器 Comparator
  • java.lang.ClassCastException:com.sun.proxy.$Proxy8 无法转换为 org.openqa.selenium.internal.WrapsDriver

    我有以下切入点和 AspectJ 中给出的建议 Pointcut call org openqa selenium WebElement sendKeys public void onWebElementAction After onWeb

随机推荐

  • Swagger2使用教程

    Swagger 学习目标 了解Swagger的作用和概念 了解前后端分离 在SpringBoot中集成Swagger Swagger简介 前后端分离 现在流行的Vue SpringBoot 后端时代 前端只用管理静态页面 html jsp
  • 12.基于STM32C8T6的四旋翼无人机的飞控制作----电路板焊接方法

    电路板焊接是非常考验手上功夫和经验的一个技术 当然简单的插件元件好焊 但是高级电路板上有LQFP QFP BGA等等封装 很多时候 测试阶段需要手工焊接 下面做下简单总结 后期慢慢配图补齐 1 0805 0603 0402电阻电容焊接 先将
  • 这两款腾讯研发的性能管理工具开放免费试用了

    如何实现专业的游戏性能监控与管理 如何快速定位并解决异常问题 有效降低产品崩溃率 提升产品整体用户体验 由腾讯WeTest打造的性能工具 PerfSight 游戏性能管理平台 和 CrashSight 异常崩溃管理工具 可以帮助开发者解决上
  • 认认真真推荐几个高质量人工智能方向的原创公众号

    当今人工智能方向越来越卷了 系统化学习能够让你高效的利用时间 达到事半功倍的效果 今天给大家推荐9个优质原创公众号 助你在系统化学习的路上一臂之力 机器学习算法那些事 一个百度人的技术提升之路 为您提供一系列计算机视觉 自然语言处理和推荐系
  • stm32项目工程的建立

    1 stm32学习笔记 项目工程的建立 xdearluo的博客 CSDN博客 2 STM32基础入门 一 Keil5新建STM32工程 根号五的博客 CSDN博客 keil5新建stm32工程 3 Stm32 keil5项目创建步骤 西瓜籽
  • RK3288把debug口从uart2修改为uart3步骤

    kernel arch arm mach rockchip rk fiq debugger c 搜索 static int debug port init struct platform device pdev 将该函数内容替换为以下即可
  • SimVODIS++: Neural Semantic Visual Odometry in Dynamic Environments 论文阅读

    论文信息 题目 SimVODIS Neural Semantic Visual Odometry in Dynamic Environments 作者 Ue Hwan Kim Se Ho Kim and Jong Hwan Kim Fell
  • Java线上CPU内存冲高问题排查步骤

    1 引言 作为一名从事Java开发快一年的程序员 在线上经常碰到某个模块的Pod发出CPU与内存告警的问题 而这些问题会导致系统响应缓慢甚至是服务不可用 一般情况下可以通过重启或者调高Pod的资源量或者增加Pod数量暂时解决问题 但这是治标
  • CryptoPP的 AutoSeededX917RNG算法的使用

    AutoSeededX917RNG算法是CryptoPP密码学库提供的又一系列随机数发生器 为什么说其是 一系列 而不是 一个 算法 从CryptoPP的源代码和帮助文档中可以看到 AutoSeededX917RNG是一个类模板 它的类型参
  • STM32 进阶教程 4 - 软件实现高精度延时 2

    前言 软件工程师在在实际项目开发过程中 软件延时想必或多或少都有接触过 诸如delay s x delay ms x delay us x 等类型的延时函数大家也一定见过或自已曾经实现过 本节给大家介绍一种在STM32 MCU平台上实现高精
  • 电子招标采购商城系统:优化传统采购业务,提速企业数字化升级

    后疫情时代 电子元器件供应链发生了巨大的变化 缺货已经影响了大多数企业 电子元器件采购人员每天被 缺货 涨价 的字眼包围着 对电子元器件企业的发展带来了极大的限制 当前 借助数字化技术对电子元器件采购管理业务进行优化升级已是迫在眉睫 企业亟
  • Candies POJ - 3159(差分约束模板题,优先队列优化Dijkstra模板)

    题意 给n个人派糖果 给出m组数据 每组数据包含A B c 三个数 意思是A的糖果数比B少的个数不多于c 即B的糖果数 A的糖果数 lt c 最后求n 比 1 最多多多少糖果 AC代码 include
  • PSOM

    Message type 1 Record message message type message body Close message type 0x00 SetChannel 0x04 Break 0x06 RpcMessage 0x
  • nifi1.17.0的Kerberos证书安装及其使用

    文章目录 一 NiFi1 17 0的集群证书安装 1 环境准备 1 1 三台主机需要的操作 2 搭建Kerberos 2 1 新建租户nifi 2 2 安装kerberos 2 3 设置用户的认证 3 生成证书 3 1 上传并解压安装包 3
  • python解压带密码的压缩文件(非传统压缩)

    python解压带密码的压缩文件 非传统压缩 coding utf 8 auther LyaJpunov data 2020 12 12 这个程序主要用于非传统加密破解 传统加密破解可以使用zipfile或者是rarfile 网上有许多的教
  • OpenHarmony之C/C++编码风格一键格式化

    还在为编码风格调整发愁吗 掌握一键格式化代码 规范编码风格 想必是一个程序员提高工作效率的必修课 在vim中 我们可以在命令模式下输入gg G自动格式化对齐代码 在QtCreator中可以按下ctrl i自动格式化对齐代码 在eclipse
  • align_corner=True/False 的解释

    参考链接 what we should use align corners false 查阅资料的时候发现一张图 如下 代码角度的差别 align corners False x ori is the coordinate in origi
  • 微信小程序-开了调试Vconsole能正常运行,不开调试不能正常运行

    这个微信小程序太奇怪了 做了一点小改动要上线 在本地连接真机调试好好的 上到体验环境手机打开就不行了 而且奇怪 体验版打开调试后又正常了 加载页面的时候报了一个错 in promise MiniProgramError nInvalid a
  • vue antv X6 ER图

    第一 引入antv npm install antv x6 save 第二 写入代码 官网demo的fetch data er json 有问题
  • 超实用的Spring bean工具类

    1 背景 我们在项目开发过程中 可能会遇到下面的场景 1 想在工具类中调用一个http接口请求数据 然后再调用spring容器中托管的service将请求结果保存到数据库 2 想在工具类中使用spring容器中的环境变量 属性 信息 3 在