限制豆何时何地可访问
我面临的情况是,我创建的豆类无法使用,这让我想知道他们在哪里以及何时!限制豆何时何地可访问
我已经做了两个豆,一个作用域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!
}
}
@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();
您可以分享一些代码示例来重现问题吗? – CodeChimp
如果你使用过@ @ Autowired,它们不能为空,如果它们为空,你会得到一个异常。显示您正在使用的配置。另外,当使用Spring Boot时,您可以简单地执行'SecurityContextHolder.getContext()。getAuthentication()'来获取当前用户。 –
@ M.Deinum他们可以是空的,这只是时间问题。在某些时候,它们在没有之前是空的。我想我在访问他们之前,他们被实例化。我更新了词干。 – Mehran