51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring Boot circular reference is already handled in application.properties but seems ignored by Java Spring Boot executable jar file

英文:

Spring Boot circular reference is already handled in application.properties but seems ignored by Java Spring Boot executable jar file

问题 {#heading}

以下是您提供的内容的中文翻译:

问题是,我使用Java Spring Boot创建了一个简单的登录员工管理系统(非常基本,足以具有登录-注销和CRUD操作)。我还尝试使用Spring Security来保护身份验证。

这是我Java Spring Boot应用程序的规格:

  • Spring Tool Suite 4.18.0.RELEASE
  • Spring Security 6
  • 使用Java 17
  • 构建在Linux Ubuntu 22.04之上
  • application.properties已经位于资源文件夹中,默认位于SBTLEmpManSys/src/main/resources

稍后我会附上与错误相关的Java文件,application.propertiespom.xml,但这是我已经处理的内容。我在application.properties中放置了此代码spring.main.allow-circular-references=true来处理此错误,它实际上起作用了。

应用程序上下文中一些bean的依赖关系形成了循环:

┌─────┐
|  securityConfiguration(字段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定义在类路径资源[org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]中
└─────┘

当我在Spring Tool Suite IDE中运行时,一切都正常工作。

但是,当我将Java Spring Boot应用程序打包成可执行的jar文件后,问题就出现了。似乎文件application.properties被忽略了。

循环引用似乎发生在EmpServiceImpl.java中,大约在以下代码行附近:

@Service
public class EmpServiceImpl implements EmpService {

	@Autowired
	private EmployeeRepository empRepDAO;
	
	//public EmpServiceImpl(@Lazy EmployeeRepository empRepDAO) { //使用'@Lazy'注解是为了避免循环引用 --> 注解不起作用
	public EmpServiceImpl(EmployeeRepository empRepDAO) {
		super();
		this.empRepDAO = empRepDAO;
	}

...[以此类推]

我运行jar文件的方式是通过终端进入target目录,然后使用java -jar SBTLEmpManSys-0.0.1-SNAPSHOT.jar运行它。以下是我运行应用程序时收到的错误片段。

应用程序运行失败

org.springframework.beans.factory.UnsatisfiedDependencyException: 创建bean时出错:'empServiceImpl'名称的bean:通过字段'passwordEncoder'表达的不满足的依赖关系:通过字段'passwordEncoder'表达的不满足的依赖关系:通过字段'httpSecurity'表达的不满足的依赖关系:通过字段'httpSecurity'表达的不满足的依赖关系:通过字段'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity'表达的不满足的依赖关系:工厂方法'httpSecurity'抛出异常,消息为:创建bean时出错:'passwordEncoder'名称的bean当前正在创建:是否存在不可解决的循环引用?

我想知道为什么错误消息中会说这个请求的bean当前正在创建:是否存在不可解决的循环引用?,因为它应该已经在application.properties中处理了。

是否有人可以帮助?任何帮助都将不胜感激。谢谢大家 Spring Boot circular reference is already handled in application.properties but seems ignored by Java Spring Boot executable jar file

这是我的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) { //使用'@Lazy'注解是为了避免循环引用 --> 注解不起作用
	public EmpServiceImpl(EmployeeRepository empRepDAO)

<details>
<summary>英文:</summary>

So the case is I a created simple login employee management system by using Java Spring Boot (very basic so it enough to have login-logout and CRUD operation). I also tried to use Spring Security to secure the authentication.

This it the spec of my Java Spring Boot application:
- spring tool suite 4.18.0.RELEASE
- spring security 6
- using java 17
- built on top linux ubuntu 22.04
- application.properties is already located in resource folder by default in `SBTLEmpManSys/src/main/resources`

I will attach my java files related to the error, `application.properties`, &amp; `pom.xml` later but this is what I already handle. I have put this code `spring.main.allow-circular-references=true` in my `application.properties` to handle this error and it actually works

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]
└─────┘

Everything works well when I ran it inside Spring Tool Suite IDE.
But the problem occur after I packed my Java Spring Boot application into executable jar file. It seems like file `application.properties` is ignored.
The circular reference seems happen in `EmpServiceImpl.java` around this line of codes:

@Service
public class EmpServiceImpl implements EmpService {

@Autowired
private EmployeeRepository empRepDAO;
//public EmpServiceImpl(@Lazy EmployeeRepository empRepDAO) { //ANNOTATION &#39;@Lazy&#39; is ADDITION to AVOID CIRCULAR REFERENCE --&gt; ANNOTATION NOT WORKING
public EmpServiceImpl(EmployeeRepository empRepDAO) {
super();
this.empRepDAO = empRepDAO;
}

...[AND_SO_ON]

The way I ran the jar file is by going into directory `target` via terminal and run it with `java -jar SBTLEmpManSys-0.0.1-SNAPSHOT.jar`. This is a snippet of error I got when I ran my app.

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?

I wonder why the error message said this `Requested bean is currently in creation: Is there an unresolvable circular reference?` because it should be handled already in `application.properties`
Does anyone can help? Any help will be very appreciated. Thanks guys ;)
This is my `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) -&gt; requests.requestMatchers(
&quot;/registrasi&quot;,
&quot;/js**&quot;,
&quot;/css**&quot;,
&quot;/img**&quot;)
.permitAll().anyRequest().authenticated())
.formLogin((form) -&gt; form.loginPage(&quot;/login&quot;).permitAll())
.logout((logout) -&gt; logout.invalidateHttpSession(true).clearAuthentication(true).logoutRequestMatcher(new AntPathRequestMatcher(&quot;/logout&quot;)).logoutSuccessUrl(&quot;/login?logout&quot;).permitAll());
return http.build();
}

}

This is my service file &#39;EmpServiceImpl.java&#39;:

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&lt;Employee, Long&gt;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
//@Autowired //THIS is ADDITION to AVOID CIRCULAR REFERENCE --&gt; ANNOTATION NOT WORKING
//public EmpServiceImpl(@Lazy EmployeeRepository empRepDAO) { //ANNOTATION &#39;@Lazy&#39; is ADDITION to AVOID CIRCULAR REFERENCE --&gt; 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(&quot;Email atau kata sandi tidak cocok!&quot;);
}
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(&quot;ROLE_USER&quot;)));
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&lt;? extends GrantedAuthority&gt; mapRolesToAuthority(Collection&lt;EmpRole&gt; roles) {
// TODO Auto-generated method stub
return roles.stream().map(role -&gt; new SimpleGrantedAuthority(role.getNamaRole())).collect(Collectors.toList());
}
//PART POJOK KARYAWAN
@Override
public List&lt;Employee&gt; getAllEmployees() {
// TODO Auto-generated method stub
return empRepDAO.findAll(); //return null;
}
@Override
public Employee getEmployeeById(long id) {
// TODO Auto-generated method stub
Optional&lt;Employee&gt; optEmp = empRepDAO.findById(id);
Employee empl = null;
if (optEmp.isPresent()) {
empl = optEmp.get();
} else {
throw new RuntimeException(&quot;Karyawan dengan emp_id &#39;&quot; + id + &quot;&#39; tidak bisa ditemukan&quot;);
}
return empl; //return null;
}
@Override
public void deleteEmployeeById(long id) {
// TODO Auto-generated method stub
this.empRepDAO.deleteById(id);
}
@Override
public Page&lt;Employee&gt; 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;
}

}

This is my `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) {#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

</details>
# 答案1
**得分**: 0
明白了!我终于在从文件`SecurityConfiguration.java`中删除`extends WebSecurityConfiguration`后解决了循环引用问题。
<details>
<summary>英文:</summary>
Got it! I finally solve the circular reference after eliminate `extends WebSecurityConfiguration` from my codes in file `SecurityConfiguration.java`
</details>

赞(1)
未经允许不得转载:工具盒子 » Spring Boot circular reference is already handled in application.properties but seems ignored by Java Spring Boot executable jar file