前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >教你写Spring组件

教你写Spring组件

作者头像
落寞的鱼丶
发布于 2022-02-22 12:34:45
发布于 2022-02-22 12:34:45
50900
代码可运行
举报
文章被收录于专栏:afjhahfhahajkafjhahfhahajk
运行总次数:0
代码可运行

前言

原文地址:https://www.cnblogs.com/qnlcy/p/15905682.html

一、宗旨

在如日中天的 Spring 架构体系下,不管是什么样的组件,不管它采用的接入方式如何眼花缭乱,它们永远只有一个目的:

接入Spring容器

二、Spring 容器

Spring 容器内可以认为只有一种东西,那就是 bean,但是围绕 bean 的生命周期,Spring 添加了许多东西

2.1 bean 的生命周期

2.1.1 实例化 bean 实例

实例化 bean 实例是 spring 针对 bean 作的拓展最多的周期

它包括:

  1. bean 的扫描
  2. bean 的解析
  3. bean 实例化

常见扫描相关内容:

@Component@Service@Controller@ConfigurationapplicationContext.xml

spring/springboot 在启动的时候,会扫描到这些注解或配置文件修饰的类信息

根据拿到的类信息,经过第二步解析后,转换成 BeanDefintion 存入到 spring 容器当中,BeanDefintion 描述 bean 的 class、scop、beanName 等信息

在 bean 的解析过程中,我们常用到的 Properties 读取 、 @Configuration 配置类的处理 会在这一步完成

bean 的实例化实际有自动完成和调用 getBean() 时候完成,还有容器初始化完毕之后实例化 bean ,他们都是根据 bean 的定义 BeanDefintion 来反射目标 bean 类,并放到 bean 容器当中

这就是大名鼎鼎的 bean 容器,就是一个 Map

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1JAVAprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
2.1.2 设置实例属性

这一阶段是 @Value@Autowired@Resource 注解起作用的阶段

2.1.3 bean 前置处理

BeanPostProcessor 前置处理方法

2.1.4 bean init 处理

@PostConstruct 注解起作用的阶段

2.1.5 bean 后置处理

BeanPostProcessor 后置处理方法

2.1.6 正常使用
2.1.7 bean 销毁

@PreDestroy 注解起作用的阶段

bean 的销毁过程中,主要的作用就是释放一些需要手动释放的资源和一些收尾工作,如文件归并、连接池释放等

在了解了 Spring bean 的生命周期后,我们接下来介绍自建 Spring 组件的接入方式

三、使用简单配置类接入方式

使用配置类接入 Spring ,一般需要搭配 PostConstruct 来使用,并且要确保 Spring 能扫描到配置

如,在组件 quartz-configable 1.0 版本当中,就是使用的这种方式

quartz-configable 需要扫描用户自定义的 job 来注册到 quartz-configable 自动创建的调度器 Scheduler 当中,并启动调度器 Scheduler

在注册 Job 的过程当中,又添加了自定义的 TriggerListener 监听器,来监听配置的变动,以动态调整 Job 执行时机

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789101112131415161718192021222324252627282930313233343536373839404142JAVA@Configuration
public class QuartzInitConfig {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private CustomTriggerListener customTriggerListener;

    @PostConstruct
    public void init() {
        //先把所有jobDetail放到map里
        initJobMap();

        //添加自定义Trigger监听器,进行任务开关的监听和故障定位的配置
        addTriggerListener(scheduler, customTriggerListener);

        //添加任务到任务调度器中
        addJobToScheduler(scheduler);

        //启动任务调度器
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            log.error("任务调度器启动失败", e);
            throw new RuntimeException("任务调度器启动失败");
        }
        log.info("任务调度器已启动");
    }

    private void initJobMap() {
        //省略部分代码
    }

    private void addJobToScheduler(Scheduler scheduler) {
        //省略部分代码
    }

    private void addTriggerListener(Scheduler scheduler, CustomTriggerListener customTriggerListener) {
        //省略部分代码
    }
}

