Spring Cloud(十三):Spring 扩展

news2024/11/18 5:53:15
  • Spring扩展点
    • Bean的生命周期中的BeanPostProcessor扩展点
    • Spring扩展点梳理
  • Spring扩展点应用场景
    • 整合Nacos 服务注册
      • ApplicationListener扩展场景——监听容器中发布的事件
      • Lifecycle Nacos 发布订阅 & Eureka 服务启动、同步、剔除
      • Lifecycle扩展场景——管理具有启动、停止生命周期需求的对象
    • 整合Nacos 发布订阅 NacosWatch
    • 整合Eureka 注册
      • 扩展: Eureka Server端上下文的初始化是在SmartLifecycle#start中实现的
    • 整合Ribbon
      • SmartInitializingSingleton扩展场景—— 对容器中的Bean对象进行定制处理
    • 整合Feign
      • FactoryBean的扩展场景——将接口生成的代理对象交给Spring管理
    • 整合sentinel
      • HandlerInterceptor扩展场景——对mvc请求增强
      • SmartInitializingSingleton&FactoryBean结合场景——根据类型动态装配对象
    • 整合seata
      • AbstractAutoProxyCreator&MethodInterceptor结合场景——实现方法增强

Spring扩展点

Bean的生命周期中的BeanPostProcessor扩展点

  1. bean create before
    resolveBeforeInstantiation(beanName, mbdToUse); => InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(beanClass, beanName);

  2. bean instance before
    determineConstructorsFromBeanPostProcessors(beanClass, beanName); => SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors(beanClass, beanName); @Autowired 构造器

  3. bean instance after

    • bean instance after merge bean query
      applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); => MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(mbd, beanType, beanName);

      1. AutowiredAnnotationBeanPostProcessor @Autowired @Value
      2. CommonAnnotationBeanPostProcessor @Resource @PostConstruct @PreDestroy
    • bean instance after earlybean
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); => SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference(exposedObject, beanName);

  4. bean field setting
    属性填充 populateBean(beanName, mbd, instanceWrapper);

    • 属性填充 before => InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)
    • 属性填充 after => field属性 和 setter方式
      InstantiationAwareBeanPostProcessor.postProcessProperties(pvs, bw.getWrappedInstance(), beanName)
      InstantiationAwareBeanPostProcessor.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  5. bean initialize

    • bean initialize before
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); =>

      1. InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(result, beanName); initmethod @PostConstruct
      2. ApplicationContextAwareProcessor.postProcessBeforeInitialization(result, beanName); Aware: ApplicationContextAware、ApplicationEventPublisherAware、EnvironmentAware
    • bean initialize before
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); =>

      1. AbstractAutoProxyCreator.postProcessAfterInitialization(result, beanName); AOP (wrapIfNecessary->createAopProxy().getProxy(classLoader); Cglib/Jdk)
    • bean initialize register distroy
      registerDisposableBeanIfNecessary(beanName, bean, mbd); => DestructionAwareBeanPostProcessor

  6. bean create after
    destroySingleton(beanName) => DestructionAwareBeanPostProcessor#postProcessBeforeDestruction(this.bean, this.beanName);

