豆类可以到达何时何地的限制

时间:2016-07-15 12:52:27

标签: java spring javabeans

我面临的情况是我创造的豆子无法进入,这让我想知道它们在何时何地!?

我制作了两个Beans,一个范围singleton和另一个范围request。我已确保通过在RestController课程中自动装配它们来正确实现它们。毫无疑问,他们居住在那里。

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

那么对于我可以在何时何地可以访问Bean的限制是什么?

BTW,我的@Configuration类也由@ComponentScan({"my.base.package"})注释,@Autowired是我指定类的父包,包括@Autowired属性。

[UPDATE]

我想我发现了问题所在,但我正在努力解决这个问题。

具有@Autowired属性的类正在被实例化为Bean本身。我认为这个已故的Bean在其依赖的其他Beans之前得到实例化,因此它们尚未可用。无论如何我可以指定实例化Beans的顺序吗?

[P.S。]

任何人将此问题标记为“偏离主题,因为:此问题似乎与编程无关”非常有趣:)

[UPDATE]

只是@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); } } } 属性为null的示例。

这些是我的配置类:

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!
    }
}

最后我面临的问题是:

{{1}}

1 个答案:

答案 0 :(得分: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 bean)。当你在方法中创建bean并直接将它们注入到其他bean中时,那些新创建的bean是Spring Managed bean,因此无法通过spring进行任何自动布线或后期处理。

而不是

ResourceBasedPreInvocationAdvice expressionAdvice = new ResourceBasedPreInvocationAdvice();

您应该将该代码移动到@Bean方法,以便它成为Spring托管bean并将注入依赖项。

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

只需引用此方法,而不是创建新实例。

ResourceBasedPreInvocationAdvice expressionAdvice = expressionAdvice();