当前位置: 首页 > news >正文

Geoserver源码解读五 Catalog

系列文章目录

Geoserver源码解读一 环境搭建

Geoserver源码解读二 主入口

Geoserver源码解读三 GeoServerBasePage

Geoserver源码解读四 REST服务

Geoserver源码解读五 Catalog


目录

系列文章目录

前言

一、定义

二、前置知识点

1.Spring 的 Bean 生命周期

ApplicationContextAware

BeanPostProcessor 

三、常见用法

四、结构梳理

1.查询工作空间

2.资源读取

五、总结


前言

Catalog数据目录是 Geoserver比较核心的内容,理解Catalog对理解Geoserver的存储机制有很大帮助,夸张点儿说就是,理解了它的逻辑就相当于理解了geoserver的逻辑。本文同样以工作空间为例梳理下它的相关逻辑。


一、定义

GeoServer 的配置形成一个目录,包括工作空间、数据源、图层、样式等。实际上就是一堆文件夹和文本文件(充当的是文件型数据库的作用)。

二、前置知识点

1.Spring 的 Bean 生命周期

Spring 的 Bean 生命周期是指从 Bean 被创建到销毁的整个过程。这个过程包括多个阶段,每个阶段都可以通过不同的方式进行自定义,在 Spring 容器启动时,它会读取配置元数据(如 XML、注解或 Java 配置),解析这些元数据,并将定义的 Bean 注册到容器中。

ApplicationContextAware

Spring 的 ApplicationContextAware 用于标记那些需要知道当前 Spring 应用上下文(ApplicationContext)的 Bean。当一个 Bean 实现 ApplicationContextAware 接口时,它可以在 Bean 的生命周期中访问和操作当前的 ApplicationContext,也就是说它的执行顺序早于Bean 的生命周期

BeanPostProcessor 

Spring 的 BeanPostProcessor 允许你在 Bean 的初始化前后添加自定义逻辑。这个接口定义了两个方法,分别在 Bean 初始化之前和之后被调用。

  • postProcessBeforeInitialization(Object bean, String beanName): 在 Bean 的初始化方法(如 afterPropertiesSet 或自定义的 init-method)之前被调用。
  • postProcessAfterInitialization(Object bean, String beanName): 在 Bean 的初始化方法之后被调用

举个栗子说明

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware,InitializingBean, DisposableBean {private ApplicationContext applicationContext;// 1.这个最先被执行@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;System.out.println("ApplicationContextAware: Application context is set");}// 2.这个第二被执行@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Before initialization of bean: " + beanName);return bean; // 可以返回原始的 Bean 或包装后的 Bean}// 4. 这个第四@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean: Bean properties are set");}// 3. 这个第三public void initMethod() {System.out.println("Custom init method: Bean is initializing");}// 5. 这个第五public void destroyMethod() {System.out.println("Custom destroy method: Bean is being destroyed");}
}
<bean id="myBean" class="com.example.MyBean" init-method="initMethod" destroy-method="destroyMethod">
</bean>

对Spring Bean生命周期的掌握。方便了解分析Geoserver是怎么对资源目录进行解析的

三、常见用法

 获取目录

Catalog catalog = geoServer.getCatalog();

获取所有工作空间

WorkspaceInfo workspace = catalog.getWorkspaces();

获取所有数据存储

List<DataStoreInfo> dataStores = catalog.getStores( DataStoreInfo.class );

获取特定图层

LayerInfo layer = catalog.getLayer( "myLayer" );

四、结构梳理

1.查询工作空间

查询入口

@RestController
@RequestMapping(path = RestBaseController.ROOT_PATH + "/workspaces",produces = {MediaType.APPLICATION_JSON_VALUE,MediaType.APPLICATION_XML_VALUE,MediaType.TEXT_HTML_VALUE})
public class WorkspaceController extends AbstractCatalogController {@Autowiredpublic WorkspaceController(@Qualifier("catalog") Catalog catalog) {super(catalog);}@GetMappingpublic RestWrapper workspacesGet() {List<WorkspaceInfo> wkspaces = catalog.getWorkspaces();return wrapList(wkspaces, WorkspaceInfo.class);}
}

从上面代码可以看出来catalog是依赖注入进来的

    <bean id="localWorkspaceCatalog" class="org.geoserver.catalog.impl.LocalWorkspaceCatalog"><constructor-arg ref="advertisedCatalog" /></bean><alias name="localWorkspaceCatalog" alias="catalog"/> 

实际用到的Catalog是localWorkspaceCatalog而localWorkspaceCatalog使用了AbstractDecorator技术。这一点上一章的 四、前置知识点-AbstractDecorator 也有讲到,此处不多赘述,本质上就是定义了一个变量去直接操作父类。

public class LocalWorkspaceCatalog extends AbstractCatalogDecorator implements Catalog {public LocalWorkspaceCatalog(Catalog delegate) {super(delegate);}
}

这里同样是个依赖注入,以此类推,下面的三级都是依赖注入

    <bean id="rawCatalog" class="org.geoserver.catalog.impl.CatalogImpl" depends-on="configurationLock"><property name="resourceLoader" ref="resourceLoader"/>  </bean><bean id="secureCatalog" class="org.geoserver.security.SecureCatalogImpl" depends-on="accessRulesDao,extensions"><constructor-arg ref="rawCatalog" /> </bean><bean id="advertisedCatalog" class="org.geoserver.catalog.impl.AdvertisedCatalog"><constructor-arg ref="secureCatalog" /><property name="layerGroupVisibilityPolicy"><bean id="org.geoserver.catalog.LayerGroupVisibilityPolicy.HIDE_NEVER" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/></property></bean>    <bean id="localWorkspaceCatalog" class="org.geoserver.catalog.impl.LocalWorkspaceCatalog"><constructor-arg ref="advertisedCatalog" /></bean>

