java – 尝试将spring boot war部署到tomcat8时未解析的循环引用?

我刚开始尝试使用
spring boot和jsp创建一个web应用程序,我可以在覆盆子pi上使用tomcat8进行部署.我可以通过嵌入式tomcat实例上的sts部署我的应用程序,我也可以将一个war文件部署到Jenkins而不会出现任何错误.但是,当我将战争添加到tomcat8 webapps文件夹并启动tomcat时,我收到以下错误:

2016-04-19 10:54:41.384  WARN 5525 --- [ost-startStop-1] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.rcctv.controllers.UserController.setUserService(com.rcctv.services.UserService); nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceImpl' defined in file [/usr/share/tomcat8/webapps/RaspberryCCTV-0.0.1-SNAPSHOT/WEB-INF/classes/com/rcctv/services/UserServiceImpl.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [org.springframework.security.crypto.password.PasswordEncoder]: : Error creating bean with name 'webSecurityConfig': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'userServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'userServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?

我尝试用@Lazy注释我的配置类,并在我的userServiceImpl类中添加了setter方法,但我仍然遇到了问题.任何帮助将不胜感激?

webConfig类

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${rememberMe.privateKey}")
    private String rememberMeKey;

    @Value("${spring.profiles.active}")
    private String env;

    @Resource
    private UserDetailsService userService;

    @Bean
    public HibernateJpaSessionFactoryBean sessionFactory() {
        return new HibernateJpaSessionFactoryBean();
    } 

    @Bean
    public RememberMeServices rememberMeServices() {
        TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(rememberMeKey, userService);
        return rememberMeServices;
    }

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

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/",
                        "/home",
                        "/error",
                        "/signup",
                        "/forgot-password",
                        "/reset-password/*",
                        "/public/**",
                        "/users/*").permitAll()
                .anyRequest().authenticated();
        http
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/raspberrycctv")
                .permitAll().and()
            .rememberMe().key(rememberMeKey).rememberMeServices(rememberMeServices()).and()
            .logout()
                .permitAll();

        if (!env.equals("dev"))
            http.requiresChannel().anyRequest().requiresSecure();
    }

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        authManagerBuilder.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

}

UserSeviceImpl

@Service
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class UserServiceImpl implements UserService, UserDetailsService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;
    private MailSender mailSender;

    @Autowired
    public UserServiceImpl(UserRepository userRepository,
            PasswordEncoder passwordEncoder,
            MailSender mailSender) {

        this.mailSender = mailSender;
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;

    }

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    @Override
    @Transactional(propagation=Propagation.REQUIRED, readOnly=false)
    public void signup(SignupForm signupForm) {
        final User user = new User();
        user.setEmail(signupForm.getEmail());
        user.setName(signupForm.getName());
        user.setPassword(passwordEncoder.encode(signupForm.getPassword()));
        user.getRoles().add(Role.UNVERIFIED);
        user.setVerificationCode(RandomStringUtils.randomAlphanumeric(16));
        userRepository.save(user);

        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        try {
                            String verifyLink = Utilities.hostUrl() + "/users/" + user.getVerificationCode() + "/verify";
                            mailSender.send(user.getEmail(), Utilities.getMessage("verifySubject"), Utilities.getMessage("verifyEmail", verifyLink));
                            logger.info("Verification mail to " + user.getEmail() + " queued.");
                        } catch (MessagingException e) {
                            logger.error(ExceptionUtils.getStackTrace(e));
                        }
                    }
            });

    }
}

最佳答案 我认为你应该通过
Spring Reference关于IoC容器.

WebSecurityConfig类需要UserDetailsS​​ervice,它由UserServiceImpl实现.此外,UserServiceImpl需要由WebSecurityConfig提供的PasswordEncoder.这会导致循环引用.删除构造函数注入应足以解决您的问题.

旁注:尽量不要使用构造函数注入.对于DI来说,Spring很聪明,但是如果使用构造函数注入,那么就是强迫spring使用你的方式.这也可能导致循环引用错误.

我建议你至少浏览一下这篇文章:https://steveschols.wordpress.com/2012/06/05/i-was-wrong-constructor-vs-setter-injection/

点赞