我面临的情况是我创造的豆子无法进入,这让我想知道它们在何时何地!?
我制作了两个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}}
答案 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();