根据上面代码可以看到,最终的生效的父类Catalog是 rawCatalog 也就是 org.geoserver.catalog.impl.CatalogImpl,从depends-on看出它的前置条件是

<bean id="configurationLock" class="org.geoserver.GeoServerConfigurationLock"/>
先看下这个前置条件我替大家看过了就是一个线程锁,当两个用户同时尝试更改同一设置时,这个锁可以确保它们不会互相覆盖对方的更改。

然后再看org.geoserver.catalog.impl.CatalogImpl里面是怎么查询工作空间的

    @Overridepublic List<WorkspaceInfo> getWorkspaces() {return facade.getWorkspaces();}@Overridepublic WorkspaceInfo getWorkspace(String id) {return facade.getWorkspace(id);}

可以看出来catalog内部又使用了个facade,这层级套用的是真的深啊,静不下心的话根本就看不下去,再继续往下看这个facade

    /** data access facade */protected CatalogFacade facade;public CatalogImpl() {setFacade(new DefaultCatalogFacade(this));dispatcher = new CatalogEventDispatcher();resourcePool = ResourcePool.create(this);}

在构造函数中的给了它一个 DefaultCatalogFacade

src/main/java/org/geoserver/catalog/impl/DefaultCatalogFacade.java

继续查看DefaultCatalogFacade可以看到下面的代码

    /** workspaces */protected CatalogInfoLookup<WorkspaceInfo> workspaces =new CatalogInfoLookup<>(WORKSPACE_NAME_MAPPER);@Overridepublic List<WorkspaceInfo> getWorkspaces() {return ModificationProxy.createList(new ArrayList<>(workspaces.values()), WorkspaceInfo.class);}@Overridepublic WorkspaceInfo getWorkspace(String id) {WorkspaceInfo ws = workspaces.findById(id, WorkspaceInfo.class);return wrapInModificationProxy(ws, WorkspaceInfo.class);}

可以看出来DefaultCatalogFacade下面还有一层workspaces也就是CatalogInfoLookup

src/main/java/org/geoserver/catalog/impl/CatalogInfoLookup.java

这是一个内部工具类,用于在 GeoServer 的目录(catalog)中查找和存储 CatalogInfo 对象。CatalogInfo 是 GeoServer 目录中的一个接口,它代表目录中的一个信息对象,如工作空间(Workspace)、数据存储(DataStore)、覆盖范围(Coverage)等

class CatalogInfoLookup<T extends CatalogInfo> {public T add(T value) {if (Proxy.isProxyClass(value.getClass())) {ModificationProxy h = (ModificationProxy) Proxy.getInvocationHandler(value);value = (T) h.getProxyObject();}Map<Name, T> nameMap = getMapForValue(nameMultiMap, value);Name name = nameMapper.apply(value);nameMap.put(name, value);Map<String, T> idMap = getMapForValue(idMultiMap, value);return idMap.put(value.getId(), value);}public Collection<T> values() {List<T> result = new ArrayList<>();for (Map<String, T> v : idMultiMap.values()) {result.addAll(v.values());}return result;}
}

从上面代码可以看出来查询出来的实际上是 idMultiMap 它的新增方法是add,到这里整个查询的逻辑基本上已经梳理到头了,但是这个idMultiMap  到底是在什么时候生成的也就是说这个add是在什么时候调用的就又是另外一条业务梳理线了

2.资源读取

上面讲到查询工作目录的时候最终到了CatalogInfoLookup的 idMultiMap ,我在add方法中打了个断点,跟踪了下进程,梳理出了下面的逻辑

首先是入口

src/main/java/applicationContext.xml

当项目起来后读取这个配置文件并初始化

<bean id="geoServerLoader" class="org.geoserver.config.GeoServerLoaderProxy"><constructor-arg ref="resourceLoader"/></bean>

读到配置文件后进入Bean生命周期(上面有讲到)

