SpringCloud源码之Spring Cloud Common核心接口说明

news2024/9/21 14:47:22

spring cloud commons

spring cloud提供的通用抽象包,组件的实现基本上都依赖于当前包的接口定义实现功能,下面就是梳理一下当前包中都提供了哪些比较重要的接口

1. 服务注册

1.1 DiscoveryClient

DiscoveryClient 是一个顶级的接口类,用于定义客户端的发现功能

public interface DiscoveryClient extends Ordered {
	/**
	 * 默认的排序
	 */
	int DEFAULT_ORDER = 0;
	/**
	 * 客户端描述
	 */
	String description();
	/**
	 * 根据服务id获取到对应的服务实例
	 */
	List<ServiceInstance> getInstances(String serviceId);
	/**
	 * 获取到所有的服务名称
	 */
	List<String> getServices();
	/**
	 * 获取到默认的排序
	 */
	@Override
	default int getOrder() {
		return DEFAULT_ORDER;
	}
}

目前通过实现可以看到有 eureka和nacos 的实现类,而导入客户端发现功能的是通过 @EnableDiscoveryClient 注解进行导入

1678438792865

Spring Cloud Commons 提供了 @EnableDiscoveryClient 注解。这将寻找 META-INF/spring.factories 文件中 DiscoveryClient 接口的实现类,但是一般 nacos和eureka 并没有通过配置文件的方式进行导入,都是通过自动装配类进行导入的

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {

	/**
	 * 是否自动注册服务,默认为true
	 */
	boolean autoRegister() default true;

}

导入的 EnableDiscoveryClientImportSelector 中将 spring.factoriesDiscoveryClient 的实现类加载出来然后注册到容器中

public class EnableDiscoveryClientImportSelector
		extends SpringFactoryImportSelector<EnableDiscoveryClient> {

	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
        //父类方法会通过泛型注解的类型去 spring.factories 文件中进行加载
		String[] imports = super.selectImports(metadata);
		//获取到注解上的数据信息
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(
				metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
		//是否进行自动注册
		boolean autoRegister = attributes.getBoolean("autoRegister");
		//如果需要自动注册直接导入:AutoServiceRegistrationConfiguration
		if (autoRegister) {
			List<String> importsList = new ArrayList<>(Arrays.asList(imports));
			importsList.add(
					"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
			imports = importsList.toArray(new String[0]);
		}
		else {
			//判断环境的类型,然后指定自动注册属性为false (spring.cloud.service-registry.auto-registration.enabled)
			Environment env = getEnvironment();
			if (ConfigurableEnvironment.class.isInstance(env)) {
				ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
				LinkedHashMap<String, Object> map = new LinkedHashMap<>();
				map.put("spring.cloud.service-registry.auto-registration.enabled", false);
				MapPropertySource propertySource = new MapPropertySource(
						"springCloudDiscoveryClient", map);
				configEnv.getPropertySources().addLast(propertySource);
			}

		}

		return imports;
	}
}

1.2 ServiceInstance

服务实例的接口用于定义当前服务的信息,实现类中会通过下面的 Registration 子接口进行限定操作

public interface ServiceInstance {

	/**
	 * 获取到当前实例的id
	 */
	default String getInstanceId() {
		return null;
	}

	/**
	 * 获取到服务的id
	 */
	String getServiceId();

	/**
	 * host主机名
	 */
	String getHost();

	/**
	 * 端口
	 */
	int getPort();

	/**
	 * 是否采用https进行通信
	 */
	boolean isSecure();

	/**
	 * 获取到服务的uri地址
	 */
	URI getUri();

	/**
	 * 扩展的元数据信息
	 */
	Map<String, String> getMetadata();

	/**
	 * 获取不同实现的方案
	 */
	default String getScheme() {
		return null;
	}

}

Registration

Registration 接口什么都没有定义,继承了 ServiceInstance 中的所有接口方法来定义当前服务的信息

/**
 * 注册服务信息接口,什么都没有定义,主要是通过父级接口 ServiceInstance
 * EurekaRegistration
 * NacosRegistration
 */
public interface Registration extends ServiceInstance {

}

1.3 AutoServiceRegistration

自定服务注册接口,其中也什么都没有定义,都交给子类 AbstractAutoServiceRegistration 进行功能实现

public interface AutoServiceRegistration {

}

当前抽象类是 commons 提供的一个泛型类,抽出来作为一个父类实现了一些基本的方法,其中泛型限定在必须实现了 Registration 接口,上面我们可以看到 Registration 什么都没有做方法都定义在了 ServiceInstance 之中;当前抽象类还实现了监听器,在发布 WebServerInitializedEvent 事件时进行处理

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

1.4 ServiceRegistry

服务注册工厂,从源码中可以看到 Eureka和Nacos 都各自对其进行了复写

1678687794621

public interface ServiceRegistry<R extends Registration> {

	/**
	 * 注册一个实例
	 */
	void register(R registration);

	/**
	 * 取消服务注册
	 */
	void deregister(R registration);

	/**
	 * 一个生命周期的方法,用于关闭 ServiceRegistry
	 */
	void close();

	/**
	 * 设置实例信息的状态信息
	 */
	void setStatus(R registration, String status);

	/**
	 * 获取到实例信息的状态值
	 */
	<T> T getStatus(R registration);

}

1.5 AutoServiceRegistrationAutoConfiguration

服务自动注册的装配类并没有做什么特别的事,只导入了一个 AutoServiceRegistrationConfiguration 配置类

@Configuration(proxyBeanMethods = false)
//导入了当前配置类 AutoServiceRegistrationConfiguration 里面是定义的空配置类
@Import(AutoServiceRegistrationConfiguration.class)
//先判断 spring.cloud.service-registry.auto-registration.enabled 属性是否存在,默认为true需要进行自动注册
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration {

	/**
	 * 注入服务自动注册类
	 */
	@Autowired(required = false)
	private AutoServiceRegistration autoServiceRegistration;

	/**
	 * 服务自动注册的配置类
	 */
	@Autowired
	private AutoServiceRegistrationProperties properties;

	@PostConstruct
	protected void init() {
		//如果服务自动注册为空,并且开启快速失败,直接抛出异常
		if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
			throw new IllegalStateException("Auto Service Registration has "
					+ "been requested, but there is no AutoServiceRegistration bean");
		}
	}

}