Spring扩展点梳理

  • BeanFactoryPostProcessor
    • BeanDefinitionRegistryPostProcessor
      • postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) # 注册Bean 定义
  • BeanPostProcessor
    • InstantiationAwareBeanPostProcessor
      • postProcessBeforeInstantiation
      • postProcessAfterInstantiation
      • postProcessProperties
      • postProcessPropertyValues
    • AbstractAutoProxyCreator
      • postProcessAfterInitialization # 实例化之后AOP支持
  • @Import
    • ImportBeanDefinitionRegistrar
      • registerBeanDefinitions
    • ImportSelector
      • String[] selectImports(AnnotationMetadata importingClassMetadata)
      • default Predicate getExclusionFilter() { return null;}
  • Aware
    • ApplicationContextAware
      • setApplicationContext(ApplicationContext applicationContext)
    • BeanFactoryAware
      • setBeanFactory(BeanFactory beanFactory)
  • InitializingBean || @PostConstruct
  • FactoryBean (动态创建Bean)(&beanName factoryBean.getObject | beanName beanFactory.getBean)(Mybatis#mapper、Openfeign)
    • T getObject() throws Exception;
    • Class<?> getObjectType();
    • default boolean isSingleton() { return true; }
  • SmartInitializingSingleton Bean
    • void afterSingletonsInstantiated(); # 初始化之后调用 过滤器…
  • ApplicationListener
    • void onApplicationEvent(E event);
  • Lifecycle
    • SmartLifecycle
      • default boolean isAutoStartup() { return true; }
      • default void stop(Runnable callback)
    • LifecycleProcessor
  • HandlerInterceptor
    • default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    • default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
    • default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception
  • MethodInterceptor
    • Object invoke(MethodInvocation invocation) throws Throwable;

Spring扩展点应用场景

整合Nacos 服务注册

ApplicationListener扩展场景——监听容器中发布的事件

NamingService -> NacosNamingService => registerInstance

思考: 为什么整合Nacos注册中心后,服务启动就会自动注册,Nacos是如何实现自动服务注册的?

  1. Tomcat启动之后, 在ServletWebServerApplicationContext中,发布事件 ServletWebServerInitializedEvent

  2. spring-cloud-commons 包 AbstractAutoServiceRegistration 监听 WebServerInitializedEvent

public abstract class AbstractAutoServiceRegistration<R extends Registration>
		implements AutoServiceRegistration, ApplicationContextAware,
		ApplicationListener<WebServerInitializedEvent> {

	public void onApplicationEvent(WebServerInitializedEvent event) {
		bind(event); // .... register();
	}
}
  1. Nacos 实现ServiceRegistry.register

Lifecycle Nacos 发布订阅 & Eureka 服务启动、同步、剔除

Lifecycle扩展场景——管理具有启动、停止生命周期需求的对象

start => AbstractApplicationContext.refresh -> finishRefresh() -> getLifecycleProcessor().onRefresh(); -> start()

整合Nacos 发布订阅 NacosWatch

public class NacosWatch
		implements ApplicationEventPublisherAware, SmartLifecycle, DisposableBean {


	@Override
	public void start() {
			...
			NamingService namingService = nacosServiceManager
					.getNamingService(properties.getNacosProperties());
			try {
				namingService.subscribe(properties.getService(), properties.getGroup(),
						Arrays.asList(properties.getClusterName()), eventListener);
			}
			catch (Exception e) {
				log.error("namingService subscribe failed, properties:{}", properties, e);
			}

			this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
					this::nacosServicesWatch, this.properties.getWatchDelay());
		}
	}

}

整合Eureka 注册

扩展: Eureka Server端上下文的初始化是在SmartLifecycle#start中实现的

EurekaServerInitializerConfiguration

整合Ribbon

SmartInitializingSingleton扩展场景—— 对容器中的Bean对象进行定制处理

所有的单例bean实例化之后调用

思考:为什么@Bean修饰的RestTemplate加上@LoadBalanced就能实现负载均衡功能?

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

LoadBalancerAutoConfiguration
对SmartInitializingSingleton的扩展,为所有用@LoadBalanced修饰的restTemplate(利用了@Qualifier 限定符)绑定实现了负载均衡逻辑的拦截器LoadBalancerInterceptor

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();

