Spring @Value注入的MongoURI调用方法时为null异常排查
问题描述
- 服务启动阶段,
@Value从配置文件读取的mongoURI值正常,@PostConstruct标注的初始化方法可以成功打印URI、建立MongoDB连接 - 调用
getUserByAuth0ID方法时抛出java.net.UnknownHostException: null: Name or service not known异常,调试发现该方法执行时成员变量mongoURI值为null - 代码中未手动修改
mongoURI赋值,此前将mongoURI硬编码为变量时功能运行正常
相关代码
DBConnectService.java:
@Service public class DBConnectService { private static MongoCollection<User> users; private static Logger logger = LogManager.getLogger(DBConnectService.class); @Value("${package.mongoURI}") private String mongoURI; /** 程序启动时初始化MongoDB连接 */ @PostConstruct public void init() { logger.info("Connecting to MongoDB"); try { System.out.println (mongoURI); // 此处URI可正常打印 CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build()); CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry); MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(mongoURI)) .codecRegistry(codecRegistry) .build(); MongoClient mongoClient = MongoClients.create(clientSettings); MongoDatabase database = mongoClient.getDatabase("db"); users = database.getCollection("users", User.class); } catch(Exception e) { logger.error("MongoDB connection failure:\n" + e); } } public User getUserByAuth0ID (String authID) { System.out.println (mongoURI); // 此处URI打印值为null User user = getUser(authID, "auth0ID"); if (user == null) { user = createUserAccount(authID); } return user; } public static User getUser (String info, String field) { User user = users.find(eq(field, info)).first(); return user; } public static User createUserAccount (String authID) { JsonObject newUserInfo = Auth0Service.getUserInfo(authID); if (newUserInfo.get("email_verified").getAsBoolean()) { User newUser = new User() .setEmail(newUserInfo.get("email").getAsString()) .setName(newUserInfo.get("name").getAsString()) .setAuth0ID(authID); users.insertOne(newUser); return newUser; } else { logger.info ("Email NOT verified"); return null; } } }
application.properties配置:
# MongoDB配置 package.mongoURI = mongodb+srv://admin:secretURL/?retryWrites=true&w=majority
问题根因
出现该问题的核心原因是调用getUserByAuth0ID时使用的不是Spring容器管理的Bean实例:
@Value注解的属性注入仅对Spring容器托管的单例Bean生效,如果你手动通过new DBConnectService()创建实例,该实例的mongoURI不会被注入,默认值就是null- 代码中将
getUser、createUserAccount定义为静态方法,也容易诱导开发者绕开Spring Bean直接调用,导致属性丢失 - 额外隐患:当前
init方法中MongoClient定义为局部变量,方法执行完后可能被GC回收,会引发后续连接失效问题
修复方案
- 移除
getUser、createUserAccount方法的static修饰符,所有业务方法通过Spring Bean实例调用 - 全项目禁止手动new
DBConnectService实例,所有依赖该服务的位置通过@Autowired或构造器注入获取Spring托管的单例对象 - 将
MongoClient定义为类成员变量,避免局部变量被GC回收导致连接中断,参考写法:private MongoClient mongoClient; // 提升为成员变量 private MongoCollection<User> users; // 去掉static修饰 private static Logger logger = LogManager.getLogger(DBConnectService.class); @Value("${package.mongoURI}") private String mongoURI; @PostConstruct public void init() { // 原有初始化逻辑,给this.mongoClient、this.users赋值即可 } - 如果确实存在静态逻辑需要调用服务,可在
@PostConstruct中将注入的实例属性赋值给静态变量兜底,但优先推荐通过注入Bean的方式调用
内容的提问来源于stack exchange,提问作者rando
相关产品推荐
相关产品推荐