1.6 AutoServiceRegistrationConfiguration

导入了服务自动注册的配置类

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {

}

1.7 ServiceRegistryAutoConfiguration

@Configuration(proxyBeanMethods = false)
public class ServiceRegistryAutoConfiguration {

	@ConditionalOnBean(ServiceRegistry.class)
	@ConditionalOnClass(Endpoint.class)
	protected class ServiceRegistryEndpointConfiguration {

		/**
		 * 这里需要获取到当前服务的注册信息,根据注册中心的不同,实现类也不同
		 * NacosRegistration、EurekaRegistration
		 */
		@Autowired(required = false)
		private Registration registration;

		/**
		 * 判断端点在使用到的实现技术上是否可以开启使用,注册一个 ServiceRegistryEndpoint 端点服务接口
		 */
		@Bean
		@ConditionalOnAvailableEndpoint
		public ServiceRegistryEndpoint serviceRegistryEndpoint(
				ServiceRegistry serviceRegistry) {
			ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(
					serviceRegistry);
			endpoint.setRegistration(this.registration);
			return endpoint;
		}

	}

}

spring cloud commons 包中抽出了一些通用的顶级接口用于定义好服务注册的标准,不同的微服务组件通过自己实现接口来实现微服务的服务注册与发现;

  • ServiceInstance:定义了当前客户端信息的基础的顶级接口,其中定义了当前客户端的一些基础信息的获取
  • Registration:继承了 ServiceInstance 接口,当前接口什么都没有定义
  • ServiceRegistry<R extends Registration>:当前接口定义了服务注册的标准api,当客户端启动时如何进行注册以及注销包括设置服务的状态信息,实现类例如:NacosServiceRegistry
  • AutoServiceRegistration:服务自动注册的接口,当前功能主要是在开启了服务启动时(spring.cloud.service-registry.auto-registration.enabled)自动注册提供的标准接口,但是其中并没有定义任何的api方法
  • AbstractAutoServiceRegistration<R extends Registration>:AutoServiceRegistration 接口的一个抽象实现类,其中做了一些基础的方法处理,例如:WebServerInitializedEvent 事件的处理;实现类可以看 NacosAutoServiceRegistration
  • DiscoveryClient:定义客户端服务发现的功能,主要用于当前客户端是否可以从远程获取到服务的注册表的信息;实现类例如:NacosDiscoveryClientEurekaDiscoveryClient 直接通过服务的名称就可以直接去拉取对应的服务信息