@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
		final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
	return () -> restTemplateCustomizers.ifAvailable(customizers -> {
		for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
			for (RestTemplateCustomizer customizer : customizers) {
				customizer.customize(restTemplate);
			}
		}
	});
}
/**
 * Annotation to mark a RestTemplate or WebClient bean to be configured to use a
 * LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier //Qualifier
public @interface LoadBalanced {
}

LoadBalancerInterceptor

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {

		@Bean
		public LoadBalancerInterceptor loadBalancerInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}

		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
				List<ClientHttpRequestInterceptor> list = new ArrayList<>(
						restTemplate.getInterceptors());
				list.add(loadBalancerInterceptor);
				restTemplate.setInterceptors(list);
			};
		}

	}

整合Feign

FactoryBean的扩展场景——将接口生成的代理对象交给Spring管理

思考:为什么Feign接口可以通过@Autowired直接注入使用?Feign接口是如何交给Spring管理的?

@FeignClient(value = "order-service", path = "/order")
public interface OrderFeignService {

    @GetMapping(value = "/info/{productId}")
    public String findOrderInfoByProductId(@PathVariable("productId") Integer productId);
}
@SpringBootApplication
@EnableFeignClients(basePackages = "com.mx.use.feign")
@EnableHystrix
@EnableHystrixDashboard //开启 Hystrix 监控功能
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
	...
}

FactoryBean => FeignClientsRegistrar -> scan(FeignClient) -> registerFeignClient -> FeignClientFactoryBean

在这里插入图片描述

@Override
public Object getObject() {
	return getTarget(); //
}

整合sentinel

HandlerInterceptor扩展场景——对mvc请求增强

AbstractSentinelInterceptor#preHandle

public abstract class AbstractSentinelInterceptor implements HandlerInterceptor {
    ...
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        try {
            String resourceName = getResourceName(request);

            if (StringUtil.isEmpty(resourceName)) {
                return true;
            }
            
            if (increaseReferece(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) {
                return true;
            }
            
            // Parse the request origin using registered origin parser.
            String origin = parseOrigin(request);
            String contextName = getContextName(request);
            ContextUtil.enter(contextName, origin);
            //Sentinel入口
            Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
            request.setAttribute(baseWebMvcConfig.getRequestAttributeName(), entry);
            return true;
        } catch (BlockException e) {
            try {
                handleBlockException(request, response, e);
            } finally {
                ContextUtil.exit();
            }
            return false;
        }
    }
    ...
}

SmartInitializingSingleton&FactoryBean结合场景——根据类型动态装配对象

SentinelDataSourceHandler

#Sentinel持久化读数据源设计,利用了SmartInitializingSingleton扩展点
SentinelDataSourceHandler#afterSingletonsInstantiated
# 注册一个FactoryBean类型的数据源 
》SentinelDataSourceHandler#registerBean
》》NacosDataSourceFactoryBean#getObject
# 利用FactoryBean获取到读数据源
》》new NacosDataSource(properties, groupId, dataId, converter)

NacosDataSourceFactoryBean

public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
	...
	@Override
	public NacosDataSource getObject() throws Exception {
		...
		return new NacosDataSource(properties, groupId, dataId, converter);
	}
	...
}

SentinelDataSourceHandler

public class SentinelDataSourceHandler implements SmartInitializingSingleton {
	...
	@Override
	public void afterSingletonsInstantiated() {
		...
		//sentinel.nacos.config.serverAddr=${sentinel.nacos.config.serverAddr}
		//NacosDataSource
		AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties.getValidDataSourceProperties();
		abstractDataSourceProperties.setEnv(env);
		abstractDataSourceProperties.preCheck(dataSourceName);
		registerBean(abstractDataSourceProperties, dataSourceName+ "-sentinel-" + validFields.get(0) + "-datasource"); //NacosDataSource
		...
	}
	...
}

整合seata (Spring Aop)

AbstractAutoProxyCreator&MethodInterceptor结合场景——实现方法增强

GlobalTransactionScanner

在这里插入图片描述

GlobalTransactionalInterceptor

在这里插入图片描述

public class GlobalTransactionalInterceptor implements ConfigurationChangeListener, MethodInterceptor, SeataInterceptor {
	...

    @Override
    public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
        Class<?> targetClass =
            methodInvocation.getThis() != null ? AopUtils.getTargetClass(methodInvocation.getThis()) : null;
        Method specificMethod = ClassUtils.getMostSpecificMethod(methodInvocation.getMethod(), targetClass);
        if (specificMethod != null && !specificMethod.getDeclaringClass().equals(Object.class)) {
            final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
            final GlobalTransactional globalTransactionalAnnotation =
                getAnnotation(method, targetClass, GlobalTransactional.class);
            final GlobalLock globalLockAnnotation = getAnnotation(method, targetClass, GlobalLock.class);
            boolean localDisable = disable || (degradeCheck && degradeNum >= degradeCheckAllowTimes);
            if (!localDisable) {
                if (globalTransactionalAnnotation != null || this.aspectTransactional != null) {
                    AspectTransactional transactional;
                    if (globalTransactionalAnnotation != null) {
                        transactional = new AspectTransactional(globalTransactionalAnnotation.timeoutMills(),
                            globalTransactionalAnnotation.name(), globalTransactionalAnnotation.rollbackFor(),
                            globalTransactionalAnnotation.noRollbackForClassName(),
                            globalTransactionalAnnotation.noRollbackFor(),
                            globalTransactionalAnnotation.noRollbackForClassName(),
                            globalTransactionalAnnotation.propagation(),
                            globalTransactionalAnnotation.lockRetryInterval(),
                            globalTransactionalAnnotation.lockRetryTimes());
                    } else {
                        transactional = this.aspectTransactional;
                    }
                    // 执行事务 transactionalTemplate.execute()
                    return handleGlobalTransaction(methodInvocation, transactional);
                } else if (globalLockAnnotation != null) {
                    return handleGlobalLock(methodInvocation, globalLockAnnotation);
                }
            }
        }
        return methodInvocation.proceed();
    }
	...
}
public class TransactionalTemplate {
    public Object execute(TransactionalExecutor business) throws Throwable {
        // 1. Get transactionInfo
        TransactionInfo txInfo = business.getTransactionInfo();
        if (txInfo == null) {
            throw new ShouldNeverHappenException("transactionInfo does not exist");
        }
        // 1.1 Get current transaction, if not null, the tx role is 'GlobalTransactionRole.Participant'.
        GlobalTransaction tx = GlobalTransactionContext.getCurrent();

        // 1.2 Handle the transaction propagation.
        Propagation propagation = txInfo.getPropagation();
        SuspendedResourcesHolder suspendedResourcesHolder = null;
        try {
            switch (propagation) {
                case NOT_SUPPORTED:
                    // If transaction is existing, suspend it.
                    if (existingTransaction(tx)) {
                        suspendedResourcesHolder = tx.suspend();
                    }
                    // Execute without transaction and return.
                    return business.execute();
                case REQUIRES_NEW:
                    // If transaction is existing, suspend it, and then begin new transaction.
                    if (existingTransaction(tx)) {
                        suspendedResourcesHolder = tx.suspend();
                        tx = GlobalTransactionContext.createNew();
                    }
                    // Continue and execute with new transaction
                    break;
                case SUPPORTS:
                    // If transaction is not existing, execute without transaction.
                    if (notExistingTransaction(tx)) {
                        return business.execute();
                    }
                    // Continue and execute with new transaction
                    break;
                case REQUIRED:
                    // If current transaction is existing, execute with current transaction,
                    // else continue and execute with new transaction.
                    break;
                case NEVER:
                    // If transaction is existing, throw exception.
                    if (existingTransaction(tx)) {
                        throw new TransactionException(
                            String.format("Existing transaction found for transaction marked with propagation 'never', xid = %s"
                                    , tx.getXid()));
                    } else {
                        // Execute without transaction and return.
                        return business.execute();
                    }
                case MANDATORY:
                    // If transaction is not existing, throw exception.
                    if (notExistingTransaction(tx)) {
                        throw new TransactionException("No existing transaction found for transaction marked with propagation 'mandatory'");
                    }
                    // Continue and execute with current transaction.
                    break;
                default:
                    throw new TransactionException("Not Supported Propagation:" + propagation);
            }

            // 1.3 If null, create new transaction with role 'GlobalTransactionRole.Launcher'.
            if (tx == null) {
                tx = GlobalTransactionContext.createNew();
            }

            // set current tx config to holder
            GlobalLockConfig previousConfig = replaceGlobalLockConfig(txInfo);

            try {
                // 2. If the tx role is 'GlobalTransactionRole.Launcher', send the request of beginTransaction to TC,
                //    else do nothing. Of course, the hooks will still be triggered.
                beginTransaction(txInfo, tx);

                Object rs;
                try {
                    // Do Your Business
                    rs = business.execute();
                } catch (Throwable ex) {
                    // 3. The needed business exception to rollback.
                    completeTransactionAfterThrowing(txInfo, tx, ex);
                    throw ex;
                }

                // 4. everything is fine, commit.
                commitTransaction(tx);

                return rs;
            } finally {
                //5. clear
                resumeGlobalLockConfig(previousConfig);
                triggerAfterCompletion();
                cleanUp();
            }
        } finally {
            // If the transaction is suspended, resume it.
            if (suspendedResourcesHolder != null) {
                tx.resume(suspendedResourcesHolder);
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JSP快速入门

目录 1、jsp简述 2、JSP快速入门 2.1、搭建环境 2.2、导入JSP页面 2.3、编写代码 2.4、启动测试 3、JSP原理 4、JSP脚本 4.1、JSP脚本的分类 4.2、案例 4.2.1、需求 4.2.2、实现 ​编辑 4.2.3、测试 ​编辑4.3、JSP缺点 5、JSP语法 5.1、JSP页面的基本结构…

【每日一题Day36】LC1742盒子中小球的最大数量 | 哈希表 找规律

盒子中小球的最大数量【LC1742】 You are working in a ball factory where you have n balls numbered from lowLimit up to highLimit inclusive (i.e., n highLimit - lowLimit 1), and an infinite number of boxes numbered from 1 to infinity. Your job at this facto…

[附源码]java毕业设计养老院管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C++ 语言学习 day10 复习(2)

1.友元 的三种形式 /*********** 友元 ************ * ①全局函数做友元 * ②类做友元 * ③类成员函数做友元 * **************************/ 代码&#xff1a; #include <iostream> #include <string> using namespace std;/* ③类函数友元 : 程序规则{ 自上…

