限制豆何时何地可访问

问题描述:

我面临的情况是,我创建的豆类无法使用,这让我想知道他们在哪里以及何时!限制豆何时何地可访问

我已经做了两个豆,一个作用域singleton和其他作用域request。我已经确认通过在RestController课程中自动装配它们来正确实施它们。他们人口众多,毫无疑问在那里。

现在我写了一个延伸PreInvocationAuthorizationAdvice的授权检查器类。作为授权课程,我需要访问当前用户的信息。所以我将当前用户的Bean自动装配到这个类,这是request范围的Bean。另外我需要一个定制的ACL引擎,它是以singleton的方式自动装配的。但是当我需要使用这两个属性时,他们都是null

那么,我可以期待一个Bean可访问的地点和时间有什么限制?

顺便说一句,我的@Configuration类也由@ComponentScan({"my.base.package"})这是我的指定类包括@Autowired属性的父包注解。

[更新]

我想我找到了问题是什么,但我还是会继续使用的解决方案中挣扎。

具有@Autowired属性的类正在被实例化为Bean本身。我认为这个晚期的Bean在其它Beans之前得到了实例化,这是因为它依赖于并且因此它们还不可用。无论如何,我可以指定正在实例化的Bean的顺序?

[PS]

任何人谁标记这个问题为“题外话,因为:这个问题似乎并没有被有关编程”是太有趣了:)

[更新]

仅当@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,它们不能为空,如果它们为空,你会得到一个异常。显示您正在使用的配置。另外,当使用Spring Boot时,您可以简单地执行'SecurityContextHolder.getContext()。getAuthentication()'来获取当前用户。 –

+0

@ M.Deinum他们可以是空的,这只是时间问题。在某些时候,它们在没有之前是空的。我想我在访问他们之前,他们被实例化。我更新了词干。 – Mehran

@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,因此在春季任何时候都不适合进行任何自动布线或后处理。

而不是

ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice(); 

你应该代码移到@Bean方法,所以这是成为一个Spring管理的bean,将与依赖注入。

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

而只是引用这个方法,而不是创建一个新的实例。

ResourceBasedPreInvocationAdvice expressionAdvice = expressionAdvice();