通过 spring cloud commons 包的自动装配类可以发现并没有做任何的功能性实现,都是定义出顶级的接口和抽出一些公共的方法,都是交给子类实现

2. 负载均衡

2.1 @LoadBalanced

负载均衡的注解,具体的源码解析可以看 @Qualifier源码解析

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {

}

2.2 ServiceInstanceChooser

服务实例选择器,定义接口用于子类进行实现可以通过服务的id来进行实例的选择,返回的是一个 ServiceInstance 服务实例信息

/**
 * service实例选择器接口
 */
public interface ServiceInstanceChooser {

	/**
	 * 根据serviceId获取到具体的一个 ServiceInstance 实例对象
	 */
	ServiceInstance choose(String serviceId);

}

2.3 LoadBalancerClient

负载均衡的客户端接口,通过子类 RibbonLoadBalancerClient 来进行功能的实现

/**
 * 负载客户端,继承了 ServiceInstanceChooser
 * RibbonLoadBalancerClient:实现了当前客户端,在 RibbonAutoConfiguration 自动装配中创建
 * BlockingLoadBalancerClient
 */
public interface LoadBalancerClient extends ServiceInstanceChooser {

	/**
	 * 执行根据服务id和负载的请求对象
	 */
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	/**
	 * 执行根据传入的服务实例和负载的请求对象
	 */
	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;

	/**
	 * 根据service的实例重新构建uri地址
	 */
	URI reconstructURI(ServiceInstance instance, URI original);

}

2.4 RestTemplateCustomizer

RestTemplate自定义配置器,负载均衡拦截器的植入就是在这里进行添加通过 LoadBalancerAutoConfiguration 自动装配类

public interface RestTemplateCustomizer {

	/**
	 * RestTemplate 自定义配置器
	 *
	 * @param restTemplate restTemplate对象
	 */
	void customize(RestTemplate restTemplate);

}

2.5 LoadBalancerRequestTransformer

用于自定义 HttpRequest 进行转换的接口,目的是将普通的 HttpRequest 类转换为支持负载均衡请求的类

@Order(LoadBalancerRequestTransformer.DEFAULT_ORDER)
public interface LoadBalancerRequestTransformer {

	/**
	 * Order for the load balancer request tranformer.
	 */
	int DEFAULT_ORDER = 0;

	/**
	 * 转换HttpRequest对象
	 *
	 * @param request 需要发起请求的request
	 * @param instance	服务实例信息
	 * @return
	 */
	HttpRequest transformRequest(HttpRequest request, ServiceInstance instance);

}

2.6 LoadBalancerRequest<T>

/**
 * 负载请求的实体,返回值是泛型类
 */
public interface LoadBalancerRequest<T> {

	//通过具体的服务实例发起请求
	T apply(ServiceInstance instance) throws Exception;

}

2.7 LoadBalancerRequestFactory

负载均衡请求实例的工厂,通过方法 createRequest() 创建一个 LoadBalancerRequest 接口的实例对象用于支持负载均衡;

public class LoadBalancerRequestFactory {

	/**
	 * 注入负载的客户端,RibbonAutoConfiguration中配置的 RibbonLoadBalancerClient
	 */
	private LoadBalancerClient loadBalancer;

	private List<LoadBalancerRequestTransformer> transformers;

	public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer,
			List<LoadBalancerRequestTransformer> transformers) {
		this.loadBalancer = loadBalancer;
		this.transformers = transformers;
	}

	public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) {
		this.loadBalancer = loadBalancer;
	}

	/**
	 * 将普通的请求对象转换为 LoadBalancerRequest 接口的实现
	 * @param request
	 * @param body
	 * @param execution
	 * @return
	 */
	public LoadBalancerRequest<ClientHttpResponse> createRequest(
			final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) {
		return instance -> {
			//包装一层http请求,让其可以拥有重写uri的能力通过负载工厂
			HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
					this.loadBalancer);
			//通过 transformers 进行转换请求
			if (this.transformers != null) {
				for (LoadBalancerRequestTransformer transformer : this.transformers) {
					serviceRequest = transformer.transformRequest(serviceRequest,
							instance);
				}
			}
			return execution.execute(serviceRequest, body);
		};
	}

}