Charles下载抓包基本流程

一、Charles官网下载链接&#xff1a; https://www.charlesproxy.com/download/ 二、抓包步骤&#xff1a; 1、安装Charles&#xff0c;并打开 2、电脑设置代理端口&#xff1a; 打开charles->Proxy->Proxy Settings,设置代理端口&#xff0c;如图所示 3、手机设置代…

Day10--配置uni-app的开发环境

1.啥子是ui-app呢&#xff1f; 1》官方介绍&#xff1a; 2》博主介绍 ************************************************************************************************************** 2.开发工具建议使用HBuilder X *************************************************…

BSA/HSA表面修饰二甘醇酐,人血清白蛋白HSA、牛血清白蛋白BSA偶联二甘醇酐

BSA作用&#xff1a; BSA一般做为稳定剂被用于限制酶或者修饰酶的保存溶液和反应液中&#xff0c;因为有些酶在低浓度下不稳定或活性低。加入BSA后&#xff0c;它可能起到“保护”或“载体”作用&#xff0c;不少酶类添加 BSA后能使其活性大幅度提高。不需要加BSA的酶加入BSA一…

【时序预测-SVM】基于鲸鱼算法优化支持向量机SVM实现时序数据预测附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

【数据结构】二叉树详解(上篇)

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《数据结构》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 二叉树&…

