java - 带有 OAuth2 的 Spring Boot 2 - 无法创建 bean entityManagerFactory,当前正在创建请求的 Bean

标签 java spring spring-boot spring-data-jpa

我正在尝试使用 Spring Boot 2 创建一个 OAuth2 授权服务器。但是,每当我尝试启动我的应用程序时,我都会收到一个错误:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.

2018-08-17 08:17:53.946 ERROR 38996 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed



org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'appConfig': Unsatisfied dependency expressed through field 'accessTokenConverter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authServerConfig' defined in file [C:\Users\Kelly Marchewa\workspace\Java\MidamAuth\bin\main\com\midamcorp\auth_server\config\AuthServerConfig.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'OAuthUserDetailsService': Unsatisfied dependency expressed through field 'userRepo'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Cannot create inner bean '(inner bean)#656d704' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#656d704': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'entityManagerFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?

    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:732) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:197) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1267) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1124) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:372) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1247) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:859) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]

    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:398) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at org.springframework.boot.SpringApplication.run(SpringApplication.java:330) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1258) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]

    at com.midamcorp.auth_server.AuthServerApplication.main(AuthServerApplication.java:26) [main/:na]

    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]

    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]

    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]

    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]

    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.0.4.RELEASE.jar:2.0.4.RELEASE]

从堆栈跟踪来看,问题的根源似乎在于创建 entityManagerFactory bean。但是,我不明白为什么这会成为一个问题。问题始于我的 AppConfig,它引用了在我的 AuthServerConfig 中找到的 JwtAccessTokenConverter:

 @Configuration
public class AppConfig {

    @Value("${spring.datasource.url}")
    private String datasourceUrl;

    @Value("${spring.datasource.driverClassName}")
    private String dbDriverClassName;

    @Value("${spring.datasource.username}")
    private String dbUsername;

    @Value("${spring.datasource.password}")
    private String dbPassword;

    @Autowired
    JwtAccessTokenConverter accessTokenConverter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public ModelMapper modelMapper() {
        ModelMapper mapper = new ModelMapper();
        return mapper;
    }

    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(dbDriverClassName);
        dataSource.setUrl(datasourceUrl);
        dataSource.setUsername(dbUsername);
        dataSource.setPassword(dbPassword);

        return dataSource;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter);
    }

}

授权服务器

 // Reference: https://dazito.com/java/spring-boot-and-oauth2-with-jdbc

@EnableAuthorizationServer
@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private PasswordEncoder passwordEncoder;

    private final AppConfig appConfig;

    @Autowired
    private OAuthUserDetailsService userService;

    private AuthenticationManager authenticationManager;

    @Autowired
    public AuthServerConfig(AuthenticationManager authenticationManager, AppConfig appConfig) {
        this.authenticationManager = authenticationManager;
        this.appConfig = appConfig;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.passwordEncoder(passwordEncoder);
        security.checkTokenAccess("permitAll()");
        security.tokenKeyAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {

        // JdbcClientDetailsService details = new
        // JdbcClientDetailsService(appConfig.dataSource());
        // details.setPasswordEncoder(passwordEncoder);
        configurer.inMemory()
                .withClient("web")
                .secret(passwordEncoder.encode("secret"))
                .accessTokenValiditySeconds(60 * 10) // 10 minutes
                .refreshTokenValiditySeconds(60 * 60 * 12) // 12 hours
                .scopes("read", "write")
                .authorizedGrantTypes("password", "refresh_token");
        // configurer.withClientDetails(details);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
        endpoints.tokenStore(tokenStore)
                .tokenEnhancer(tokenEnhancerChain)
                .userDetailsService(userService)
                .authenticationManager(authenticationManager);
    }

    @Bean
    @Primary // Making this primary to avoid any accidental duplication with another token
                // service instance of the same name
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore);
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnchancer();
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"),
                "mypass".toCharArray());

        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
        return converter;
    }
}

这需要一个 UserDetailsS​​ervice bean:

// Reference: http://www.baeldung.com/role-and-privilege-for-spring-security-registration
@Service
public class OAuthUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        OAuthUser user = userRepo.findByUserName(username);

        if(user == null) {
            throw new UsernameNotFoundException("Could not find " + username);
        }

        UserDetails details = new User(user.getUserName(), user.getPassword(), getGrantedAuthorities(user.getRoles()));
        return details;
    }


    private List<GrantedAuthority> getGrantedAuthorities(List<Role> roles) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        if(roles != null) {
            for(Role role: roles) {
                authorities.add(new SimpleGrantedAuthority(role.getRoleTitle()));       
            }
        }       
            return authorities; }


}

它引用了一个非常基本的 CrudRepository。

public interface UserRepository extends CrudRepository<OAuthUser, Integer> {

    public OAuthUser findByUserName(String name);

    @Query("SELECT u FROM OAuthUser as u JOIN u.roles as r WHERE r.id = ?1 AND u.isEnabled = true")
    public List<OAuthUser> findByRole(long roleID);
}

当然,存在依赖关系“链”,但我没有看到任何循环引用。此外,此应用程序正在运行。虽然我进行了其他更改,但在尝试将应用程序从 Spring Boot 1.5 和 Java 8 迁移到 Spring Boot 2 和 Java 10 时出现了问题。

我不确定这是否与我的某些依赖项存在兼容性问题?

构建.gradle

buildscript {
    ext {
        springBootVersion = '2.0.4.RELEASE'
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}


apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'application'
mainClassName = 'com.midamcorp.auth_server.AuthServerApplication'

group = 'com.midamcorp'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 10

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}




dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.boot:spring-boot-starter-jdbc')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('commons-io:commons-io:2.5')    
    compile ('org.modelmapper:modelmapper:1.0.0')   
    compile('org.springframework.security:spring-security-jwt:1.0.9.RELEASE')
    compile('org.springframework.security.oauth:spring-security-oauth2:2.3.3.RELEASE') 
    runtime('org.springframework.boot:spring-boot-devtools')
    compile ('org.apache.httpcomponents:httpclient:4.5.5')
    runtime('org.postgresql:postgresql')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('org.springframework.security:spring-security-test')    
    runtime('javax.servlet:javax.servlet-api:4.0.1')


}

如果有任何帮助,我将不胜感激。谢谢。

最佳答案

DataSource 移动到一个单独的配置文件中,该文件仅包含 DataSource bean 和环境值。我相信您在 JwtAccessTokenConverter 的某处存在循环依赖。

当我遵循可能相同的教程时,我遇到了类似的问题。

@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.url}")
    private String datasourceUrl;

    @Value("${spring.datasource.driverClassName}")
    private String dbDriverClassName;

    @Value("${spring.datasource.username}")
    private String dbUsername;

    @Value("${spring.datasource.password}")
    private String dbPassword;


    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(dbDriverClassName);
        dataSource.setUrl(datasourceUrl);
        dataSource.setUsername(dbUsername);
        dataSource.setPassword(dbPassword);

        return dataSource;
    } 

}

关于java - 带有 OAuth2 的 Spring Boot 2 - 无法创建 bean entityManagerFactory,当前正在创建请求的 Bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51896889/

相关文章:

java - "Missing return statement"在 if/for/while 内

java - Android - 如何查看谁调用了 zxing onActivityResult 方法?

spring-boot - 如何配置 Nginx 将 https 流量重定向到我的 Springboot 应用程序

java - 在两个应用程序之间共享 Spring Boot YAML 配置

java - 如何通过 post 请求将数据保存在 Cosmos DB 中?

java - 如何在IDEA中检查代码样式格式?

java - 构建端到端 Web 应用程序所需的技术?

java - 如何使用 Spring Cloud Contract Verifier 跳过测试生成 Maven 目标?

java - 根据给定模板使用 Apache PDFBox 库生成自定义 pdf 布局?

java - Spring 启动 : Can I post multiple objects as multiple @RequestParams to a REST service?