LoadBalancerRequestFactory 中包含多个 LoadBalancerRequestTransformer ,然后通过工厂方法创建 LoadBalancerRequest实例,这三个接口进行搭配使用

总结:ribbon组件通过 RibbonLoadBalancerClient 去实现 LoadBalancerClient 然后通过 LoadBalancerAutoConfiguration 自动装配中注入 RestTemplate bean对象后进行自定义添加拦截器 LoadBalancerInterceptor 和通过 RibbonLoadBalancerClient 实现负载

2.8 com.netflix.loadbalancer

以下是 com.netflix.loadbalancer 提供的负载均衡相关的接口

2.8.1 ILoadBalancer

顶级的负载均衡策略接口,通过子类实现,在spring中一般使用默认的实现 ZoneAwareLoadBalancer 通过 RibbonClientConfiguration 自动装配进行配置

public interface ILoadBalancer {

	/**
	 *添加服务列表
	 */
	public void addServers(List<Server> newServers);
	
	/**
	 * 选择一个服务实例
	 */
	public Server chooseServer(Object key);
	
	/**
	 * 标记服务已经宕机
	 */
	public void markServerDown(Server server);
    
	@Deprecated
	public List<Server> getServerList(boolean availableOnly);

	/**
	 * 获取到只能访问的服务
     */
    public List<Server> getReachableServers();

    /**
     * 获取到所有的服务
     */
	public List<Server> getAllServers();
}

2.8.2 IRule

负载均衡的规则,这里一般也使用默认的 ZoneAvoidanceRule 通过 RibbonClientConfiguration 自动装配进行配置

public interface IRule{
    /*
     * 根据key选择服务
     */
    public Server choose(Object key);
    /*
     * 设置负载均衡器
     */
    public void setLoadBalancer(ILoadBalancer lb);
    /*
     * 获取负载均衡器
     */
    public ILoadBalancer getLoadBalancer();    
}

2.8.3 Server

定义的服务类,一般通过子类进行复写,例如:NacosServerZookeeperServer

public class Server {
    //主机
    private String host;
    //端口
    private int port = 80;
    //限定
    private String scheme;
    //服务的id
    private volatile String id;
    //是否活跃
    private volatile boolean isAliveFlag;
    //区分的区域
    private String zone = UNKNOWN_ZONE;
    //是否准备好
    private volatile boolean readyToServe = true;
	//元数据信息
    private MetaInfo simpleMetaInfo
}

2.8.4 ServerList

服务列表的接口,这个接口就是交给子类进行实现用来获取所有的服务实例的接口,服务进行初始化时,会掉用 getUpdatedListOfServers() 获取到服务列表;具体初始化调用是在 ZoneAwareLoadBalancer 构造函数中调用restOfInit() 进行初始化服务列表的

public interface ServerList<T extends Server> {
	/**
     * 获取到初始的服务列表
     */
    public List<T> getInitialListOfServers();
    /**
     * 获取到更新后的服务列表,周期为30秒(可配置)
     */
    public List<T> getUpdatedListOfServers();   
}

3. 服务调用

3.1 NamedContextFactory

spring cloud common中提供的一个名称上下文工厂,在 openFeign 中就用于上下文的指定,是一个泛型抽象类,C extends NamedContextFactory.Specification,其中可以根据名字来对应不同的上下文容器

  • FeignContext:feign中用于进行接口配置的上下文
  • SpringClientFactory:ribbon中用于负载获取的客户端工厂(在openFeign中进行负载的入口)
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {
    /**
	 * 配置资源的名称
	 */
	private final String propertySourceName;

	/**
	 * 配置名称
	 */
	private final String propertyName;

	/**
	 * 通过名称和容器进行对应,1个名称对应一个容器
	 * openFeign 的实现就是一个接口就会对应一个上下文的容器
	 */
	private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();

	/**
	 * 指定配置对象
	 */
	private Map<String, C> configurations = new ConcurrentHashMap<>();

	/**
	 * 父级的全局容器
	 */
	private ApplicationContext parent;

	/**
	 * 默认配置类型
	 */
	private Class<?> defaultConfigType;
    
    //核心方法,创建子容器
    protected AnnotationConfigApplicationContext createContext(String name) {
		//创建一个spring的普通注解上下文
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		//当前 configurations 包含了容器中所有的配置对象,如果是feign,这个配置的类型就是 FeignClientSpecification
		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);
				}
			}
		}
		//初始化一些环境的配置进行,并且注入配置资源的名称可以读取yaml配置文件中的配置信息
		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) {
			// 给当前容器设置父容器,如果子容器获取不到再去父容器中获取
			context.setParent(this.parent);
			context.setClassLoader(this.parent.getClassLoader());
		}
		//生成容器上下文展示的名称
		context.setDisplayName(generateDisplayName(name));
		//刷新容器
		context.refresh();
		return context;
	}
}

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

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