18 【Redux Toolkit】

18 【Redux Toolkit】 上边的案例我们一直在使用Redux核心库来使用Redux&#xff0c;除了Redux核心库外Redux还为我们提供了一种使用Redux的方式——Redux Toolkit。它的名字起的非常直白&#xff0c;Redux工具包&#xff0c;简称RTK。RTK可以帮助我们处理使用Redux过程中的重…

ABTest样本量计算

A/B 测试一般是比较实验组和对照组在某些指标上是否存在差异&#xff0c;当然更多时候是看实验组相比对照组某个指标表现是否更好。 这样的对比在统计学上叫做两样本假设检验&#xff0c;即实验组和对照组为两样本&#xff0c;假设检验的原假设Ho&#xff1a;实验组和对照组无…

Springboot 整合 JWT + Redis 实现双Token 校验Demo(简单实现)

一、新建一个SpringBoot 项目&#xff0c;springboot项目创建过程详见 mac idea 创建 springboot 项目_JAVA&#xff24;WangJing的博客-CSDN博客_mac idea创建springboot项目 二、SpringBoot 整合使用 Rdis SpringBoot 项目 添加 redis配置_JAVA&#xff24;WangJing的博客…

Linux内存映射函数mmap与匿名内存块

学习系列&#xff1a;《APUE14.8》《CSAPP9.8.4》 1 总结 memory-mapped io可以将文件映射到内存中的buffer&#xff0c;当我们从buffer读写数据时&#xff0c;其实操作的是对应文件中的数据。这样可以达到不使用READ/WRITE的IO操作。mmap也可以直接映射匿名内存块&#xff0c…