QuartzInitConfig 类的作用是把扫描到的任务类放入调度器当中,并添加自定义监听(用于动态修改 cron 表达式)

此类加载有两个过程:

  1. 注入组件初始化需要的资源
  2. 根据注入的资源初始化组件

步骤 1 所需要的功能与 Spring 的注入功能完美契合,而恰好 @Configuration 修饰的类也被当作了一个 Spring bean,所以才能顺利注入组件需要的资源

步骤 2 的初始化任务,极为契合 Spring bean 创建完毕后的初始化动作 @PostConstruct 当中,它同样是资源注入完毕后的初始化动作。

四、带有条件的简单配置类

有时候,我们希望通过开关或者特定的配置来启用应用内具备的功能,这时候,我们可以使用 @ConditionalOnProperty 来解决问题

risk 组件扫描出符合规则的切点,在切点执行之前,去执行发送风控数据到风控平台的动作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1234567891011121314151617181920212223JAVA@Configuration
@ConditionalOnProperty({"risk.expression", "risk.appid", "risk.appsecret", "risk.url"})
public class RiskAspectConfig {

    //项目内配置
    @Value("${risk.expression}")
    private String riskExpression;

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        SpringBeans springBeans = springBeans();
        RiskSenderDelegate riskSenderDelegate = new RiskSenderDelegate(springBeans);
        GrjrMethodInterceptor grjrMethodInterceptor = new GrjrMethodInterceptor(riskSenderDelegate);
        JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
        jdkRegexpMethodPointcut.setPattern(riskExpression);
        log.info("切面准备完毕,切点为{}", riskExpression);
        return new DefaultPointcutAdvisor(jdkRegexpMethodPointcut, grjrMethodInterceptor);
    }

    //省略部分代码

}

虽然类 RiskAspectConfig 是一个 Spring 配置类,方法 defaultPointcutAdvisor() 创建了一个切点顾问,用来在切点方法处实现风控的功能,但是,并不是应用启动之后,切点就会生效,这是因为有 @ConditionalOnProperty 的存在

@ConditionalOnProperty 的作用: 根据提供的条件判断对应的属性是否存在,存在,则加载此配置类,不存在,则忽略。

当应用中存在如下配置时:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456YAMLgrjr:
  risk:
   expression: xxxx
   appid: xxx
   appsecret: xxx
   url: xxx

RiskAspectConfig 配置类才会被加载,才会生成切点顾问 DefaultPointcutAdvisor,因此切点就会生效

当需要的配置逐渐增多的时候,一条条添加进 @ConditionalOnProperty 显得比较冗长复杂,这时候该如何处理呢?

五、使用对应的 Properties 配置类来封装配置

在项目 fastdfs-spring-boot-starter 当中,像上述需要的配置有很多,那么它是怎么处理的呢?

它把需要的配置放到了一个 Java 类里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789101112JAVA@ConfigurationProperties(prefix = "fastdfs.boot")
public class FastDfsProperties {
    private String trackerServerHosts;
    private int trackerHttpPort = 80;
    private int connectTimeout = 5000;
    private int networkTimeout = 30000;
    private boolean antiStealToken = false;
    private String charset = "ISO8859-1";
    private String secretKey;

    //省略字段 get set 方法
}

其中, @ConfigurationProperties 指定了配置的 prefix ,上述配置相当于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789YAMLfastdfs:
  boot:
    trackerServerHosts: xxx
    trackerHttpPort: 80
    connectTimeout: 5000
    networkTimeout: 30000
    antiStealToken: false
    charset: ISO8859-1
    secretKey: xxx

这种类到现在为止还不可以和 Spring 结合起来,尚需要把它声明为 Spring bean 才生效

声明为 Spring bean 有两种形式

  • 在类本身上添加 @Component 注解,标识这是一个 Spring bean
  • @Configuration 类上使用 @EnableConfigurationProperties 来启用配置

