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

Spring Boot可执行Jar忽略application.properties循环引用配置问题求助

员工管理系统Jar运行时循环引用配置失效问题排查

我基于Java Spring Boot开发了一个具备登录登出和CRUD功能的简易员工管理系统,使用Spring Security保障认证安全。项目环境如下:

  • Spring Tool Suite 4.18.0.RELEASE
  • Spring Security 6
  • Java 17
  • 基于Ubuntu 22.04构建
  • application.properties默认存放于SBTLEmpManSys/src/main/resources目录

我已在application.properties中添加spring.main.allow-circular-references=true配置,在Spring Tool Suite IDE中运行时,该配置可有效解决如下循环引用错误:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  securityConfiguration (field private org.springframework.security.config.annotation.web.builders.HttpSecurity org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.httpSecurity)
↑     ↓
|  org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]
└─────┘

但将项目打包为可执行Jar文件后,进入target目录执行java -jar SBTLEmpManSys-0.0.1-SNAPSHOT.jar运行时,出现循环引用错误,提示配置被忽略,错误信息如下:

Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'empServiceImpl': Unsatisfied dependency expressed through field 'passwordEncoder': Error creating bean with name 'securityConfiguration': Unsatisfied dependency expressed through field 'httpSecurity': Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity' defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]: Failed to instantiate [org.springframework.security.config.annotation.web.builders.HttpSecurity]: Factory method 'httpSecurity' threw exception with message: Error creating bean with name 'passwordEncoder': Requested bean is currently in creation: Is there an unresolvable circular reference?

循环引用问题出现在EmpServiceImpl类中,我尝试使用@Lazy注解但未生效。以下是相关代码:

SecurityConfiguration.java

package com.kastamer.sbtl.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.kastamer.sbtl.service.EmpService;

@Configuration
@PropertySource(value = "classpath:application.properties")
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfiguration {

    @Autowired
    public EmpService empService;
    
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // TODO Auto-generated method stub
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        // TODO Auto-generated method stub
        http.authorizeHttpRequests((requests) -> requests.requestMatchers(
                "/registrasi",
                "/js**",
                "/css**",
                "/img**")
                .permitAll().anyRequest().authenticated())
        .formLogin((form) -> form.loginPage("/login").permitAll())
        .logout((logout) -> logout.invalidateHttpSession(true).clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login?logout").permitAll());
        
        return http.build();
    }
}

EmpServiceImpl.java

package com.kastamer.sbtl.service;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.kastamer.sbtl.model.EmpRole;
import com.kastamer.sbtl.model.Employee;
import com.kastamer.sbtl.repository.EmployeeRepository;
import com.kastamer.sbtl.web.dto.EmpRegistrationDTO;

@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmployeeRepository empRepDAO; //this is interface extend JpaRepository<Employee, Long>
    
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    //@Autowired //THIS is ADDITION to AVOID CIRCULAR REFERENCE --> ANNOTATION NOT WORKING
    //public EmpServiceImpl(@Lazy EmployeeRepository empRepDAO) { //ANNOTATION '@Lazy' is ADDITION to AVOID CIRCULAR REFERENCE --> ANNOTATION NOT WORKING
    public EmpServiceImpl(EmployeeRepository empRepDAO) {
        super();
        this.empRepDAO = empRepDAO;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        Employee pegawai = empRepDAO.findByEmail(username);
        
        if (pegawai == null) {
            throw new UsernameNotFoundException("Email atau kata sandi tidak cocok!");
        }
        
        return new org.springframework.security.core.userdetails.User(pegawai.getEmail(), pegawai.getPassword(), mapRolesToAuthority(pegawai.getRoles())); //return null;
    }

    @Override
    public Employee save(EmpRegistrationDTO empRegistrationDTO) {
        // TODO Auto-generated method stub
        Employee karyawan = new Employee(
                empRegistrationDTO.getFullName(),
                empRegistrationDTO.getEmail(),
                passwordEncoder.encode(empRegistrationDTO.getPassword()),
                Arrays.asList(new EmpRole("ROLE_USER")));
        
        return empRepDAO.save(karyawan); //return null;
    }

    @Override
    public void simpanPembaruanData(Employee employee) {
        // TODO Auto-generated method stub
        employee.setPassword(passwordEncoder.encode(employee.getPassword()));
        
        this.empRepDAO.save(employee);
    }
    
    private Collection<? extends GrantedAuthority> mapRolesToAuthority(Collection<EmpRole> roles) {
        // TODO Auto-generated method stub
        return roles.stream().map(role -> new SimpleGrantedAuthority(role.getNamaRole())).collect(Collectors.toList());
    }

    //PART POJOK KARYAWAN
    @Override
    public List<Employee> getAllEmployees() {
        // TODO Auto-generated method stub
        return empRepDAO.findAll(); //return null;
    }

    @Override
    public Employee getEmployeeById(long id) {
        // TODO Auto-generated method stub
        Optional<Employee> optEmp = empRepDAO.findById(id);
        Employee empl = null;
        
        if (optEmp.isPresent()) {
            empl = optEmp.get();
        } else {
            throw new RuntimeException("Karyawan dengan emp_id '" + id + "' tidak bisa ditemukan");
        }
        
        return empl; //return null;
    }

    @Override
    public void deleteEmployeeById(long id) {
        // TODO Auto-generated method stub
        this.empRepDAO.deleteById(id);
    }

    @Override
    public Page<Employee> findPaginated(int pageNo, int pageSize, String sortField, String sortAscOrDesc) {
        // TODO Auto-generated method stub
        Sort runut = sortAscOrDesc.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() : Sort.by(sortField).descending();
        
        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, runut);
        
        return this.empRepDAO.findAll(pageable); //return null;
    }
}

application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/myDB
spring.datasource.username=[POSTGRES_USERNAME]
spring.datasource.password=[POSTGRES_PASSWORD]
spring.datasource.driver-class-name=org.postgresql.Driver

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

spring.jpa.hibernate.ddl-auto=update

logging.level.org.hibernate.sql=debug
logging.level.org.hibernate.type=trace
#spring.jpa.show-sql=true

# Default user login and password for spring security web login page (if spring security is enabled)
#spring.security.user.name=spring
#spring.security.user.password=spring123 
#spring.security.user.roles=USER

spring.main.allow-bean-definition-overriding=true
spring.main.allow-circular-references=true

请求帮忙排查为何可执行Jar运行时,application.properties中的循环引用配置会被忽略,导致循环引用错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 22:35:55