Spring源码阅读之PropertySource

Spring @PropertySource用法和源码分析 用法 https://mkyong.com/spring/spring-propertysources-example/ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nh5bKk0V-1620551204402)(C:\Users\Lv Hao\AppData\Roaming\Typora\typora-user-images\image-20210509144724369.png)] 核心类 Properties [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下 阅读详情

试问,一篇文章一半的字不认识,你能理解讲了什么故事吗?Spring中大部分的类你都陌生,你能读懂?顶多是死记硬背罢了!

本文带你了解Spring中的存储属性资源的类-PropertySource

最佳打开方式:自己一边手动翻看源码,一边对照阅读。文章中粘出的代码都很容易,慢慢啃,绝对有收获!

一、PropertySource

public abstract class PropertySource<T> {

	protected final String name;
	protected final T source;
	public String getName() {
		return this.name;
	}
	public T getSource() {
		return this.source;
	}
	public boolean containsProperty(String name) {
		return (getProperty(name) != null);
	}
	public abstract Object getProperty(String name);
}

最上层的类PropertySource是一个抽象类,只有2个属性,name和泛型定义的source,而且是final标注的,表明赋值后不可修改。方法也很简单,用来获取属性。

下面是类关系图:

 看着很复杂,但其实仔细看可以发现,以PropertySource为基础,一共能分为2部分:左边的EnumerablePropertySource为一部分,剩下右边的为一部分,接下来,我们来看看这两部分分别是干什么的。

二、右半部分

这部分是直接继承自PropertySource,而且没有子类,如下图中用红框圈出的部分:

2.1 JndiPropertySource

该类的作用是从底层Spring JndLocatorDelegate读取属性,要查找的名称将自动以“java:comp/env/”作为前缀。

public class JndiPropertySource extends PropertySource<JndiLocatorDelegate> {

	public JndiPropertySource(String name) {
		this(name, JndiLocatorDelegate.createDefaultResourceRefLocator());
	}

	public JndiPropertySource(String name, JndiLocatorDelegate jndiLocator) {
		super(name, jndiLocator);
	}

	public Object getProperty(String name) {
		if (getSource().isResourceRef() && name.indexOf(':') != -1) {
			return null;
		}

		try {
			Object value = this.source.lookup(name);
			if (logger.isDebugEnabled()) {
				logger.debug("JNDI lookup for name [" + name + "] returned: [" + value + "]");
			}
			return value;
		}
		catch (NamingException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("JNDI lookup for name [" + name + "] threw NamingException " +
						"with message: " + ex.getMessage() + ". Returning null.");
			}
			return null;
		}
	}
}

JNDI即Java Naming and Directory Interface(JAVA命名和目录接口)。为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。

2.2 RandomValuePropertySource

该类为任何以"random."开头的属性返回一个随机值,主要代码如下:

public class RandomValuePropertySource extends PropertySource<Random> {
	public static final String RANDOM_PROPERTY_SOURCE_NAME = "random";
	private static final String PREFIX = "random.";
	public RandomValuePropertySource() {
		this(RANDOM_PROPERTY_SOURCE_NAME);
	}
	public RandomValuePropertySource(String name) {
		super(name, new Random());
	}
	@Override
	public Object getProperty(String name) {
		if (!name.startsWith(PREFIX)) {
			return null;
		}
		logger.trace(LogMessage.format("Generating random property for '%s'", name));
		return getRandomValue(name.substring(PREFIX.length()));
	}

	private Object getRandomValue(String type) {
		if (type.equals("int")) {
			return getSource().nextInt();
		}
		if (type.equals("long")) {
			return getSource().nextLong();
		}
		String range = getRange(type, "int");
		if (range != null) {
			return getNextIntInRange(Range.of(range, Integer::parseInt));
		}
		range = getRange(type, "long");
		if (range != null) {
			return getNextLongInRange(Range.of(range, Long::parseLong));
		}
		if (type.equals("uuid")) {
			return UUID.randomUUID().toString();
		}
		return getRandomBytes();
	}

这里举几个例子来说明用法:

class test{
    public static void main(String[] args) {
        RandomValuePropertySource random = new RandomValuePropertySource();
        System.out.println(random.getProperty("random.int"));//生成int随机数
        System.out.println(random.getProperty("random.int(100,200)"));//指定范围
        System.out.println(random.getProperty("random.long"));//生成long随机数
        System.out.println(random.getProperty("random.long(200,300)"));//指定范围
        System.out.println(random.getProperty("random.uuid"));//生成随机uuid
    }
}

​

