2016-11-19 14 views
9

मैं वर्तमान में एक वैडिन वसंत आवेदन पर काम कर रहा हूं। एकमात्र चीज जो मैं कहने में सक्षम हूं, उपयोगकर्ताओं का प्रमाणीकरण/प्रमाणीकरण jdbcTemplate के माध्यम से डेटाबेस से पूछताछ करके किया जाना चाहिए। इस मुद्दे को कैसे हल करें? मैं वसंत बूट 1.4.2.RELEASE का उपयोग कर रहा हूँ।वसंत सुरक्षा परिपत्र बीन निर्भरता

Description: 
The dependencies of some of the beans in the application context form a cycle: 
┌─────┐ 
| jdbcAccountRepository defined in file [repositories\JdbcAccountRepository.class] 
↑  ↓ 
| securityConfiguration.WebSecurityConfig (field services.JdbcUserDetailsServicessecurity.SecurityConfiguration$WebSecurityConfig.userDetailsService) 
↑  ↓ 
| jdbcUserDetailsServices (field repositories.JdbcAccountRepository services.JdbcUserDetailsServices.repository) 
└─────┘ 

मूल कोड इस तरह दिखता है:

AccountRepository:

public interface AccountRepository { 
    void createAccount(Account user) throws UsernameAlreadyInUseException; 
    Account findAccountByUsername(String username); 
} 

JdbcAccountRepository:

@Repository 
public class JdbcAccountRepository implements AccountRepository { 

    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); 

    private final JdbcTemplate jdbcTemplate; 
    private final PasswordEncoder passwordEncoder; 

    @Autowired 
    public JdbcAccountRepository(JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) { 
     this.jdbcTemplate = jdbcTemplate; 
     this.passwordEncoder = passwordEncoder; 
    } 

    @Transactional 
    @Override 
    public void createAccount(Account user) throws UsernameAlreadyInUseException { 
     try { 
      jdbcTemplate.update(
       "insert into Account (firstName, lastName, username, password, role) values (?, ?, ?, ?, ?)", 
       user.getFirstName(), 
       user.getLastName(), 
       user.getUsername(), 
       passwordEncoder.encode(
         user.getPassword()), 
         user.getRole() 
      ); 
     } catch (DuplicateKeyException e) { 
      throw new UsernameAlreadyInUseException(user.getUsername()); 
     } 
    } 

    @Override 
    public Account findAccountByUsername(String username) { 
     return jdbcTemplate.queryForObject(
      "select username, password, firstName, lastName, role from Account where username = ?", 
      (rs, rowNum) -> new Account(
        rs.getString("username"), 
        rs.getString("password"), 
        rs.getString("firstName"), 
        rs.getString("lastName"), 
        rs.getString("role")), 
      username 
     ); 
    } 
} 

JdbcUserDetailsServices:

@Service 
public class JdbcUserDetailsServices implements UserDetailsService { 
    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); 

    @Autowired 
    JdbcAccountRepository repository; 

    @Override 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
     try { 
      Account account = repository.findAccountByUsername(username); 
      User user = new User(
       account.getUsername(), 
       account.getPassword(), 
       AuthorityUtils.createAuthorityList(
         account.getRole() 
       ) 
      ); 
      return user; 
     } catch (DataAccessException e) { 
      LOGGER.debug("Account not found", e); 
      throw new UsernameNotFoundException("Username not found."); 
     } 
    } 
} 

SecurityConfiguration:

@Configuration 
@ComponentScan 
public class SecurityConfiguration { 

    @Autowired 
    ApplicationContext context; 

    @Autowired 
    VaadinSecurity security; 

    @Bean 
    public PreAuthorizeSpringViewProviderAccessDelegate preAuthorizeSpringViewProviderAccessDelegate() { 
     return new PreAuthorizeSpringViewProviderAccessDelegate(security, context); 
    } 