零信任对企业安全防护能起到什么作用?

随着网络攻击的不断演变&#xff0c;变得更加普遍和复杂&#xff0c;企业正在寻找一种基于身份的网络安全新方法。这些策略和解决方案旨在保护企业内的所有人和机器&#xff0c;并用于检测和防止身份驱动的违规行为。 企业很容易被感染&#xff0c;但问题在于如何找到解决方案。…

基于花朵授粉算法的无线传感器网络部署优化附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

hadoop集群安装(二):克隆服务器集群并免密

文章目录说明分享集群构建集群规划角色划分配置主机名、ip和主机名映射ssh免密总结说明 已 上篇 创建模型虚拟机为基础构建hadoop集群 分享 大数据博客列表开发记录汇总个人java工具库 项目https://gitee.com/wangzonghui/object-tool 包含json、string、集合、excel、zip压缩…

美食杰项目 -- 个人主页(四)

目录前言&#xff1a;具体实现思路&#xff1a;步骤&#xff1a;1. 展示美食杰菜谱大全效果2. 引入element-ui3. 代码总结&#xff1a;前言&#xff1a; 本文给大家讲解&#xff0c;美食杰项目中 实现个人主页的效果&#xff0c;和具体代码。 具体实现思路&#xff1a; 判断是…

如何复用ijkplayer库实现ffmpeg的功能

ijkplayer库介绍 现在ijkplayer播放器应用的非常广泛&#xff0c;很多播放器基本上都是基于ijkplayer二次迭代开发的&#xff0c;众所周知&#xff0c;ijkplayer是基于ffplay的&#xff0c;所以要使用ijkplayer&#xff0c;就必须使用三个so库。 jeffmonyJeffMonydeMacBook-P…

MySQL Server 和 MySQL Workbench安装

对于开发人员来说&#xff0c;只需要安装 MySQL Server 和 MySQL Workbench 这两个软件&#xff0c;就能满足开发的需要了。 ⚫ MySQL Server&#xff1a;专门用来提供数据存储和服务的软件。 ⚫ MySQL Workbench&#xff1a;可视化的 MySQL 管理工具&#xff0c;通过它&#…

会议信息管理系统SSM记录(四)

目录&#xff1a; &#xff08;1&#xff09;部门管理&#xff1a;查询-添加-删除 &#xff08;2&#xff09;部门管理&#xff1a;修改 &#xff08;1&#xff09;部门管理&#xff1a;查询-添加-删除 在DepartmentController中添加方法&#xff1a; 这里getAllDeps方法上篇…