通常的,在开发组件的时候,我们使用第二种方式,把 Properties 的启用,交给 @Configuration 配置类来管理,大家可以想想为什么

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码12345678910111213141516171819202122232425JAVA@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(FastDfsClient.class) // 当 Spring 容器中不存在 FastDfsClient 时才加载这个类
@EnableConfigurationProperties(FastDfsProperties.class) //启用上面的 FastDfsProperties
public class FastDfsAutoConfiguration {

    /**
    * 创建 FastDfsClient 放到 Spring 容器当中
    */
    @Bean
    @ConditionalOnProperty("fastdfs.boot.trackerServerHosts")
    FastDfsClient fastDFSClient(FastDfsProperties fastDfsProperties) {
        globalInit(fastDfsProperties);
        return new FastDfsClient();
    }

    /**
    * 根据 properties 来配置 fastdfs
    */
    private void globalInit(FastDfsProperties fastDFSProperties) {
        // 省略部分代码
    }

    //省略部分代码
}

@EnableConfigurationProperties(FastDfsProperties.class) 启用了括号内的 Properties 类,并把它们注入到 Spring 容器当中,使其可以被其他 Spring bean 导入

六、使用 META-INF/spring.factories 文件来代替扫描

有时候,我们开发的组件的类路径和应用的类路径不同,比如,应用类路径常常为 com.xxx.xxx,而组件的类路径常常为 com.xxx.yyy,这时候,经常需要为 Spring 指定扫描路径,才能把我们的组件加载进去,如果在自己项目当中加载上述 quartz-configable 组件,组件类路径为 com.xxx.yyy

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码12345678JAVA@ComponentScan({"com.xxx.xxx", "com.xxx.yyy"})
@SpringBootApplication
public class GrjrFundBatch {

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

如果新增了类似这样的 quartz-configable 组件,就需要改动 @ComponentScan 代码,这对启动类是有侵入性的,也是繁琐的,也极有可能写错,当组件路径有改动的时候也需要跟着改动

怎样避免这种硬编码形式的注入呢?

Springboot 在加载类的时候,会扫描 classpath 下的 META-INF/spring.factories 文件,当发现了 spring.factories 文件后,根据文件中的配置来加载类

其中一项配置为 org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx.xxx.xxx.xxxx ,它声明了 Springboot 要加载的自动配置类,Springboot根据配置自动去加载配置类

借用这个规则,现在来升级我们的 quartz-configable 组件

我们在组件项目 resources 目录下添加 META-INF/spring.factories 文件,文件内容如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1PROPERTIESorg.springframework.boot.autoconfigure.EnableAutoConfiguration=com.grjr.quartz.config.GjSchedulerAutoConfiguration

然后在应用启动类当中删除已经无用的 @Component 注解即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1234567JAVA@SpringBootApplication
public class Application {

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

此时,quartz-configable 依然能生效

使用 META-INF/spring.factories 虽然带来了简洁和便利,但是它总是去自动加载配置类,所以我们在设计组件的时候,一定要搭配 @ConditionOnxxxx 注解,有条件的去加载我们的组件

七、使用自定义 @EnableXxxx 注解的形式开启组件功能

就像上面说的一样,使用 META-INF/spring.factories 总会去加载配置类,自定义扫描路径有可能会写错类路径,那么,还有没有其他方式呢?

有,使用自定义注解来注入自己的组件,就像 dubbo 的 starter 组件一样,我们自己造一个 @EnableXxx 注解

7.1 自定义注解的核心

自定义注解的核心是 Spring 的 @Import 注解,它基于 @Import 注解来注入组件自身需要的资源和初始化组件自身

7.2 @Import 注解解析

@Import 注解是 Spring 用来注入 Spring bean 的一种方式,可以用来修饰别的注解,也可以直接在 Springboot 配置类上使用。

它只有一个value属性需要设置,来看一下源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123JAVApublic @interface Import {
    Class<?>[] value();
}

这里的 value属性只接受三种类型的Class:

  • @Configuration 修饰的配置类
  • 接口 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 的实现类
  • 接口 org.springframework.context.annotation.ImportSelector 的实现类

下面针对三种类型的 Class 分别做简单介绍,中间穿插自定义注解与外部配置的结合使用方式。

7.2.1 被@Configuration 修饰的配置类

像 Springboot 中的配置类一样正常使用,需要注意的是,如果该类的包路径已在 Springboot 启动类上配置的扫描路径下,则不需要再重新使用 @Import 导入了,因为 @Import 的目的是注入 bean,但是 Springboot 启动类自动扫描已经可以注入你想通过 @Import 导入的 bean 了。

7.2.2 接口 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 的实现类

@Import 修饰自定义注解时候,通常会导入这个接口的实现类。

来看一下接口定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码12345678910111213JAVApublic interface ImportBeanDefinitionRegistrar {
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
            BeanNameGenerator importBeanNameGenerator) {
        registerBeanDefinitions(importingClassMetadata, registry);
    }

    /**
    * importingClassMetadata 被@Import修饰的自定义注解的元信息,可以获得属性集合
    * registry Spring bean注册中心
    **/
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    }

通过这种方式,我们可以根据自定义注解配置的属性值来注入 Spring Bean 信息。

来看如下案例,我们通过一个注解,启动 RocketMq 的消息发送器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1234567JAVA@SpringBootApplication
@EnableMqProducer(group="xxx")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

这是一个服务项目的启动类,这个服务开启了 RocketMq 的一个发送器,并且分到 xxx 组里。

来看一下 @EnableMqProducer 注解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789101112JAVA@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({XXXRegistrar.class,XXXConfig.class})
public @interface EnableMqProducer {

    String group() default "DEFAULT_PRODUCER_GROUP";

    String instanceName() default "defaultProducer";

    boolean retryAnotherBrokerWhenNotStoreOK() default true;
}

这里使用 @Import 导入了两个配置类,第一个是接口 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 的实现类,第二个是被 @Configuration 修饰的配置类

我们看第一个类 XXXRegistrar,这个类的功能是注入一个自定义的 DefaultMQProducer 到Spring 容器中,使业务方可以直接通过 @Autowired 注入 DefaultMQProducer 使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码1234567891011121314151617181920212223JAVApublic class XXXRegistrar implements ImportBeanDefinitionRegistrar {  
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //获取注解里配置的属性
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableMqProducer.class.getName()));
        //根据配置的属性注入自定义 bean 到 spring 容器当中
        registerBeanDefinitions(attributes, registry);
    }

    private void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        //获取配置
        String group = attributes.getString("group");
        //省略部分代码...
        //添加要注入的类的字段值
        Map<String, Object> values = new HashMap<>();
        //这里有的同学可能不清楚为什么key是这个
        //这里的key就是DefaultMQProducer的字段名
        values.put("producerGroup", group);
        //省略部分代码

        //注册到Spring中
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, DefaultMQProducer.class.getName(), DefaultMQProducer.class, values);
    }

到这里,我们已经注入了一个 DefaultMQProducer 的实例到 Spring 容器中,但是这个实例,还不完整,比如:

  • 还没有启动
  • nameServer地址还没有配置
  • 外部配置的属性还没有覆盖实例已有的值(nameServer地址建议外部配置)。

但是好消息是,我们已经可以通过注入来使用这个未完成的实例了。

上面遗留的问题,就是第二个类接下来要做的事。

来看第二个配置类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789101112131415161718192021222324252627282930JAVA@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@EnableConfigurationProperties(XxxProperties.class)  //Spring提供的配置自动映射功能,配置后可直接注入 
public class XXXConfig {

    @Resource //直接注入
    private XxxProperties XxxProperties;

