4
votes

I am new to spring and trying to create a web app using spring boot and jsp which I can deploy using tomcat8 on a raspberry pi. I can deploy my app through sts on an embedded tomcat instance and I can also deploy a war file to Jenkins without any errors. However, when I add the war to tomcat8 webapps folder and start tomcat I get the following error:

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?

I have tried annotating my configuration class with @Lazy and added setter methods to my userServiceImpl class but I still got the issue. Any help would be greatly appreciated?

webConfig class

@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));
                        }
                    }
            });

    }
}
1

1 Answers

2
votes

I think you should go through Spring Reference about IoC container.

WebSecurityConfig class requires UserDetailsService, which is implemented by UserServiceImpl. Also, UserServiceImpl requires PasswordEncoder which is provided by WebSecurityConfig. This causes a circular reference. Removing constructor injection should be enough to resolve your problem.

Side note: Try not to use constructor injection. Spring is clever when it comes to DI, but if you use constructor injection you are forcing spring to use your way. This can also cause circular reference errors.

I recommend you to at least skim this article: https://steveschols.wordpress.com/2012/06/05/i-was-wrong-constructor-vs-setter-injection/