 2.3 AnsiPropertySource

该类的作用是用来获取AnsiStyle形式的属性,使用的地方在SpringBoot的banner中。

代码如下:

public class AnsiPropertySource extends PropertySource<AnsiElement> {

	private static final Iterable<Mapping> MAPPINGS;

	static {
		List<Mapping> mappings = new ArrayList<>();
		mappings.add(new EnumMapping<>("AnsiStyle.", AnsiStyle.class));
		mappings.add(new EnumMapping<>("AnsiColor.", AnsiColor.class));
		mappings.add(new Ansi8BitColorMapping("AnsiColor.", Ansi8BitColor::foreground));
		mappings.add(new EnumMapping<>("AnsiBackground.", AnsiBackground.class));
		mappings.add(new Ansi8BitColorMapping("AnsiBackground.", Ansi8BitColor::background));
		mappings.add(new EnumMapping<>("Ansi.", AnsiStyle.class));
		mappings.add(new EnumMapping<>("Ansi.", AnsiColor.class));
		mappings.add(new EnumMapping<>("Ansi.BG_", AnsiBackground.class));
		MAPPINGS = Collections.unmodifiableList(mappings);
	}
}

定义了颜色、字体风格、背景等。

使用的时候,在banner.txt中如下:

${AnsiColor.BRIGHT_YELLOW}${AnsiStyle.BOLD}
__  _  ___________  ___
\ \/ \/ /\____ \  \/  /
 \     / |  |_> >    <
  \/\_/  |   __/__/\_ \
         |__|        \/
${AnsiColor.CYAN}${AnsiStyle.BOLD}
::  Java                 ::  (v${java.version})
::  Spring Boot          ::  (v${spring-boot.version})
${Ans

那么启动的时候,解析过程会调用该类,结果如下:

​

3.3 ConfigurationPropertySourcesPropertySource

这个类没有特别的地方,是为了便于这些属性资源可以与PropertySolver一起使用或添加到 Environment中。

这个类后续讲 Environment和PropertySolver会说到。

3.4 FilteredPropertySource

这个类使用来过滤掉一些指定的属性,代码如下:

class FilteredPropertySource extends PropertySource<PropertySource<?>> {

	private final Set<String> filteredProperties;

	FilteredPropertySource(PropertySource<?> original, Set<String> filteredProperties) {
		super(original.getName(), original);
		this.filteredProperties = filteredProperties;
	}

	@Override
	public Object getProperty(String name) {
		if (this.filteredProperties.contains(name)) {
			return null;
		}
		return getSource().getProperty(name);
	}
}

该类支持把别的PropertySource传入,并且指定一个特定的集合,查询的时候,指定集合中的属性返回null。

三、左半部分

右半部分说完,我们来看左半部分,左边都是PropertySource的子类EnumerablePropertySource类的派生类,如下:

​

我们先来看EnumerablePropertySource,这个看名字含义是:可枚举的PropertySource,代码如下:

public abstract class EnumerablePropertySource<T> extends PropertySource<T> {

	public EnumerablePropertySource(String name, T source) {
		super(name, source);
	}
	protected EnumerablePropertySource(String name) {
		super(name);
	}
	@Override
	public boolean containsProperty(String name) {
		return ObjectUtils.containsElement(getPropertyNames(), name);
	}

	public abstract String[] getPropertyNames();

}

和名字一样,只是比父类多了一个抽象方法,用于获取source中的所有属性名字。

子类都很类似,都是获取属性的一些方法,我们这里主要讲一下MapPropertySource和他的子类。

3.1 MapPropertySource

该类作用和名字意思一样,指定了父类中T source中泛型类型,为map。实现了父类EnumerablePropertySource的方法,获取了map中key的集合。

public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {

	public MapPropertySource(String name, Map<String, Object> source) {
		super(name, source);
	}
	@Override
	@Nullable
	public Object getProperty(String name) {
		return this.source.get(name);
	}
	@Override
	public boolean containsProperty(String name) {
		return this.source.containsKey(name);
	}
	@Override
	public String[] getPropertyNames() {
		return StringUtils.toStringArray(this.source.keySet());
	}

}

3.2 DefaultPropertiesPropertySource

该类是MapPropertySource的子类,类中与父类与众不同的方法都加了注释:

下面代码中出现的PropertySources和PropertySource不是一回事,和名字意思一样,PropertySources中包含了多个PropertySource。

public class DefaultPropertiesPropertySource extends MapPropertySource {

	public static final String NAME = "defaultProperties";
    //入参中的propertySource名字是否和当前类一样
	public static boolean hasMatchingName(PropertySource<?> propertySource) {
		return (propertySource != null) && propertySource.getName().equals(NAME);
	}
	//参数校验通过后,将入参source带入action中执行
	public static void ifNotEmpty(Map<String, Object> source, Consumer<DefaultPropertiesPropertySource> action) {
		if (!CollectionUtils.isEmpty(source) && action != null) {
			action.accept(new DefaultPropertiesPropertySource(source));
		}
	}

	//将给定的map添加到sources中,或者合sources中的名字为NAME的source合并
	public static void addOrMerge(Map<String, Object> source, MutablePropertySources sources) {
		if (!CollectionUtils.isEmpty(source)) {
			Map<String, Object> resultingSource = new HashMap<>();
			DefaultPropertiesPropertySource propertySource = new DefaultPropertiesPropertySource(resultingSource);
			if (sources.contains(NAME)) {
				mergeIfPossible(source, sources, resultingSource);
				sources.replace(NAME, propertySource);
			}
			else {
				resultingSource.putAll(source);
				sources.addLast(propertySource);
			}
		}
	}

	@SuppressWarnings("unchecked")
	private static void mergeIfPossible(Map<String, Object> source, MutablePropertySources sources,
			Map<String, Object> resultingSource) {
		PropertySource<?> existingSource = sources.get(NAME);
		if (existingSource != null) {
			Object underlyingSource = existingSource.getSource();
			if (underlyingSource instanceof Map) {
				resultingSource.putAll((Map<String, Object>) underlyingSource);
			}
			resultingSource.putAll(source);
		}
	}
    //将propertySources中名字为NAME("defaultProperties")的source移动到最后
	public static void moveToEnd(MutablePropertySources propertySources) {
		PropertySource<?> propertySource = propertySources.remove(NAME);
		if (propertySource != null) {
			propertySources.addLast(propertySource);
		}
	}

}

四、总结

通过这么多类的说明,大家应该对PropertySource有了深刻的理解,说白了就是对属性资源的操作类,Spring根据不同的使用场景实现了不同的类。


觉得有帮助的同学不妨点个赞吧!你的支持是我写作的最大动力,谢谢!

Spring Boot源码解析:RandomValuePropertySource的工作原理 Spring Boot是一个流行的Java框架,用于构建独立的、生产级别的Spring应用程序。RandomValuePropertySource是Spring Boot中一个特殊的PropertySource实现,它提供了生成随机值的能力。在本文中,我们通过源代码解析了RandomValuePropertySource的实现细节,了解了它是如何工作的。RandomValuePropertySource是Spring Boot中的一个内置PropertySource实现,它允许我们在配置文件中使用随机值。 阅读详情

相关推荐

SpringIOC之PropertySource

占位符和默认值:你可以在属性文件中使用占位符,并在属性值中引用这些占位符。Spring 将自动解析这些占位符并替换为相应的属性值。例如:

qq_57756904的博客 1060

Spring高级之注解@PropertySource详解(超详细)

定义/作用 @PropertySource注解用于指定资源文件读取的位置,它不仅能读取properties文件,也能读取xml文件,并且通过YAML解析器,配合自定义PropertySourceFactory实现解析YAML文件。 源码: //只能作用在类上 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(PropertySources.class) public @interface

qq_40837310的博客 5万+

SpringBoot集成SpringSecurity5和OAuth2 — 2、OAuth2客户端【SSO单点登录时作为客户端】

SpringBoot集成SpringSecurity5和OAuth2 — 2、OAuth2客户端【SSO单点登录时作为客户端】

Mr_XiMu的博客 3739

浅析PropertySource 基本使用

文章目录一、PropertySource 简介二、@PropertySource与Environment读取配置文件三、@PropertySource与@Value读取配置文件@Value 基本使用@Value 高级用法四、@PropertySource 与 @Import 一、PropertySource 简介 ​ org.springframework.context.annotation...

程序员cxuan的个人主页 6996

手把手教你用NetToPLCsim搭建西门子S7-1200仿真环境(附避坑指南)

本文详细指导如何利用NetToPLCsim与PLCSIM搭建西门子S7-1200仿真环境,实现无硬件条件下的PLC程序测试与上位机通信开发。内容涵盖软件选型、环境部署、关键参数配置及通信测试,并重点提供了连接失败、数据读写错误等常见问题的深度避坑指南,帮助工程师高效构建可靠的虚拟调试工作流。

a3b4c5的博客 610

DEAP数据集实战:用PyTorch搭建DNN/CNN脑电情绪识别模型(附完整代码)

本文详细介绍了如何使用PyTorch搭建DNN和CNN模型对DEAP数据集进行脑电情绪识别。从数据预处理到模型架构设计,再到训练优化和部署,提供了完整的实战指南和代码示例,帮助研究者快速掌握脑电信号识别技术。

k8l9m0n的博客 392

Spring Boot 中的 PropertySource 是什么,原理,如何使用

首先,您需要在应用程序中定义属性。在上面的代码中,我们定义了两个属性:myapp.name 和 myapp.version。这些属性将在应用程序中使用。

程序猿徐师兄的博客 1910

WSL 2 部署 Rocky Linux 9:从零到生产环境配置指南(2025版)

本文详细介绍了如何在WSL 2上部署Rocky Linux 9,从环境准备到生产环境配置的全流程指南。通过优化安装流程和系统配置,帮助开发者和运维工程师在Windows环境下高效运行企业级Linux系统,特别适合需要本地开发但部署到RHEL系服务器的项目。

weixin_28455801的博客 479

Spring源码阅读之PropertySources

试问,一篇文章一半的字不认识,你能理解讲了什么故事吗?Spring中大部分的类你都陌生,你能读懂?顶多是死记硬背罢了! 本文带你了解Spring中的存储属性资源的类-PropertySources 最佳打开方式:自己一边手动翻看源码,一边对照阅读。文章中粘出的代码都很容易,慢慢啃,绝对有收获! 一、PropertySources ...

1895

Windows 10/11 安装 HYSPLIT 气象模型全攻略(附必备工具包下载清单)

本文提供了一份详尽的Windows 10/11系统下HYSPLIT气象模型安装与配置全攻略。指南涵盖了从核心认知、必备工具包(Tcl/Tk、ImageMagick)下载,到分步安装、环境变量设置及首次运行验证的完整流程,旨在帮助研究者和学生高效部署这一用于大气轨迹模拟与污染物扩散分析的专业工具。

weixin_28335283的博客 607

FFmpeg音频转换避坑实录:为什么VOS的REC转MP3比WAV转MP3体积小一半?

本文深入解析了FFmpeg在VOS系统REC格式音频转换中的优化技巧,揭示了REC转MP3比WAV转MP3体积小一半的原因。通过分析REC格式的压缩特性、转码参数陷阱及FFmpeg调优方法,帮助开发者实现高效音频转换,显著降低存储成本。

weixin_30752699的博客 526

spring 源码系列(三)- PropertySource和Environment

注:本章内容主要是作为springboot的run()方法中的环境预准备prepareEnvironment()方法的预备知识,其中本章的environment部分可能比较抽象,不是很好理解,这并没有什么问题,只要大概明白即可,后续阅读prepareEnvironment()方法时会加深理解。 1 @PropertySource 1.1 使用 最常见的使用方法是与@Value搭配: @Comp...

bintoYu的博客 966

SAP PS 收入确认方法配置清单(成本推导收入 / 项目进度推导收入)

摘要:本文详细介绍了SAPPS模块中两种收入确认方法的配置流程:成本推导收入(成本比例法)和项目进度推导收入(里程碑法)。通过事务码OKG1-OKG5等关键配置步骤,分别实现基于累计成本比例和里程碑完成权重的收入确认逻辑。文章对比了两种方法的适用场景和管控要点:成本法适用于成本与进度强相关的项目,需严控预计总成本;进度法则依赖明确的里程碑验收。同时提供了落地建议,包括项目类型绑定、数据校验和变更管控等最佳实践,为SAPPS系统收入确认功能实施提供完整指导。

金牌架构师 952

spring 源码系列(零)- 阅读顺序

之所以有这个第“零”篇,是为了让大家对spring体系有着更好的认识,因此在这里推荐大家阅读知乎的大神bravo1988的一篇关于spring的文章,这篇文章很生动具体,可以说是让我茅塞顿开: 传送门:怎么回答面试官:你对Spring的理解? 本篇就只有这么多,后续的几篇会对spring的一些源码进行详细的介绍。 ...

bintoYu的博客 1450

上海计算机学会2020年5月月赛C++乙组T2经济普查

中国正在以前所未有的力度推进脱贫攻坚,国家计划在2020年使得在现行标准下的贫困人口实现全面脱贫,为此,需要对居民的经济状况进行普查。 题目描述 给定一个正整数n,表示人口数量。一开始,每个居民拥有的财产记为a1​,a2​,⋯,an​,财产可能发生两种变化: 一种来源于个体,由某个居民的经济活动而产生。在某个时刻,某个居民的财产会直接变成某个数值,可能升高也可能降低。 一种来源于政策,在某个时刻,国家会对财产低于某个标准线全部的居民,实施政策支持,使得他们的财产全部正好到达标准线。 给定这些变

长春高老师编程 903

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

spring 源码阅读之@Configuration解析

然后解析的到的配置bean会经过ConfigurationClassParser类进行配置解析,具体解析方法在processConfigurationClass,真正解析方法doProcessConfigurationClass。@Configuration注解用于标识一个类是配置类,用于声明和组织Bean定义,首先@Configuration本身也是一个@Component,在其注解定义上标有@Component。配置bean里可以通过方法上@Bean注解进行bean的定义。

sinat_16493273的博客 336

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Spring中PropertySource属性源配置文件的优先级、顺序问题大解析(加载流程)【享学Spring】

前言 我相信关于Spring的配置文件的优先级、加载顺序一直是个老生常谈的问题,即使经常被提起,但却还是一个非常容易就被遗忘或者弄混的知识点。 如果你度娘上去搜索:Spring Boot 配置顺序等关键字,会发现解释的文章非常之多,但每每够是过眼云烟,事后没多久就忘了。 我个人经验总结若想把这块变成永久记忆,一种方式就是理解作者的设计意图,掌握设计思想。另外一种就是把它落实在源码上,毕竟查源码找顺...

架构师:通透,才能写出好代码! 9527

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

基于Spring Boot的Environment源码理解实现分散配置详解

前提 org.springframework.core.env.Environment是当前应用运行环境的公开接口,主要包括应用程序运行环境的两个关键方面:配置文件(profiles)和属性。Environment继承自接口PropertyResolver,而PropertyResolver提供了属性访问的相关方法。这篇文章从源码的角度分析Environment的存储容器和加载流程,然后基于源码的理解给出一个生产级别的扩展。 本文较长,请用一个舒服的姿势阅读。 Environment类体系 Pr

CarloPan的博客 808

Spring 源码阅读 03:初始化 Spring 上下文信息

在 propertyResolver 被创建的时候,requiredProperties 会被初始化为一个空集合,我们可以在代码中通过调用它的 setRequiredProperties 方法,向 requiredProperties 参数名。这个方法中并没有任何实现逻辑,而且是 protected 修饰的,因此,这里是一个扩展点,子类可以通过重写这个方法来使用实例替换 XML 文件中的${}占位符,这里只是给占位符提供一个实例作为替换内容,并未进行替换的操作,实际的替换操作在后续的流程中。

知识分享官 384

Spring 源码学习(一)-容器的基础结构

点击上方“蓝字”技术的故事还有很多 只想与你静静分享N和我公众号后台回复“java”,获得作者Java知识体系/面试必看资料Hello,大家好,我是子悠,今天是...

Java极客技术 309

spring environment_Spring 源码学习(一)-容器的基础结构

本篇笔记主要记录了以下内容:使用 ClassPathXmlApplicationContext,通过在 xml 注册一个 bean,跟踪代码,了解它从配置文件的 标签,加载到 BeanFactory 注册表 beanDefinitionMap 的详细过程。layout: post- ClassPathXmlApplicationContext - 设置配置文件路径 - Profile - Pro...

weixin_39668890的博客 225

跟我一起阅读SpringBoot源码(三)——ConfigurableEnvironment

StandardServletEnvironment前情回顾继承与实现关系MutablePropertySources自定义属性源StandardEnvironment#customizePropertySourcesgetSystemEnvironmentgetSystemPropertiesStandardServletEnvironment#customizePropertySources 前情回顾 前面有讲到ConfigurableEnvironment,然后springBoot启动的时候就会去准备

小小的人儿的博客 2528

通过 applicationcontext 获取value_Spring官网阅读(十一)ApplicationContext详细介绍(上)...

点击上方IT牧场,选择置顶或者星标技术干货每日送达!目录1、ApplicationContext的继承关系2、ApplicationContext的功能Spring中的国际化(MessageSource)Spring中的环境(Environment)总结在前面的文章中,我们已经完成了官网中关于IOC内容核心的部分。包括容器的概念,Spring创建Bean的模型BeanDefinit...

weixin_39604045的博客 758

Spring官网阅读(十一)ApplicationContext详细介绍(上)

在前面的文章中,我们已经完成了官网中关于IOC内容核心的部分。包括容器的概念,Spring创建Bean的模型BeanDefinition的介绍,容器的扩展点(BeanFactoryPostProcessor,FactroyBean,BeanPostProcessor)以及最重要的Bean的生命周期等。接下来大概还要花三篇文章完成对官网中第一大节的其它内容的学习,之所以要这么做,是笔者自己粗读了一...

做一个认真的程序员 4323

Spring 源码学习(一)容器的基础结构

`Spring` 是这样加载 `xml` 配置的 [TOC] 本篇笔记主要记录了以下内容: 使用 ClassPathXmlApplicationContext,通过在 xml 注册一个 bean,跟踪代码,了解它从配置文件的 <bean> 标签,加载到 BeanFactory 注册表 beanDefinitionMap 的详细过程。 展示的代码摘取了一些核心方法,去掉一些默认设...

weixin_33767813的博客 302

学习笔记:Spring框架源码Part.1——基础

学习视频链接:https://www.bilibili.com/video/BV1zd4y1L7YD Spring源码学习笔记—基础前言第一章 bean的元数据一、回顾bean的注入方式二、BeanDefiniiton详解1、认识BeanDefinition2、AbstractBeanDefinition3、GenericBeanDefinition三、BeanDefinition注册器四、加载BeanDefinition1、读取xml配置文件2、加载带注解的bean3、读取配置类4、类路径扫描5、包扫

qq_45867699的博客 1373
上一篇: Spring源码必备-@Order排序详解
下一篇: Spring源码阅读之PropertySources
七号公园的忧伤
七号公园的忧伤 新星创作者: Java技术领域 新星创作者: Java技术领域
博客等级 码龄6年 4857粉丝 79原创
评论 23
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七号公园的忧伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值