You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加java-melody依赖后Spring Boot出现空指针异常,需补充哪些配置?

问题描述

在Spring Boot应用中添加java-melody starter依赖后,每次访问都会抛出空指针异常。

添加的POM依赖:

<dependency>
    <groupId>net.bull.javamelody</groupId>
    <artifactId>javamelody-spring-boot-starter</artifactId>
    <version>1.92.0</version>
</dependency>

异常触发点与ValidationService相关,相关代码如下:

AuthenticationService核心代码

@Slf4j
@Service
public class AuthenticationService implements IAuthenticationService {
    @Autowired
    private ValidationService validationService;
    @Autowired
    private UserLoginDao userLoginDao;

    public TempLoginModel doSoftLogin(@Valid UserLoginRequest request) {
        UserLogin userLogin = userLoginDao.findByUsernameAndCorporateCode(request.getUsername())
                .orElseThrow(() -> new UsernameNotFoundException(
                        env.getProperty("message.authentication.service.wrong.credential")));

        validationService.exceptionIfUserLoginNotActivated
                .andThen(validationService.exceptionIfUserLoginLocked)
                .accept(userLogin);

        String jwtToken = JWTUtil.createJwt(request.getUsername(),
                userLogin.getUserInformation().getMobileNumber());

        return new TempLoginModel(jwtToken);
    }
}

ValidationService核心代码

@Slf4j
@Service
public class ValidationService {
    public Consumer<UserLogin> exceptionIfUserLoginNotActivated = (user) -> {
        if (!user.isActivated()) {
            throw new NoAccessException(env.getProperty("message.user.login.not.activate"));
        }
    };

    public Consumer<UserLogin> exceptionIfUserLoginLocked = (user) -> {
        if (user.getWrongLoginAttempt() >= getWrongPasswordAttemptCount()) {
            throw new NoAccessException(env.getProperty("message.user.login.locked"));
        }
    };
}

异常栈信息:

java.lang.NullPointerException: null
    at com.java.corporate.service.impl.AuthenticationService.exceptionIfInvalidLogin(AuthenticationService.java:355)
    at com.java.corporate.service.impl.AuthenticationService.doSoftLogin(AuthenticationService.java:190)
    at com.java.corporate.service.impl.AuthenticationService$$FastClassBySpringCGLIB$$1d9d9fd9.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at net.bull.javamelody.MonitoringSpringInterceptor.invoke(MonitoringSpringInterceptor.java:76)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)

问题分析与解决方案

核心原因

  1. Spring AOP代理与成员变量冲突:JavaMelody通过Spring AOP生成CGLIB代理对象增强服务类时,不会自动代理类的public成员变量(如ValidationService中的两个Consumer实例)。当AuthenticationService调用代理后的ValidationService的成员变量时,会拿到空引用,触发空指针。
  2. ValidationService依赖缺失:代码中env(Environment)未注入,即使代理问题解决,env.getProperty()也会抛出空指针。

解决步骤

  1. 重构ValidationService,替换成员变量式Consumer
    将Consumer改为普通方法,同时注入必要依赖:

    @Slf4j
    @Service
    public class ValidationService {
        @Autowired
        private Environment env;
        // 假设错误登录尝试次数配置在application.properties中
        @Value("${security.wrong-login-attempt-count:5}")
        private int wrongLoginAttemptCount;
    
        public void validateUserLogin(UserLogin userLogin) {
            checkUserActivated(userLogin);
            checkUserLoginLocked(userLogin);
        }
    
        private void checkUserActivated(UserLogin user) {
            if (!user.isActivated()) {
                throw new NoAccessException(env.getProperty("message.user.login.not.activate"));
            }
        }
    
        private void checkUserLoginLocked(UserLogin user) {
            if (user.getWrongLoginAttempt() >= wrongLoginAttemptCount) {
                throw new NoAccessException(env.getProperty("message.user.login.locked"));
            }
        }
    }
    
  2. 修改AuthenticationService的调用逻辑
    替换原有的Consumer链式调用为普通方法调用:

    // 替换原来的Consumer调用代码
    validationService.validateUserLogin(userLogin);
    
  3. JavaMelody的可选配置
    基础场景下starter默认配置即可运行,若需要自定义监控规则,可在application.properties中添加:

    # 排除静态资源或无需监控的接口
    javamelody.excluded-urls=/css/**,/js/**,/health/**
    # 排除特定包下的类不被监控
    javamelody.excluded-packages=com.java.corporate.util
    # 开启监控页面的登录验证(可选)
    javamelody.authorized-users=admin:admin123
    

    若遇到AOP代理冲突,可强制使用CGLIB代理:

    spring.aop.proxy-target-class=true
    

内容的提问来源于stack exchange,提问作者Sudan Shrestha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 15:39:57