Я столкнулся с ситуацией, когда бобы, которые я создал, недоступны, что заставляет меня задаться вопросом, где и когда они !?Ограничения на то, где и когда бобы доступны
Я сделал две фасоль, одну область singleton
и другие области request
. Я убедился, что они правильно реализованы путем их автоподготовки в классе RestController
. И они населены, без сомнения.
Теперь я написал класс проверки полномочий, расширяющий PreInvocationAuthorizationAdvice
. Являясь классом авторизации, мне нужно иметь доступ к информации текущего пользователя. Таким образом, я передал текущий бин текущего пользователя этому классу, это request
. Кроме того, мне нужен индивидуальный движок ACL, который автоопределяется в порядке singleton
. Но когда я дойду до точки, когда мне нужно использовать эти два свойства, они оба - null
!
Итак, каковы ограничения на то, где и когда я могу ожидать, что Bean будет доступен?
BTW, мой @Configuration
класс также аннотируется @ComponentScan({"my.base.package"})
, который является родительским пакетом моего назначенного класса, включая имущество @Autowired
.
[UPDATE]
Я думаю, что я нашел то, что проблема есть, но пока я борюсь с решением.
Класс с объектами @Autowired
, создается экземпляр как сам Bean. Я думаю, что этот поздний Бин получает экземпляр перед другими Бобами, на которые он зависит, и в результате они еще не доступны. В любом случае, я могу указать порядок создания экземпляров Beans?
[PS]
Любой, кто попадает на этот вопрос "вне темы, потому что: Этот вопрос не кажется, о программировании" так смешно :)
[UPDATE]
Просто пример, когда @Autowired
property 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!
}
}
Возможно, вы сможете поделиться примером кода, который воспроизводит проблему? – CodeChimp
Если вы использовали '@ Autowired', они не могут быть пустыми, если они будут пустыми, вы получите исключение. Покажите конфигурацию, которую вы используете. Также при использовании Spring Boot вы можете просто сделать 'SecurityContextHolder.getContext(). GetAuthentication()', чтобы получить текущего пользователя. –
@ M.Deinum Они могут быть нулевыми, это просто вопрос времени. В какой-то момент они имеют значение null до того, как они не будут. Я думаю, что я обращаюсь к ним, прежде чем они будут созданы. Я обновил стебель. – Mehran