    @Autowired //注入上一步生成的实例
    private DefaultMQProducer producer;

    @PostConstruct
    public void init() {
        //省略部分代码
        //获取外部配置的值
        String nameServer = XxxProperties.getNameServer();
        //修改实例
        producer.setNamesrvAddr(nameServer);
        //启动实例
        try {
            this.producer.start();
        } catch (MQClientException e) {
            throw new RocketMqException("mq消息发送实例启动失败", e);
        }
    }

    @PreDestroy
    public void destroy() {
        producer.shutdown();
    }

到这里,通过自定义注解和外部配置的结合,一个完整的消息发送器就可以使用了,但方式有取巧之嫌,因为在消息发送器启动之前,不知道还有没有别的类使用了这个实例,这是不安全的。

7.2.3 接口org.springframework.context.annotation.ImportSelector的实现类

首先看一下接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
复制代码123456789101112131415JAVApublic interface ImportSelector {

    /**
     * importingClassMetadata 注解元信息,可获取自定义注解的属性集合
     * 根据自定义注解的属性,或者没有属性,返回要注入Spring的Class全限定类名集合
     如:XXX.class.getName(),Spring会自动注入XXX的一个实例
     */
    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }

}

这个接口的实现类如果没有进行 Spring Aware 接口拓展,功能比较单一,因为我们无法参与 Spring Bean 的构建过程,只是告诉 Spring 要注入的 Bean 的名字。不再详述。

八、总结

综上所述,我们一共聊了三种形式的组件创建方式

  • 相同路径下, @Configuration 修饰的配置类
  • 使用 META-INF/spring.factories 文件接入
  • 结合 @Import 注解注入