    @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) 
    public static class GlobalMethodSecurity extends GlobalMethodSecurityConfiguration { 

     @Bean 
     @Override 
     protected AccessDecisionManager accessDecisionManager() { 
      return super.accessDecisionManager(); 
     } 
    } 

    @Configuration 
    @EnableWebSecurity 
    public static class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

     @Autowired 
     JdbcUserDetailsServices userDetailsService; 

     @Autowired 
     DataSource dataSource; 

     @Bean 
     public PasswordEncoder passwordEncoder() { 
      return NoOpPasswordEncoder.getInstance(); 
     } 

     @Bean 
     public TextEncryptor textEncryptor() { 
      return Encryptors.noOpText(); 
     } 

     /* 
     * (non-Javadoc) 
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter 
     * #configure(org.springframework.security.config.annotation.web.builders.WebSecurity) 
     */ 
     @Override 
     public void configure(WebSecurity web) throws Exception { 
      //Ignoring static resources 
      web.ignoring().antMatchers("/VAADIN/**"); 
     } 

     @Override 
     protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception { 
      auth.userDetailsService(userDetailsService); 
     } 

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

     /* 
     * (non-Javadoc) 
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter 
     * #configure(org.springframework.security.config.annotation.web.builders.HttpSecurity) 
     */ 
     @Override 
     protected void configure(HttpSecurity http) throws Exception { 

      http 
       .exceptionHandling() 
        .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")) 
        .and() 
       .authorizeRequests() 
        .antMatchers("/**").permitAll() 
        .and() 
       .csrf().disable(); 
     } 
    } 
} 

पी एस [1.1.5,1.2.0), इस समस्या (अन्य निर्भरता की वजह से घटित नहीं होगा, मैं चाहिए करने के लिए ढाल स्प्रिंग बूट संस्करण नवीनतम उपयोग करने के लिए हैं)

उत्तर

12

आप चक्र को हल करने setter-based dependency injection साथ constructor-based dependency injection की जगह सकता है, Spring Framework Reference Documentation देखें:

सर्कुलर निर्भरता

+०१२३५१६४१०

यदि आप मुख्य रूप से कन्स्ट्रक्टर इंजेक्शन का उपयोग करते हैं, तो एक अनारक्षित परिपत्र निर्भरता परिदृश्य बनाना संभव है।

उदाहरण के लिए: कक्षा ए को कन्स्ट्रक्टर इंजेक्शन के माध्यम से कक्षा बी के एक उदाहरण की आवश्यकता होती है, और कक्षा बी को कन्स्ट्रक्टर इंजेक्शन के माध्यम से कक्षा ए के एक उदाहरण की आवश्यकता होती है। यदि आप कक्षा ए और बी के लिए बीन्स को एक दूसरे में इंजेक्शन देने के लिए कॉन्फ़िगर करते हैं, तो स्प्रिंग आईओसी कंटेनर रनटाइम पर इस परिपत्र संदर्भ का पता लगाता है, और BeanCurrentlyInCreationException फेंकता है।

एक संभावित समाधान कुछ वर्गों के स्रोत कोड को कन्स्ट्रक्टर के बजाए सेटर्स द्वारा कॉन्फ़िगर करने के लिए संपादित करना है। वैकल्पिक रूप से, कन्स्ट्रक्टर इंजेक्शन से बचें और केवल सेटटर इंजेक्शन का उपयोग करें। दूसरे शब्दों में, हालांकि इसकी अनुशंसा नहीं की जाती है, आप सेटर इंजेक्शन के साथ परिपत्र निर्भरताओं को कॉन्फ़िगर कर सकते हैं।

ठेठ मामले (बिना परिपत्र निर्भरताओं के) के विपरीत, बीन ए और बीन बी के बीच एक गोलाकार निर्भरता बीन्स में से एक को पूरी तरह से शुरू करने से पहले इंजेक्शन देने के लिए मजबूर करती है (क्लासिक चिकन/अंडा परिदृश्य)।

+0

https://ibb.co/d2x4j5 हीरो आपको लगता है कि @Autowired नीचे जाना एक क्षेत्र –

+0

@ ВсеЕдно है: धन्यवाद, लेकिन यह है कि सिफारिश JavaDoc का हिस्सा नहीं है। क्या यह आपके आईडीई की एक प्लगइन है जो इसकी सिफारिश करता है? हालांकि, स्प्रिंग सिक्योरिटी ने एएफएआईके को कन्स्ट्रक्टर इंजेक्शन के लिए संस्करण 4.x के साथ कई सेम बदल दिए। तो कोई लगातार तरीका नहीं है। – dur

4

मैं @Lazy विधि पसंद करता हूं। इस तरह से मैं एक पैटर्न से चिपक सकता हूं।

देखें http://www.baeldung.com/circular-dependencies-in-spring

+0

आपको अपने उत्तर में उल्लेख करना चाहिए, कि यह समाधान केवल काम करता है, यदि निर्भर वस्तु के प्रॉक्सी (जावा प्रॉक्सी या CGLIB प्रॉक्सी) बनाना संभव है। – dur

संबंधित मुद्दे