相关文章

node项目的建立

文章目录 1.node项目的建立1.1项目初始化1.2 安装express1.3 初始化服务器 2.配置跨域2.1安装cors2.2cors的引入&#xff08;app.js中&#xff09; 3.初始化路由3.1新建文件3.2初始路由模块3.3app.js注册3.4 在postman测试 4.抽离路由处理模块3.1 在router_handler新建user.js3…

为什么LC谐振频率附近信号会被放大

这个是LC低通滤波电路&#xff0c; 它的增益曲线是这样的 很多同学不理解为什么谐振频率附近信号会被放大&#xff0c;今天就来聊一聊为什么谐振频率附近信号会被放大。 看到这个LC低通滤波电路&#xff0c;假设输入信号源内阻为Rs&#xff0c;L和C为理想电感和电容&#xff0…

Jmeter(五)_CSV Data参数化,Beanshell

一.CSV Data Set Config 准备好一个txt文件&#xff0c;写入如下内容&#xff0c;第一行可以不写&#xff0c;写了的话也会作为一组数据被运行&#xff1a; 然后把后缀名改为CSV&#xff0c;这样一个参数化文件就准备好了 然后打开jmeter&#xff0c;在需要使用这个参数化…

数据库系统-数据库查询实现算法

文章目录 一、一趟扫描算法1.1 算法概述1.2 算法逻辑&物理实现1.2.1 逻辑层面1.2.2 物理层面1.2.2.1 P11.2.2.2 P21.2.2.3 P31.2.2.4 P4 1.3 迭代器构造查询实现算法1.4 关系操作的一趟扫描算法1.4 基于索引的查询实现算法 二、两趟扫描算法2.1 两趟算法基本思想2.2 多路归…

Clickhouse分布式表引擎(Distributed)写入核心原理解析

Clickhouse分布式表引擎&#xff08;Distributed&#xff09;写入核心原理解析 Clickhouse分布式表引擎&#xff08;Distributed&#xff09;写入核心原理解析Clickhouse分布式表引擎&#xff08;Distributed&#xff09;查询核心原理解析 Distributed表引擎是分布式表的代名…

vue打包并部署到nginx上

一、打包vue项目 打包的命令依据项目的配置可能会有所不同&#xff0c;打包的命令可以在package.json中查看 项目中vue.config.js中的配置如下&#xff1a; proxy关系到我们项目部署到nginx上需要配置对应的反向代理 publicPath关系到我们部署时是否需要配置子路径 默认情况…

基于公共信箱的全量消息实现

作者 | 百度消息中台团队 导读 消息中台为百度App以及厂内百度系产品提供即时通讯的能力&#xff0c;提供包括私聊、群聊、聊天室、直播弹幕等用户沟通场景&#xff0c;并帮助业务通过消息推送触达用户。百度App存在需要以『低用户打扰』的形式触达全量用户的场景&#xff0c;而…

AcWing第 96 场周赛

竞赛 - AcWing 一、完美数 4876. 完美数 - AcWing题库 1、题目 如果一个正整数能够被 2520 整除&#xff0c;则称该数为完美数。 给定一个正整数 n&#xff0c;请你计算 [1,n]范围内有多少个完美数。 输入格式 一个整数 n。 输出格式 一个整数&#xff0c;表示 [1,n] 范…

C++:Article : 链接器(三):库与可执行文件的生成

链接器&#xff1a;库与可执行文件 1. 静态库1.1 静态链接下&#xff0c;可执行文件如何生成 2. 动态库2.1 动态库特点以及与静态库使用方式差异2.2 动态库和静态库使用时间 3. load-time dynamic linking&#xff08;加载时动态链接&#xff09;3.1&#xff1a;阶段一&#xf…

【工具】FFmpeg|超大视频本地有损压缩,500MB变25MB(支持 Windows、Linux、macOS)