其中穿插了 @ConditionOnXxxx 选择性启动、Properties 封装的技术,快去试一下吧

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
打开我的收藏夹 -- Python数据分析杂谈
Json是一种轻量级的数据交换格式,具有数据格式简单,读写方便易懂等很多优点。用它来进行前后端的数据传输,大大的简化了服务器和客户端的开发工作量。
看、未来
2021/09/18
5510
Python爬虫数据抽取(一):解析库json及jsonpath pickle
Python爬虫数据抽取(一):解析库json及jsonpath pickle
Java架构师必看
2021/05/14
6200
Python爬虫数据抽取(一):解析库json及jsonpath pickle
python处理JSON
JSON是JavaScript Object Notation的缩写,它是一种数据交换格式。在web网络传输数据的时候,我们经常会遇到JSON数据。
皮大大
2023/08/25
4250
【python接口自动化】- 使用json及jsonpath转换和提取数据
​ JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它可以让人们很容易的进行阅读和编写,同时也方便了机器进行解析和生成,适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。简单说就是javascript中的对象和数组,通过这两种结构可以表示各种复杂的结构。
huofo
2022/03/18
2.4K0
【python接口自动化】- 使用json及jsonpath转换和提取数据
利用Python搞定json数据<建议收藏>
在实际工作中,尤其是web数据的传输,我们经常会遇到json数据。它不像常见的文本数据、数值数据那样友好,而且它和Python中的字典类型数据又很相像,给很多人造成了困扰。
皮大大
2021/02/27
2.6K0
Python数据提取Json
参考链接: Python-Json 2 : 使用json.load/loads读取JSON文件/字符串
用户7886150
2021/01/15
3.3K0
数据提取之JSON与JsonPATH
我们知道再爬虫的过程中我们对于爬取到的网页数据需要进行解析,因为大多数数据是不需要的,所以我们需要进行数据解析,常用的数据解析方式有正则表达式,xpath,bs4,这次我们来介绍一下另一个数据解析库--jsonpath,在此之前我们需要先了解一下什么是json。
前端皮皮
2021/12/02
2.2K0
数据提取之JSON与JsonPATH
Python解析JSON数据教程
JSON格式是网站和API使用的通用标准格式,现在主流的一些数据库(如PostgreSQL)都支持JSON格式。在本文中,我们将介绍如何使用Python处理JSON数据。首先,让我们先来看看JSON的定义。
用户7850017
2021/10/29
4.4K0
Python解析JSON数据教程
上手python之json数据格式
主要功能:json就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互. 类似于:
一个风轻云淡
2022/11/15
4030
上手python之json数据格式
在Python中处理JSON数据的常见问题与技巧
当今互联网时代,JSON(JavaScript Object Notation)已成为一种广泛使用的数据交换格式。在Python中,我们经常需要处理JSON数据,包括解析JSON数据、创建JSON数据、以及进行JSON数据的操作和转换等。本文将为你分享一些在Python中处理JSON数据的常见问题与技巧,帮助你更好地应对JSON数据的处理任务。
华科云商小彭
2023/09/26
3760
在Python中处理JSON数据的常见问题与技巧
Python爬虫(十六)_JSON模块与JsonPath
本篇将介绍使用,更多内容请参考:Python学习指南 数据提取之JSON与JsonPATH JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它是的人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。 JSON和XML的比较可谓不相上下。 Python2.7中自带了JSON模块,直接import json就可以使用了。 官方博客:http://docs.python.org/library/
用户1174963
2018/01/17
2.4K0
Python爬虫(十六)_JSON模块与JsonPath
Python处理json总结
JSON:JavaScript Object Notation 【JavaScript 对象表示法】
吾非同
2020/10/23
1.3K0
Python处理json总结
python︱处理与使用json格式的数据(json/UltraJSON/Demjson)、pickle模块、yaml模块
python种关于json有很多,simplejson,cjson,还有ujson(详细内容可见:http://blog.csdn.net/gzlaiyonghao/article/details/6567408). cjson模块只支持string/unicode的key JSON(JavaScript Object Notation)编码格式的数据。
悟乙己
2022/05/09
1K0
Python爬虫:jsonpath强势来袭
JSON包括六个构造字符,分别是:左方括号、右方括号、左大括号、右大括号、冒号与逗号。
我被狗咬了
2021/01/28
3.9K0
Python 中怎样做数据交换格式
JSON 格式采用键值对的方式表达信息。它的值可以是对象、数组、字符串、整数、浮点数、布尔型或空值。下面是一个 JSON 数据的例子:
程序猿川子
2024/06/17
1190
Python 中怎样做数据交换格式
干货 | 如何利用Python处理JSON格式的数据,建议收藏!!!
JSON数据格式在我们的日常工作中经常会接触到,无论是做爬虫开发还是一般的数据分析处理,今天,小编就来分享一下当数据接口是JSON格式时,如何进行数据处理进行详细的介绍,内容分布如下
用户6888863
2020/07/15
2.3K0
C++搭建集群聊天室(五):JSON序列化与反序列化
Json是一种轻量级的数据交换格式,具有数据格式简单,读写方便易懂等很多优点。用它来进行前后端的数据传输,大大的简化了服务器和客户端的开发工作量。
看、未来
2021/09/18
1.1K0
Python中JSON的基本使用
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它主要提供了四个方法: dumps、dump、loads、load。
py3study
2020/01/06
3.5K0
Json数据
JSON(JavaScript Object Notation,即JavaScript对象表示法)是一种轻量级的数据交换格式。它独立于语言和平台,JSON解析器和JSON库支持不同的编程语言。JSON具有自我描述性,很容易理解。目前大多数接口返回的数据格式为JSON,因此进行接口测试必须掌握JSON。
清风穆云
2021/08/09
1.5K0
python对json的操作总结
Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式。Json最广泛的应用是作为AJAX中web服务器和客户端的通讯的数据格式。现在也常用于h
周小董
2019/03/25
1.3K0
python对json的操作总结
推荐阅读
相关推荐
打开我的收藏夹 -- Python数据分析杂谈
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文