Java如何从Maven项目resources目录的JSON数组文件中获取随机元素
实现方案
核心思路很简单:两个JSON文件合计2w多条字符串,全加载到内存也就占几MB空间,完全没必要每次API请求都去读文件做解析,服务启动时一次性把姓名数组加载到内存缓存,后续生成随机人物时直接从内存列表随机取元素赋值即可,性能最高。
第一步:编写启动预加载组件,加载类路径下的JSON文件
Maven项目src/main/resources目录下的文件会被打包到类路径根目录,必须用类加载器以流的方式读取,不要硬写src/main/resources/xxx.json这类本地文件路径,否则项目打包成jar部署后会报文件找不到的错误。
以SpringBoot环境(自带Jackson JSON解析库)为例,写一个单例组件在启动时完成文件加载:import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Component; import jakarta.annotation.PostConstruct; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @Component public class NameCache { private List<String> firstNames; private List<String> lastNames; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); // Bean初始化完成后自动执行该方法加载文件 @PostConstruct private void loadNameData() throws Exception { // 加载名数据 try (InputStream firstNameIs = getClass().getClassLoader().getResourceAsStream("first-names.json")) { JsonNode firstNameNode = OBJECT_MAPPER.readTree(firstNameIs); firstNames = OBJECT_MAPPER.convertValue(firstNameNode.get("first_names"), OBJECT_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, String.class)); } // 加载姓数据 try (InputStream lastNameIs = getClass().getClassLoader().getResourceAsStream("last-names.json")) { JsonNode lastNameNode = OBJECT_MAPPER.readTree(lastNameIs); lastNames = OBJECT_MAPPER.convertValue(lastNameNode.get("last_names"), OBJECT_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, String.class)); } } // 对外暴露随机取姓名的方法 public String getRandomFirstName() { return firstNames.get(ThreadLocalRandom.current().nextInt(firstNames.size())); } public String getRandomLastName() { return lastNames.get(ThreadLocalRandom.current().nextInt(lastNames.size())); } }如果你用的是非Spring的普通Maven项目,把这个类改成饿汉单例模式,在私有构造方法里执行
loadNameData()逻辑即可;如果用Gson、Fastjson2等其他JSON库,替换掉JSON解析部分的代码就行,核心逻辑不变。这里用ThreadLocalRandom代替普通Random,高并发场景下不会出现种子竞争的性能问题,普通并发量下用Random也完全没问题。第二步:生成Person对象时直接从缓存取随机值赋值
在你的业务逻辑层注入上面的缓存组件,生成随机人物时直接调用方法赋值即可:@Service public class PersonGenerateService { @Resource private NameCache nameCache; public Person getRandomPerson() { Person person = new Person(); person.setFirstName(nameCache.getRandomFirstName()); person.setLastName(nameCache.getRandomLastName()); // 其余随机属性按相同逻辑生成赋值即可 return person; } }避坑提醒
- 不要每次接口请求都重新读取、解析JSON文件,频繁IO加JSON解析会把接口响应速度拉低几个数量级,完全没有必要。
- 读取resources下的文件必须用类加载器的
getResourceAsStream()方法,不要用本地文件路径读取,否则打包部署后100%找不到文件。 - 随机取下标时不要硬编码数组长度,用列表的
size()方法动态获取,后续你往JSON文件里增删姓名数据不需要改代码。

内容的提问来源于stack exchange,提问作者cantcode4mylife
相关产品推荐
相关产品推荐

