2016-07-15 3 views
-2

Я столкнулся с ситуацией, когда бобы, которые я создал, недоступны, что заставляет меня задаться вопросом, где и когда они !?Ограничения на то, где и когда бобы доступны

Я сделал две фасоль, одну область singleton и другие области request. Я убедился, что они правильно реализованы путем их автоподготовки в классе RestController. И они населены, без сомнения.

Теперь я написал класс проверки полномочий, расширяющий PreInvocationAuthorizationAdvice. Являясь классом авторизации, мне нужно иметь доступ к информации текущего пользователя. Таким образом, я передал текущий бин текущего пользователя этому классу, это request. Кроме того, мне нужен индивидуальный движок ACL, который автоопределяется в порядке singleton. Но когда я дойду до точки, когда мне нужно использовать эти два свойства, они оба - null!

Итак, каковы ограничения на то, где и когда я могу ожидать, что Bean будет доступен?

BTW, мой @Configuration класс также аннотируется @ComponentScan({"my.base.package"}), который является родительским пакетом моего назначенного класса, включая имущество @Autowired.

[UPDATE]

Я думаю, что я нашел то, что проблема есть, но пока я борюсь с решением.

Класс с объектами @Autowired, создается экземпляр как сам Bean. Я думаю, что этот поздний Бин получает экземпляр перед другими Бобами, на которые он зависит, и в результате они еще не доступны. В любом случае, я могу указать порядок создания экземпляров Beans?

[PS]

Любой, кто попадает на этот вопрос "вне темы, потому что: Этот вопрос не кажется, о программировании" так смешно :)

[UPDATE]

Просто пример, когда @Autowired property null.

Это мои классы конфигурации:

@Configuration 
@PropertySource("/config.properties") 
@ComponentScan({"my.package"}) 
public class AppConfig implements ApplicationContextAware 
{ 
    private ApplicationContext appContext; 
    @Autowired 
    private Environment env; 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) 
     throws BeansException 
    { 
     this.appContext = applicationContext; 
    } 

    @Bean 
    public RedissonClient getRedisson() 
    { 
     //Code ommited: returning a redisson connection. 
    } 
} 

@Configuration 
@ComponentScan({"my.pacakge"}) 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SecurityConfig extends GlobalMethodSecurityConfiguration 
{ 
    @Bean 
    public AclEngine getAclEngine() 
    { 
     return new AclEngine(); 
    } 

    @Autowired 
    private RedissonClient redisson; 

    @Bean 
    @Scope(value = "request") 
    public User getCurrentUser() 
    { 
     //Code ommited: retrieving the user from Redisson and returning it. 
    } 

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) 
     throws Exception 
    { 
     auth.authenticationProvider(authenticator()); 
    } 

    @Bean 
    public AuthenticationProvider authenticator() 
    { 
     return new AclAuthenticationProvider(); 
    } 

    @Bean 
    HttpSessionSecurityContextRepository getHttpSessionSecurityContextRepository() 
    { 
     HttpSessionSecurityContextRepository x = new HttpSessionSecurityContextRepository(); 
     x.setAllowSessionCreation(false); 
     return x; 
    } 

    @Bean 
    SecurityContextPersistenceFilter getSecurityContextPersistenceFilter() 
    { 
     return new SecurityContextPersistenceFilter(getHttpSessionSecurityContextRepository()); 
    } 

    @Override 
    protected AccessDecisionManager accessDecisionManager() 
    { 
     try { 
      AffirmativeBased ab = (AffirmativeBased) super.accessDecisionManager(); 
      List<AccessDecisionVoter<? extends Object>> advs = ab.getDecisionVoters(); 
      ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

      List<AccessDecisionVoter<? extends Object>> toBeRemoved = new ArrayList<>(); 
      for (AccessDecisionVoter<? extends Object> adv : advs) { 
       if (adv instanceof PreInvocationAuthorizationAdviceVoter) { 
        toBeRemoved.add(adv); 
       } 
      } 
      for (AccessDecisionVoter<? extends Object> adv : toBeRemoved) { 
       advs.remove(adv); 
      } 
      advs.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); 
      return ab; 
     } 
     catch (ClassCastException ex) { 
      ArrayList decisionVoters = new ArrayList(); 
      ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 
      decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); 
      return new AffirmativeBased(decisionVoters); 
     } 
    } 

    public class AclAuthenticationProvider implements AuthenticationProvider 
    { 
     @Override 
     public Authentication authenticate(Authentication authentication) throws AuthenticationException 
     { 
      return null; 
     } 

     @Override 
     public boolean supports(Class<?> authentication) 
     { 
      return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); 
     } 
    } 

    public class SessionInitializer extends AbstractHttpSessionApplicationInitializer 
    { 
     public SessionInitializer() 
     { 
      super(SecurityConfig.class); 
     } 
    } 
} 

