2016-07-15 20 views
-2

Ich bin mit einer Situation konfrontiert, wo die Bohnen, die ich erstellt habe, nicht zugänglich sind, was mich fragt, wo und wann sie sind?Einschränkungen wo oder wann Bohnen sind zugänglich

Ich habe zwei Bohnen gemacht, ein Bereich singleton und anderen Bereich request. Ich habe sichergestellt, dass sie korrekt implementiert sind, indem Sie sie in einer RestController Klasse automatisch ablaufen lassen. Und sie sind zweifellos dort bevölkert.

Jetzt habe ich eine Autorisierungs-Checker-Klasse geschrieben, die PreInvocationAuthorizationAdvice erweitert. Als Berechtigungsklasse muss ich auf die aktuellen Benutzerinformationen zugreifen können. Also habe ich die Bean des aktuellen Benutzers mit dieser Klasse autowired, das ist die request Scoped Bean. Außerdem benötige ich eine angepasste ACL-Engine, die in einer Autowirke in einer singleton Weise betrieben wird. Aber wenn ich den Punkt erreiche, an dem ich diese beiden Eigenschaften verwenden muss, sind sie beide null!

Was sind die Einschränkungen wo und wann ich erwarten kann, dass eine Bean erreichbar ist?

BTW, meine @Configuration Klasse wird auch von @ComponentScan({"my.base.package"}) kommentiert, die ein Elternpaket meiner designierten Klasse einschließlich der @Autowired Eigenschaft ist.

[UPDATE]

Ich glaube, ich gefunden, was das Problem ist, aber noch mit der Lösung, die ich bin zu kämpfen.

Die Klasse mit den Eigenschaften @Autowired wird als Bean selbst instanziiert. Ich denke, dass diese späte Bohne vor den anderen Bohnen instanziiert wird, von denen sie abhängig ist und als Ergebnis sind sie noch nicht verfügbar. Kann ich die Reihenfolge der instanziierten Bohnen angeben?

[PS]

Wer diese Frage als "off-topic, weil: Diese Frage nicht über die Programmierung zu sein scheint" markiert so lustig :)

[UPDATE]

Nur ein Beispiel, wenn @Autowired Eigenschaft ist null.

Das sind meine Konfigurationsklassen:

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

Und schließlich, wo ich das Problem:

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

Könnten Sie in der Lage sein, ein Codebeispiel zu teilen, das das Problem reproduziert? – CodeChimp

+0

Wenn Sie '@ Autowired' verwendet haben, können sie nicht null sein, wenn sie null wären, würden Sie eine Ausnahme erhalten. Zeigen Sie die Konfiguration an, die Sie verwenden. Wenn Sie Spring Boot verwenden, können Sie einfach 'SecurityContextHolder.getContext(). GetAuthentication()' verwenden, um den aktuellen Benutzer zu erhalten. –

+0

@ M.Deinum Sie können null sein, es ist nur eine Frage der Zeit. Irgendwann sind sie null, bevor sie es nicht sind. Ich denke, ich greife auf sie zu, bevor sie instanziiert werden. Ich habe den Stiel aktualisiert. – Mehran

Antwort

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

Frühling wird nur Verweise in Klasseninstanzen injiziert (auch bekannt als Bohnen), die es verwaltet . Wenn Sie Beans innerhalb von Methoden erstellen und direkt in andere Beans injizieren, sind diese neu erstellten Beans federverwaltete Beans und können daher im Frühling weder automatisch noch nachverarbeitet werden.

Statt

ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

Sie sollten diesen Code zu einem @Bean Methode bewegen, so dass eine Feder Managed Bean wird und mit den Abhängigkeiten injiziert werden.

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

Und verweisen Sie nur diese Methode, anstatt eine neue Instanz zu erstellen.

ResourceBasedPreInvocationAdvice expressionAdvice = expressionAdvice();