public class GeoServerLoaderProxyimplements BeanPostProcessor,ApplicationListener<ContextClosedEvent>,ApplicationContextAware,GeoServerReinitializer {/** resource loader */protected GeoServerResourceLoader resourceLoader;/** the actual loader */GeoServerLoader loader;public GeoServerLoaderProxy(GeoServerResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.loader = lookupGeoServerLoader(applicationContext);loader.setApplicationContext(applicationContext);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {if (loader != null) {return loader.postProcessAfterInitialization(bean, beanName);}return bean;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {if (loader != null) {return loader.postProcessBeforeInitialization(bean, beanName);}return bean;}protected GeoServerLoader lookupGeoServerLoader(ApplicationContext appContext) {GeoServerLoader loader = GeoServerExtensions.bean(GeoServerLoader.class, appContext);if (loader == null) {loader = new DefaultGeoServerLoader(resourceLoader);}return loader;}@Overridepublic void initialize(GeoServer geoServer) throws Exception {loader.initializeDefaultStyles(geoServer.getCatalog());}
}

然后重点看一下它的postProcessBeforeInitialization方法

    protected GeoServerLoader lookupGeoServerLoader(ApplicationContext appContext) {GeoServerLoader loader = GeoServerExtensions.bean(GeoServerLoader.class, appContext);if (loader == null) {loader = new DefaultGeoServerLoader(resourceLoader);}return loader;}

实际上就是loader(src/main/java/org/geoserver/config/GeoServerLoader.java)的postProcessBeforeInitialization方法

    public final Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {if (bean instanceof Catalog) {// ensure this is not a wrapper but the real dealif (bean instanceof Wrapper && ((Wrapper) bean).isWrapperFor(Catalog.class)) {return bean;}postProcessBeforeInitializationCatalog(bean);}if (bean instanceof GeoServer) {postProcessBeforeInitializationGeoServer(bean);}return bean;}

再继续看postProcessBeforeInitializationCatalog方法

private void postProcessBeforeInitializationCatalog(Object bean) {// loadtry {// setup ADMIN_ROLE security context to load secured resourcesactivateAdminRole();Catalog catalog = (Catalog) bean;XStreamPersister xp = xpf.createXMLPersister();xp.setCatalog(catalog);loadCatalog(catalog, xp);// initialize stylesinitializeStyles(catalog, xp);} catch (Exception e) {throw new RuntimeException(e);} finally {// clear security contextSecurityContextHolder.clearContext();}}

重点在loadCatalog,再继续往下看loadCatalog

@Overrideprotected void loadCatalog(Catalog catalog, XStreamPersister xp) throws Exception {catalog.setResourceLoader(resourceLoader);readCatalog(catalog, xp);if (!legacy) {// add the listener which will persist changescatalog.addListener(new GeoServerConfigPersister(resourceLoader, xp));catalog.addListener(new GeoServerResourcePersister(catalog));}executeListener(catalog, xp);}

重点在readCatalog,再继续往下看readCatalog

重点来了啊 重点来了

protected void readCatalog(Catalog catalog, XStreamPersister xp) throws Exception {// we are going to synch up the catalogs and need to preserve listeners,// but these two fellas are attached to the new catalog as wellcatalog.removeListeners(ResourcePool.CacheClearingListener.class);catalog.removeListeners(GeoServerConfigPersister.class);catalog.removeListeners(GeoServerResourcePersister.class);// look for catalog.xml, if it exists assume we are dealing with// an old data directoryResource f = resourceLoader.get("catalog.xml");CatalogImpl catalog2;if (!Resources.exists(f)) {// assume 2.x style data directoryStopwatch sw = Stopwatch.createStarted();LOGGER.config("Loading catalog " + resourceLoader.getBaseDirectory());catalog2 = (CatalogImpl) readCatalog(xp);LOGGER.config("Read catalog in " + sw.stop());} else {// import old style catalog, register the persister now so that we start// with a new version of the catalogcatalog2 = (CatalogImpl) readLegacyCatalog(f, xp);}List<CatalogListener> listeners = new ArrayList<>(catalog.getListeners());// make to remove the old resource pool catalog listener((CatalogImpl) catalog).sync(catalog2);// attach back the old listenersfor (CatalogListener listener : listeners) {catalog.addListener(listener);}}
    /** Reads the catalog from disk. */Catalog readCatalog(XStreamPersister xp) throws Exception {CatalogImpl catalog = new CatalogImpl();catalog.setResourceLoader(resourceLoader);xp.setCatalog(catalog);xp.setUnwrapNulls(false);// see if we really need to verify stores on startupboolean checkStores = checkStoresOnStartup(xp);if (!checkStores) {catalog.setExtendedValidation(false);}// global stylesloadStyles(resourceLoader.get("styles"), catalog, xp);// workspaces, stores, and resourcesResource workspaces = resourceLoader.get("workspaces");if (Resources.exists(workspaces)) {// do a first quick scan over all workspaces, setting the defaultResource dws = workspaces.get("default.xml");WorkspaceInfo defaultWorkspace = null;if (Resources.exists(dws)) {try {defaultWorkspace = depersist(xp, dws, WorkspaceInfo.class);if (LOGGER.isLoggable(Level.CONFIG)) {LOGGER.config("Loaded default workspace '" + defaultWorkspace.getName() + "'");}} catch (Exception e) {LOGGER.log(Level.WARNING, "Failed to load default workspace", e);}} else {LOGGER.warning("No default workspace was found.");}List<Resource> workspaceList =workspaces.list().parallelStream().filter(r -> Resources.DirectoryFilter.INSTANCE.accept(r)).collect(Collectors.toList());try (AsynchResourceIterator<WorkspaceContents> it =new AsynchResourceIterator<>(workspaces,Resources.DirectoryFilter.INSTANCE,new WorkspaceMapper())) {while (it.hasNext()) {WorkspaceContents wc = it.next();WorkspaceInfo ws;final Resource workspaceResource = wc.resource;try {ws = depersist(xp, wc.contents, WorkspaceInfo.class);catalog.add(ws);LOGGER.log(Level.CONFIG,() -> String.format("Loaded workspace '%s'", ws.getName()));} catch (Exception e) {LOGGER.log(Level.WARNING,"Failed to load workspace '" + workspaceResource.name() + "'",e);continue;}// load the namespaceNamespaceInfo ns = null;try {ns = depersist(xp, wc.nsContents, NamespaceInfo.class);catalog.add(ns);} catch (Exception e) {LOGGER.log(Level.WARNING,"Failed to load namespace for '" + workspaceResource.name() + "'",e);}// set the default workspace, this value might be null in the case of coming// from a// 2.0.0 data directory. See https://osgeo-org.atlassian.net/browse/GEOS-3440if (defaultWorkspace != null) {if (ws.getName().equals(defaultWorkspace.getName())) {catalog.setDefaultWorkspace(ws);if (ns != null) {catalog.setDefaultNamespace(ns);}}} else {// create the default.xml filedefaultWorkspace = catalog.getDefaultWorkspace();if (defaultWorkspace != null) {try {persist(xp, defaultWorkspace, dws);} catch (Exception e) {LOGGER.log(Level.WARNING,"Failed to persist default workspace '"+ workspaceResource.name()+ "'",e);}}}// load the styles for the workspaceResource styles = workspaceResource.get("styles");if (styles != null) {loadStyles(styles, catalog, xp);}}}// maps each store into a SingleResourceContentsResourceMapper<SingleResourceContents> storeMapper =sd -> {Resource f = sd.get("datastore.xml");if (Resources.exists(f)) {return new SingleResourceContents(f, f.getContents());}f = sd.get("coveragestore.xml");if (Resources.exists(f)) {return new SingleResourceContents(f, f.getContents());}f = sd.get("wmsstore.xml");if (Resources.exists(f)) {return new SingleResourceContents(f, f.getContents());}f = sd.get("wmtsstore.xml");if (Resources.exists(f)) {return new SingleResourceContents(f, f.getContents());}if (!isConfigDirectory(sd)) {LOGGER.warning("Ignoring store directory '" + sd.name() + "'");}// nothing foundreturn null;};for (Resource wsd : workspaceList) {// load the stores for this workspacetry (AsynchResourceIterator<SingleResourceContents> it =new AsynchResourceIterator<>(wsd, Resources.DirectoryFilter.INSTANCE, storeMapper)) {while (it.hasNext()) {SingleResourceContents SingleResourceContents = it.next();final String resourceName = SingleResourceContents.resource.name();if ("datastore.xml".equals(resourceName)) {loadDataStore(SingleResourceContents, catalog, xp, checkStores);} else if ("coveragestore.xml".equals(resourceName)) {loadCoverageStore(SingleResourceContents, catalog, xp);} else if ("wmsstore.xml".equals(resourceName)) {loadWmsStore(SingleResourceContents, catalog, xp);} else if ("wmtsstore.xml".equals(resourceName)) {loadWmtsStore(SingleResourceContents, catalog, xp);} else if (!isConfigDirectory(SingleResourceContents.resource)) {LOGGER.warning("Ignoring store directory '"+ SingleResourceContents.resource.name()+ "'");continue;}}}// load the layer groups for this workspaceResource layergroups = wsd.get("layergroups");if (layergroups != null) {loadLayerGroups(layergroups, catalog, xp);}}} else {LOGGER.warning("No 'workspaces' directory found, unable to load any stores.");}// layergroupsResource layergroups = resourceLoader.get("layergroups");if (layergroups != null) {loadLayerGroups(layergroups, catalog, xp);}xp.setUnwrapNulls(true);catalog.resolve();// re-enable extended validationif (!checkStores) {catalog.setExtendedValidation(true);}return catalog;}

这就是解析工作空间的核心代码了,并且可以看到它和上一步的关联的地方

catalog.add(ws);

扩展的说一下解析工作空间时用到了XStream技术,这个技术主要用于xml文件和java对象的互相转换

也就是说到此为止,Catalog的业务逻辑算是基本上梳理完了

五、总结

回顾上面的一坨坨代码,总结出来资源目录的处理就两条线

1.资源读取(上述4.2)【本质上就是读取文件】

2.资源的查询过滤(上述4.1)【本质上就是数组或者集合的增删改查】

相关文章:

Geoserver源码解读五 Catalog

系列文章目录 Geoserver源码解读一 环境搭建 Geoserver源码解读二 主入口 Geoserver源码解读三 GeoServerBasePage Geoserver源码解读四 REST服务 Geoserver源码解读五 Catalog 目录 系列文章目录 前言 一、定义 二、前置知识点 1.Spring 的 Bean 生命周期 ApplicationCon…...

安全与加密常识(5)自签名证书

文章目录 什么是自签名证书?自签名证书有什么优势?自签名证书有什么缺陷?企业可以使用自签名证书吗?如何创建自签名证书?前面我们介绍了什么是证书签名请求:证书签名请求(Certificate Signing Request,CSR)是一种数据文件,通常由申请者生成,并用于向证书颁发机构(C…...

Java官网网址及其重要资源

Java是一种广泛应用于开发各种应用程序的编程语言&#xff0c;它具有跨平台、面向对象和高性能等优势。若你想学习Java或深入了解它的最新动态&#xff0c;Java官网是你的首要目的地。在本文中&#xff0c;我们将向你介绍Java官网的网址以及一些重要资源。 Java官网网址&#x…...

Linux--start-stop-daemon

参考&#xff1a;start-stop-daemon(8) - Linux manual page 1、名称 start-stop-daemon&#xff1a;启动和停止系统守护程序。 2、简介 start-stop-daemon [option...] command 3、描述 start-stop-daemon用于控制系统级进程的创建和终止。使用其中一个匹配选项&#xff0…...

优化Java中XML和JSON序列化

优化Java中XML和JSON序列化 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在Java应用程序中&#xff0c;对于XML和JSON的序列化操作是非常常见的需求。本文将…...

像学Excel 一样学 Pandas系列-创建数据分析维度

嗨&#xff0c;小伙伴们。又到喜闻乐见的Python 数据分析王牌库 Pandas 的学习时间。按照数据分析处理过程&#xff0c;这次轮到了新增维度的部分了。 老样子&#xff0c;我们先来回忆一下&#xff0c;一个完整数据分析的过程&#xff0c;包含哪些部分内容。 其中&#xff0c…...

Rust 基础教程

Rust 编程语言教程 Rust是一门注重安全、并发和性能的系统编程语言。本文将从Rust的基本语法、常用功能到高级特性&#xff0c;详细介绍Rust的使用方法。 目录 简介环境配置基础语法 变量和常量数据类型函数控制流 所有权和借用 所有权借用 结构体和枚举 结构体枚举 模块和包…...

Study--Oracle-06-Oracler网络管理

一、ORACLE的监听管理 1、ORACLE网络监听配置文件 cd /u01/app/oracle/product/12.2.0/db_1/network/admin 2、在Oracle数据库中&#xff0c;监听器&#xff08;Listener&#xff09;是一个独立的进程&#xff0c;它监听数据库服务器上的特定端口上的网络连接请求&#xff0c…...

uniapp零基础入门Vue3组合式API语法版本开发咸虾米壁纸项目实战

嗨&#xff0c;大家好&#xff0c;我是爱搞知识的咸虾米。 今天给大家带来的是零基础入门uniapp&#xff0c;课程采用的是最新的Vue3组合式API版本&#xff0c;22年发布的uniappVue2版本获得了官方推荐&#xff0c;有很多同学等着我这个vue3版本的那&#xff0c;如果没有学过vu…...

数字信号处理教程(2)——时域离散信号与时域离散系统

上回书说到数字信号处理中基本的一个通用模型框架图。今天咱们继续&#xff0c;可以说今天要讲的东西必须是学习数字信号处理必备的观念——模拟与数字&#xff0c;连续和离散。 时域离散序列 由于数字信号基本都来自模拟信号&#xff0c;所以先来谈谈模拟信号。模拟信号就是…...

imx6ull/linux应用编程学习(8)PWM应用编程(基于正点)

1.应用层如何操控PWM&#xff1a; 与 LED 设备一样&#xff0c; PWM 同样也是通过 sysfs 方式进行操控&#xff0c;进入到/sys/class/pwm 目录下 这里列举出了 8 个以 pwmchipX&#xff08;X 表示数字 0~7&#xff09;命名的文件夹&#xff0c;这八个文件夹其实就对应了…...

等保2.0 实施方案

一、引言 随着信息技术的广泛应用&#xff0c;网络安全问题日益突出&#xff0c;为确保信息系统安全、稳定、可靠运行&#xff0c;保障国家安全、公共利益和个人信息安全&#xff0c;根据《网络安全法》及《信息安全技术 网络安全等级保护基本要求》&#xff08;等保2.0&#x…...

7/3 第六周 数据库的高级查询

...

ubuntu20.04安装kazam桌面屏幕录制工具

在Ubuntu 20.04上安装Kazam可以通过以下步骤进行&#xff1a; 1.打开终端&#xff1a;可以通过按下Ctrl Alt T组合键来打开终端。 2.添加PPA源&#xff1a;Kazam不再在官方Ubuntu仓库中&#xff0c;但可以通过PPA源进行安装。在终端中输入以下命令来添加PPA&#xff1a; su…...

Python应对反爬虫的策略

Python应对反爬虫的策略 概述User-Agent 伪造应对302重定向IP限制与代理使用Cookies和Session管理动态内容加载数据加密与混淆请求频率限制爬虫检测算法法律与道德考量结语 概述 在数字化时代&#xff0c;网络数据采集已成为获取信息的重要手段之一。然而&#xff0c;随着技术…...

240703_昇思学习打卡-Day15-K近邻算法实现红酒聚类

KNN(K近邻)算法实现红酒聚类 K近邻算法&#xff0c;是有监督学习中的分类算法&#xff0c;可以用于分类和回归&#xff0c;本篇主要讲解其在分类上的用途。 文章目录 KNN(K近邻)算法实现红酒聚类算法原理数据下载数据读取与处理模型构建--计算距离模型预测 算法原理 KNN算法虽…...

keil5模拟 仿真 报错没有读写权限

debug*** error 65: access violation at 0x4002100C : no write permission 修改为&#xff1a; Dialog DLL默认是DCM3.DLL Parameter默认是-pCM3 应改为 Dialog DLL默认是DARMSTM.DLL Parameter默认是-pSTM32F103VE...

力扣爆刷第158天之TOP100五连刷56-60(子集、最小栈、最长有效括号)

力扣爆刷第158天之TOP100五连刷56-60&#xff08;子集、最小栈、最长有效括号&#xff09; 文章目录 力扣爆刷第158天之TOP100五连刷56-60&#xff08;子集、最小栈、最长有效括号&#xff09;一、78. 子集二、105. 从前序与中序遍历序列构造二叉树三、43. 字符串相乘四、155. …...

高薪程序员必修课-Java中 Synchronized锁的升级过程

目录 前言 锁的升级过程 1. 偏向锁&#xff08;Biased Locking&#xff09; 原理&#xff1a; 示例&#xff1a; 2. 轻量级锁&#xff08;Lightweight Locking&#xff09; 原理&#xff1a; 示例&#xff1a; 3. 重量级锁&#xff08;Heavyweight Locking&#xff09;…...

Vue项目打包上线

Nginx 是一个高性能的开源HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它在设计上旨在处理高并发的请求&#xff0c;是一个轻量级、高效能的Web服务器和反向代理服务器&#xff0c;广泛用于提供静态资源、负载均衡、反向代理等功能。 1、下载nginx 2、…...

算法题中常用的C++功能

文章目录 集合优先队列双端队列排序时自定义比较函数最大数值字符串追加&#xff1a;删除&#xff1a;子串&#xff1a; 元组vector查找创建和初始化赋值&#xff1a; 字典map引入头文件定义和初始化插入元素访问元素更新元素删除元素检查元素存在遍历元素int和string转换 集合…...

左扰动和右扰动

在SLAM&#xff08;Simultaneous Localization and Mapping&#xff09;中&#xff0c;使用左扰动还是右扰动主要取决于你如何定义坐标系和你希望扰动影响的姿态表示。这通常与你的坐标系选择和你正在解决的具体问题有关。 左扰动通常用于以下情况&#xff1a; 当你使用局部坐…...

【计算机网络】期末复习(2)

目录 第一章&#xff1a;概述 第二章&#xff1a;物理层 第三章&#xff1a;数据链路层 第四章&#xff1a;网络层 第五章&#xff1a;传输层 第一章&#xff1a;概述 三大类网络 &#xff08;1&#xff09;电信网络 &#xff08;2&#xff09;有线电视网络 &#xff0…...

ojdbc8-full Oracle JDBC 驱动程序的一个完整发行版各文件的功能

文章目录 1. ojdbc8.jar2. ons.jar -3. oraclepki.jar -4. orai18n.jar -5. osdt_cert.jar -6. osdt_core.jar -7. ojdbc.policy -8. README.txt -9. simplefan.jar -10. ucp.jar -11. xdb.jar - ojdbc8-full 是 Oracle JDBC 驱动程序的一个完整发行版&#xff0c;包含了连接和…...

在Linux环境下使用sqlite3时,如果尝试对一个空表进行操作(例如插入数据),可能会遇到表被锁定的问题。

在Linux环境下使用sqlite3时&#xff0c;如果尝试对一个空表进行操作&#xff08;例如插入数据&#xff09;&#xff0c;可能会遇到表被锁定的问题。这通常是因为sqlite3在默认情况下会对空表进行“延迟创建”&#xff0c;即在实际需要写入数据之前&#xff0c;表不会被真正创建…...

【目标检测】DINO

一、引言 论文&#xff1a; DINO: DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detection 作者&#xff1a; IDEA 代码&#xff1a; DINO 注意&#xff1a; 该算法是在Deformable DETR、DAB-DETR、DN-DETR基础上的改进&#xff0c;在学习该算法前&#…...

一文包学会ElasticSearch的大部分应用场合

ElasticSearch 官网下载地址&#xff1a;Download Elasticsearch | Elastic 历史版本下载地址1&#xff1a;Index of elasticsearch-local/7.6.1 历史版本下载地址2&#xff1a;Past Releases of Elastic Stack Software | Elastic ElasticSearch的安装(windows) 安装前所…...

创建kobject

1、kobject介绍 kobject的全称是kernel object&#xff0c;即内核对象。每一个kobject都会对应系统/sys/下的一个目录。 2、相关结构体和api介绍 2.1 struct kobject // include/linux/kobject.h 2.2 kobject_create_and_add kobject_create_and_addkobject_createkobj…...

数据结构 - C/C++ - 树

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 树的概念 结构特性 树的样式 树的存储 树的遍历 节点增删 二叉搜索树 平衡二叉树 树的概念 二叉树是树形结构&#xff0c;是一种非线性结构。 非线性结构&#xff1a;在二叉树中&#x…...

Linux源码阅读笔记12-RCU案例分析

在之前的文章中我们已经了解了RCU机制的原理和Linux的内核源码&#xff0c;这里我们要根据RCU机制写一个demo来展示他应该如何使用。 RCU机制的原理 RCU&#xff08;全称为Read-Copy-Update&#xff09;,它记录所有指向共享数据的指针的使用者&#xff0c;当要修改构想数据时&…...

【C++】双线性差值算法实现RGB图像缩放

双线性差值算法 双线性插值&#xff08;Bilinear Interpolation&#xff09;并不是“双线性差值”&#xff0c;它是一种在二维平面上估计未知数据点的方法&#xff0c;通常用于图像处理中的图像缩放。 双线性插值的基本思想是&#xff1a;对于一个未知的数据点&#xff0c;我…...

计算机网络知识普及之四元组

在涉及到TCP/UDP等IP类通信协议时&#xff0c;存在四元组概念 这里只是普及使用 先来一些前置知识&#xff0c;什么是IP协议&#xff1f; IP协议全称为互联网协议&#xff0c;处于网络层中&#xff0c;主要作用是标识网络中的设备&#xff0c;每个设备的IP地址是唯一的。 在网…...

深度探讨网络安全:挑战、防御策略与实战案例

目录 ​编辑 一、引言 二、网络安全的主要挑战 恶意软件与病毒 数据泄露 分布式拒绝服务攻击&#xff08;DDoS&#xff09; 内部威胁 三、防御策略与实战案例 恶意软件防护 网络钓鱼防护 数据泄露防护 总结 一、引言 随着信息技术的迅猛发展&#xff0c;网络安全问…...

“穿越时空的机械奇观:记里鼓车的历史与科技探秘“

在人类文明的发展历程中&#xff0c;科技的创新与进步不仅仅推动了社会的进步&#xff0c;也为我们留下了丰富的文化遗产。记里鼓车&#xff0c;作为一种古老的里程计量工具&#xff0c;其历史地位和技术成就在科技史上具有重要的意义。本文将详细介绍记里鼓车的起源、结构原理…...

DevOps CMDB平台整合Jira工单

背景 在DevOps CMDB平台建设的过程中&#xff0c;我们可以很容易的将业务应用所涉及的云资源&#xff08;WAF、K8S、虚拟机等&#xff09;、CICD工具链&#xff08;Jenkins、ArgoCD&#xff09;、监控、日志等一次性的维护到CMDB平台&#xff0c;但随着时间的推移&#xff0c;…...

Vue-路由

路由简介 SPA单页面应用。导航区和展示区 单页Web应用整个应用只有一个完整的页面点击页面中的导航连接不会刷新页面&#xff0c;只会做页面的局部更新数据需要通过ajax请求获取 路由&#xff1a;路由就是一组映射关系&#xff0c;服务器接收到请求时&#xff0c;根据请求路…...

【Rust入门教程】安装Rust

文章目录 前言Rust简介Rust的安装更新与卸载rust更新卸载 总结 前言 在当今的编程世界中&#xff0c;Rust语言以其独特的安全性和高效性吸引了大量开发者的关注。Rust是一种系统编程语言&#xff0c;专注于速度、内存安全和并行性。它具有现代化的特性&#xff0c;同时提供了低…...

Character.ai因内容审查流失大量用户、马斯克:Grok-3用了10万块英伟达H100芯片

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 1、爆火AI惨遭阉割&#xff0c;1600万美国年轻人失恋&#xff1f;Character.ai被爆资金断裂 美国流行的社交软件Character.ai近期对模型进行大幅度内容审查&#xff0c;导致用户感到失望并开始流失。…...

Spring源码九:BeanFactoryPostProcessor

上一篇Spring源码八&#xff1a;容器扩展一&#xff0c;我们看到ApplicationContext容器通过refresh方法中的prepareBeanFactory方法对BeanFactory扩展的一些功能点&#xff0c;包括对SPEL语句的支持、添加属性编辑器的注册器扩展解决Bean属性只能定义基础变量的问题、以及一些…...

大模型笔记1: Longformer环境配置

论文: https://arxiv.org/abs/2004.05150 目录 库安装 LongformerForQuestionAnswering 库安装 首先保证电脑上配置了git. git环境配置: https://blog.csdn.net/Andone_hsx/article/details/87937329 3.1、找到git安装路径中bin的位置&#xff0c;如&#xff1a;D:\Prog…...

类和对象(提高)

类和对象&#xff08;提高&#xff09; 1、定义一个类 关键字class 6 class Data1 7 { 8 //类中 默认为私有 9 private: 10 int a;//不要给类中成员 初始化 11 protected://保护 12 int b; 13 public://公共 14 int c; 15 //在类的内部 不存在权限之分 16 void showData(void)…...

免费最好用的证件照制作软件,一键换底+老照片修复+图片动漫化,吊打付费!

这款软件真的是阿星用过的&#xff0c;最好用的证件照制作软件&#xff0c;没有之一&#xff01; 我是阿星&#xff0c;今天要给大家安利一款超实用的证件照工具&#xff0c;一键换底&#xff0c;自动排版&#xff0c;免费无广告&#xff0c;让你在家就能轻松搞定证件照&#…...

antfu/ni 在 Windows 下的安装

问题 全局安装 ni 之后&#xff0c;第一次使用会有这个问题 解决 在 powershell 中输入 Remove-Item Alias:ni -Force -ErrorAction Ignore之后再次运行 ni Windows 11 下的 Powershell 环境配置 可以参考 https://github.com/antfu-collective/ni?tabreadme-ov-file#how …...

Linux 生产消费者模型

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux初窥门径⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 前言 1. 生产消费者模型 1.1 什么是生产消…...

深入浅出:MongoDB中的背景创建索引

深入浅出&#xff1a;MongoDB中的背景创建索引 想象一下&#xff0c;你正忙于将成千上万的数据塞入你的MongoDB数据库中&#xff0c;你的用户期待着实时的响应速度。此时&#xff0c;你突然想到&#xff1a;“嘿&#xff0c;我应该给这些查询加个索引&#xff01;” 没错&…...

Spring事务十种失效场景

首先我们要明白什么是事务&#xff1f;它的作用是什么&#xff1f;它在什么场景下在Spring框架下会失效&#xff1f; 事务&#xff1a;本质上是由数据库和程序之间交互的过程中的衍生物,它是一种控制数据的行为规则。有几个特性 1、原子性&#xff1a;执行单元内&#xff0c;要…...

JELR-630HS漏电继电器 30-500mA 导轨安装 约瑟JOSEF

JELR-HS系列 漏电继电器型号&#xff1a; JELR-15HS漏电继电器&#xff1b;JELR-25HS漏电继电器&#xff1b; JELR-32HS漏电继电器&#xff1b;JELR-63HS漏电继电器&#xff1b; JELR-100HS漏电继电器&#xff1b;JELR-120HS漏电继电器&#xff1b; JELR-160HS漏电继电器&a…...

如何实现一个简单的链表或栈结构

实现一个简单的链表或栈结构是面向对象编程中的基础任务。下面我将分别给出链表和栈的简单实现。 链表&#xff08;单链表&#xff09;的实现 链表是由一系列节点组成的集合&#xff0c;每个节点都包含数据部分和指向列表中下一个节点的链接&#xff08;指针或引用&#xff0…...

抖音外卖服务商入驻流程及费用分别是什么?入驻官方平台的难度大吗?

随着抖音关于新增《【到家外卖】内容服务商开放准入公告》的意见征集通知&#xff08;以下简称“通知”&#xff09;的发布&#xff0c;抖音外卖服务商入驻流程及费用逐渐成为众多创业者所关注和热议的话题。不过&#xff0c;就当前的讨论情况来看&#xff0c;这个话题似乎没有…...

“小红书、B站崩了”,背后的阿里云怎么了?

导语&#xff1a;阿里云不能承受之重 文 | 魏强 7月2日&#xff0c;“小红书崩了”、“B站崩了”等话题登上了热搜。 据第一财经、财联社等报道&#xff0c;7月2日&#xff0c;用户在B站App无法使用浏览历史关注等内容&#xff0c;消息界面、更新界面、客服界面均不可用&…...

用HttpURLConnection复现http响应码405

目录 使用GET方法&#xff0c;访问GET接口&#xff0c;服务端返回405使用GET方法&#xff0c;访问POST接口&#xff0c;服务端返回405使用POST方法&#xff0c;访问GET接口&#xff0c;服务端返回405 使用GET方法&#xff0c;访问GET接口&#xff0c;服务端返回405 发生场景&a…...

Node.js-path 模块

path 模块 path 模块提供了 操作路径 的功能&#xff0c;如下是几个较为常用的几个 API&#xff1a; 代码实例&#xff1a; const path require(path);//获取路径分隔符 console.log(path.sep);//拼接绝对路径 console.log(path.resolve(__dirname, test));//解析路径 let pa…...

力扣404周赛 T1/T2/T3 枚举/动态规划/数组/模拟

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 3200.三角形的最大高度【简单】 题目&#xff1a; 给你两个整数 red 和 b…...

【OnlyOffice】桌面应用编辑器,插件开发大赛,等你来挑战

OnlyOffice&#xff0c;桌面应用编辑器&#xff0c;最近版本已从8.0升级到了8.1 从PDF、Word、Excel、PPT等全面进行了升级。随着AI应用持续的火热&#xff0c;OnlyOffice也在不断推出AI相关插件。 因此&#xff0c;在此给大家推荐一下OnlyOffice本次的插件开发大赛。 详细信息…...

yolov5实例分割跑通以及C#读取yolov5_Seg实例分割转换onnx进行检测部署

一、首先需要训练yolov5_seg的模型&#xff0c;可以去网上学习&#xff0c;或者你直接用我的&#xff0c; 训练环境和yolov5—7.0的环境一样&#xff0c;你可以直接拷过来用。 yolov5_seg算法 链接&#xff1a;https://pan.baidu.com/s/1m-3lFWRHwg5t8MmIOKm4FA 提取码&…...

小程序的制作费用很贵么

小程序这么火&#xff0c;想做一个小程序大概要话多少钱&#xff1f;&#x1f442;&#x1f442; 经常被客户问到这个问题&#x1f44c;&#xff0c;要做一个商.城多少钱要做一个物流多少钱要做一个餐饮的多少钱&#xff0c;那今天就说说大概的费用&#x1f44f;。主要也是看功…...

起售13.98万,取消鲢鱼嘴设计,试驾体验第十一代索纳塔!

对于2002年就进入国内市场的索纳塔,相信大多数人并不陌生,定位上是一台中型车,整体的风格就是突出运动基因,而在今年是迎来了家族第十一代车型上市。车辆指导售价在13.98~18.68万之间,作为一台中型车,定价方面还算合理,从低到高,动力上有两种选择,一种是1.5T涡轮增压引…...

2.0T275马力,油耗6.3L能加92,5米大7座

探险者固然是一款很好的车型,特别是昆仑巅峰版还带后桥限滑差速器,脱困能力更强。但探险者的价格终归比较高,退而求其次也可以看看全新换代的锐界L,整体实力也不差。新车指导价为22.98-30.98万元,目前终端优惠8800元左右。??优缺点速览优点:1、提供纯燃油和油电混动2、提…...

Facebook开户 | 如何检查公共主页的状态

想要了解你的Facebook公共主页的状态吗&#xff1f; Facebook公共主页是让广告主与粉丝互动、传播信息的绝佳平台&#xff0c;但是大家知道如何检查并维护自己的主页状态吗&#xff1f;别担心&#xff0c;Facebook提供了一系列简单易用的工具来帮助大家实现这一目标。 *Page Q…...

STM32定时器及输出PWM完成呼吸灯

文章目录 一、STM32定时器原理1、基本定时器2、通用定时器&#xff08;1&#xff09;时钟源&#xff08;2&#xff09;预分频器PSC&#xff08;3&#xff09;计数器CNT&#xff08;4&#xff09;自动装载寄存器ARR 3、高级定时器 二、PWM工作原理三、控制LED以2s的频率周期性地…...

分布式拒绝服务解决方式

在网络安全领域中&#xff0c;分布式拒绝服务&#xff08;DDoS&#xff09;攻击始终占据着举足轻重的地位&#xff0c;其影响力不容忽视。随着网络技术的日新月异和网络环境的日益复杂化&#xff0c;DDoS攻击不仅变得愈发频繁&#xff0c;而且其破坏性和影响力也呈现出惊人的增…...

构建 Terraform 模块的分步指南

文章目录 一、介绍二、了解 Terraform 模块的基础知识三、Terraform 模块剖析第 1 步&#xff1a;确定可重用组件第 2 步&#xff1a;创建模块结构第 3 步&#xff1a;定义模块的变量第 4 步&#xff1a;编写模块配置第 5 步&#xff1a;提供输出值第 6 步&#xff1a;在配置中…...