2016-07-15 11 views
-2

私が作成したBeanにアクセスできない状況に直面しています。Beansのアクセス可能な場所と時間に関する制限

私は2つの豆を作りました.1つはスコープsingletonと他のスコープはrequestです。私は彼らがRestControllerクラスでautowiringすることによって正しく実装されていることを確認しました。そして、彼らは人口が多い、間違いなくそこにあります。

今度はPreInvocationAuthorizationAdviceに拡張された認可チェッカークラスを作成しました。認証クラスであるため、私は現在のユーザーの情報にアクセスする必要があります。だから私は現在のユーザーのBeanをこのクラスにautowired、これはrequestスコープBeanです。また、私はsingletonの方法でautowiredされているカスタマイズされたACLエンジンが必要です。しかし、私はこれらの2つのプロパティを使用する必要がある時点に達すると、両方ともnullです!

だから、どこでいつ私がBeanにアクセスできると予想できるの?

私の@Configurationクラスには、@Autowiredプロパティを含む私の指定されたクラスの親パッケージである@ComponentScan({"my.base.package"})によっても注釈が付けられます。

[UPDATE]

私は問題が何であるかを見つけたと思うが、まだ私は解決策に苦しんでいます。

プロパティが@Autowiredのクラスは、Bean自体としてインスタンス化されています。私は、この後期のBeanは、それが依存している他のBeanの前にインスタンス化されていると考えています。その結果、まだ利用できません。とにかくインスタンス化されているBeanの順序を指定できますか?

[PS] としてこの質問にフラグを立て

誰でも: "ので、オフトピックこの質問は、プログラミングについてではありませんが、" とても面白いです:)

[UPDATE]

@Autowiredプロパティが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'を使用している場合は、nullにすることはできません。ヌルになると例外が発生します。使用している構成を表示します。また、Spring起動時に '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); 
    } 
} 

春だけで、それが管理している(豆別名)クラスのインスタンスへの参照を注入します。 Beanをメソッド内に作成して他のBeanに直接注入する場合、新しく作成されたBeanはSpring Managed Beanであるため、春までに自動配線や後処理に適格ではありません。それは春の管理Beanになり、依存関係を注入されているので、代わりに

ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

あなたは@Beanメソッドにそのコードを移動する必要があります。

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

新しいインスタンスを作成する代わりに、このメソッドを参照するだけです。

ResourceBasedPreInvocationAdvice expressionAdvice = expressionAdvice(); 
関連する問題