参考&#xff1a; 如何将一分钟长的1080p视频压缩至5MB以内&#xff1f;-知乎-滔滔清风近期HEVC扩展备用安装方法-B站-悲剧天下 总共三个步骤&#xff0c;安装FFmpeg、运行指令、打开视频。 亲测 500MB 变 25MB。 1 安装FFmpeg 对于不需要看教程可以自行完成安装的同学们&am…

MySQL基础案例——数据表的基本操作:创建表和修改表

目录 案例目的&#xff1a; 创建表&#xff1a; 创建offices&#xff1a; 创建employees表&#xff1a; 修改表&#xff1a; 将 employees 的 mobile 字段移动到 officeCode 字段后&#xff1a; 将 birth 字段名称改为 employee_birth: 修改 sex 字段&#xff0c;数据类…

TryHackMe-Looking Glass(boot2root)

Looking Glass 穿过镜子。仙境挑战室的续集。 端口扫描 循例nmap 又是一堆ssh&#xff0c;跟之前的玩法一样 找到正确的ssh端口之后后给了一段密文&#xff0c;要求输入secret才能进入ssh 这看起来非常像凯撒密码 唯一可识别的信息是Jabberwocky&#xff0c;我们找到了它 它…

IDA简单使用

今天来简单介绍一下逆向中常用到的另一个静态分析工具IDA&#xff0c;还是昨天那个打印demo&#xff08;64位&#xff09;&#xff1a; #include #include char a[] "https://www.vultop.com/"; int main(int argc, char* argv[]) { printf("%s", a)…

什么是微服务

目录 一、微服务介绍 1. 什么是微服务 2. 微服务由来 3. 为什么需要微服务&#xff1f; 3.1 最期的单体架构带来的问题 3.2 微服务与单体架构区别 3.3 微服务与SOA区别 4. 微服务本质 5. 什么样的项目适合微服务 6. 微服务折分与设计 6.1 微服务设计原则 7. 微服务…

linux gcc + openocd + stlink + cubeMX + cortex Debug

文章目录 运行环境&#xff1a;1.1 gcc1)下载并解压gcc2)环境配置 2.1 openocd1)下载并解压openocd2)环境配置&#xff08;没有权限就加sudo&#xff09; 3.1 stlink1)下载并双击安装stlink 4.1 cubeMX1)下载并解压cubeMX2)生成makefile工程 5.1 cortex Debug1)setting设置2)la…

冷链物流运转 3D 可视化监控,助力大数据实时监控

智慧物流是以信息化为依托并广泛应用物联网、人工智能、大数据、云计算等技术工具&#xff0c;在物流价值链上的 6 项基本环节&#xff08;运输、仓储、包装、装卸搬运、流通加工、配送&#xff09;实现系统感知和数据采集的现代综合智能型物流系统。随着冷链信息化、数字化发展…

史上最全! 瑞芯微RK3568核心板评估板资源分享!

▎瑞芯微RK3568芯片 高性能处理器&#xff1a;采用四核A55架构CPU&#xff0c;G52 GPU&#xff1b;内置NPU&#xff0c;可提供1T算力 高可靠性设计&#xff1a;支持DDR及CPU Cache全链路ECC 内置自研ISP图像处理器&#xff1a;8M30fps处理能力&#xff0c;强大的HDR功能&#…

Springboot Netty 实现自定义协议

Netty是由JBOSS提供的一个java开源框架&#xff0c;现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说&#xff0c;Netty 是一个基于NIO的客户、服务器端的编程框架&…

《编程思维与实践》1039.字符组合

《编程思维与实践》1039.字符组合 题目 思路 先将字符串去重排序(保证每个组合中的字符按字典序),然后枚举出所有组合的情形,最后再进行字典序排序即可. 其中字符串的去重排序可以利用ASCII码值进行桶排序,关键在于如何枚举所有组合的情形. 每个位置有两种可能(选或不选),但至…

MongoDB 聚合管道的输出结果到集合($out)及合并结果到集合($merge)

上一篇文章&#xff0c;我们介绍了使用聚合管道完成文档之间的关联查询、以及如果将两个管道中的文档进行合并&#xff0c;如果需要进一步了解可以参考&#xff1a;MongoDB 聚合管道的文档关联查询($lookup)及管道合并($unionWith)https://blog.csdn.net/m1729339749/article/d…