И, наконец, где я сталкиваюсь с проблемой:

public class ResourceBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice 
{ 
    @Autowired 
    private User currentUser; 
    @Autowired 
    private AclEngine aclEngine; 

    @Override 
    public boolean before(Authentication authentication, MethodInvocation methodInvocation, PreInvocationAttribute preInvocationAttribute) 
    { 
     //Where I want to access currentUser and aclEngine but they are null. 
     //I can trace the code to this point without any Exception thrown! 
    } 
} 
+2

Возможно, вы сможете поделиться примером кода, который воспроизводит проблему? – CodeChimp

+0

Если вы использовали '@ Autowired', они не могут быть пустыми, если они будут пустыми, вы получите исключение. Покажите конфигурацию, которую вы используете. Также при использовании Spring Boot вы можете просто сделать 'SecurityContextHolder.getContext(). GetAuthentication()', чтобы получить текущего пользователя. –

+0

@ M.Deinum Они могут быть нулевыми, это просто вопрос времени. В какой-то момент они имеют значение null до того, как они не будут. Я думаю, что я обращаюсь к ним, прежде чем они будут созданы. Я обновил стебель. – Mehran

ответ

1
@Override 
protected AccessDecisionManager accessDecisionManager() 
{ 
    try { 
     AffirmativeBased ab = (AffirmativeBased) super.accessDecisionManager(); 
     List<AccessDecisionVoter<? extends Object>> advs = ab.getDecisionVoters(); 
     ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

     List<AccessDecisionVoter<? extends Object>> toBeRemoved = new ArrayList<>(); 
     for (AccessDecisionVoter<? extends Object> adv : advs) { 
      if (adv instanceof PreInvocationAuthorizationAdviceVoter) { 
       toBeRemoved.add(adv); 
      } 
     } 
     for (AccessDecisionVoter<? extends Object> adv : toBeRemoved) { 
      advs.remove(adv); 
     } 
     advs.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); 
     return ab; 
    } 
    catch (ClassCastException ex) { 
     ArrayList decisionVoters = new ArrayList(); 
     ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 
     decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); 
     return new AffirmativeBased(decisionVoters); 
    } 
} 

Spring только впрыснуть ссылки на экземпляры класса (AKA бобы), что он управляет , Когда вы создаете бобы внутри методов и напрямую вносите их в другие компоненты, эти вновь созданные бобы являются компонентами Spring Managed beans и, как таковые, не имеют права на какую-либо автоматическую проводку или почтовую обработку весной вообще.

Вместо

ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

Вы должны переместить этот код в метод @Bean так что становится Spring управляемый компонент и будет закачиваться с зависимостями.

@Bean 
public ResourceBasedPreInvocationAdvice expressionAdvice() { 
    return new ResourceBasedPreInvocationAdvice(); 
} 

И просто ссылайтесь на этот метод вместо создания нового экземпляра.

ResourceBasedPreInvocationAdvice expressionAdvice = expressionAdvice(); 

 Смежные вопросы

  • Нет связанных вопросов^_^