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
相关产品推荐
相关产品推荐

