"Autowire" 将 spring 模块化应用程序部署到 tomcat 后失败

"Autowire" fails after deploying spring modular application to tomcat

我需要一些帮助,因为我自己找不到解决方案而且 google 也没有帮助。 我有一个模块化 spring 应用程序,我可以使用 SpringBoot 从命令行 运行 毫无问题。 我使用 gradle war 命令创建了一个 war。我已经在带有 PostgreSQL 数据库和 JRE 8 的服务器上安装了 Tomcat 8。我已将 war 放入 webapps 文件夹,并将我的外部 conf 文件放入 conf 文件夹。 我的所有其他模块都存在于 war 文件的 libs 文件夹中。 当我 运行 和 Tomcat 时,出现以下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personDetailsService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private eu.bato.anyoffice.serviceapi.service.PersonService eu.bato.anyoffice.frontend.config.PersonDetailsService.personService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [eu.bato.anyoffice.serviceapi.service.PersonService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

这是我的主要 conf 文件的一部分:

@Configuration
@EnableAutoConfiguration
@ComponentScan(value = {"eu.bato.anyoffice"})
@EnableWebMvc
public class Application extends WebMvcConfigurerAdapter{

    @Autowired
    SchedulerService scheduler;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @PostConstruct
    protected void startScheduler(){
        scheduler.start();
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

    @Autowired
    private MessageSource messageSource;

定义 PersonDetailsS​​ervice bean 的安全配置:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(personDetailsService()).passwordEncoder(new StandardPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(authenticationFilter(), LogoutFilter.class)
                .csrf().disable()
                .authorizeRequests()
                ......
                .permitAll();
    }

    @Bean
    PersonDetailsService personDetailsService() {
        return new PersonDetailsService();
    }

    @Bean
    Filter authenticationFilter() {
        BasicAuthenticationFilter basicAuthFilter = new BasicAuthenticationFilter(customAuthenticationManager(), new BasicAuthenticationEntryPoint());
        return basicAuthFilter;
    }

    @Bean
    ProviderManager customAuthenticationManager() {
        List<AuthenticationProvider> providers = new LinkedList<>();
        providers.add(daoAuthPovider());
        ProviderManager authenticationManager = new ProviderManager(providers);
        authenticationManager.setEraseCredentialsAfterAuthentication(true);
        return authenticationManager;
    }

    @Bean
    DaoAuthenticationProvider daoAuthPovider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(personDetailsService());
        provider.setPasswordEncoder(new StandardPasswordEncoder());
        //TODO: add salt
        return provider;
    }

PersonDetailsS​​ervice 的一部分 class:

public class PersonDetailsService implements UserDetailsService {

    private static final Logger log = LoggerFactory.getLogger(PersonDetailsService.class);

    private static final StandardPasswordEncoder encoder = new StandardPasswordEncoder();

    @Autowired
    private PersonService personService;

    @Autowired
    private Environment environment;

    @PostConstruct
    protected void initialize() {
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("Authenticating: " + username);

PersonService 接口在包 eu.bato.anyoffice.serviceapi.service 中,它的实现在 eu.bato.anyoffice.backend.service.impl 中,并且有标签 @Service@Transactional

如有任何提示,我将不胜感激。我可以提供任何进一步的日志和信息。

您的配置中的问题是 PersonService 是由 Servlet Context 中声明的 @ComponentScan 加载的。

这样 PersonServiceApplication Context 中无法访问 SecurityConfig

Servlet Context 中的 beans 可以引用 Application Context 中的 bean,反之则不行!

因此将 @ComponentScan 放入 SecurityConfig 允许该组件可访问。