Issue
I'm having some problems to ignore the @Scope
when I'm not have a request scope. I can explain.
I'm saving some informations of the user in the audit table using Hibernate Envers. This works good when exists a request (from my Rest Controller), because the user needs to be logged, so the user are always found in this situation.
But, I'm working with RabbitMQ also. When I receive some message that needs to perform some action on database (insert a entity, per example), my code tries to load from the application context the User
bean. The User
Bean are tied with the @Scope
request and the Spring can't find a thread-bound request for that.
So, I receive the error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.get': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.getTarget(CglibAopProxy.java:705)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.domain.config.UserConfiguration$User$$EnhancerBySpringCGLIB$$c7e6e64e.getUserId(<generated>)
at com.domain.audit.RevisionEntityListener.newRevision(RevisionEntityListener.java:28)
at org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator.generate(DefaultRevisionInfoGenerator.java:93)
at org.hibernate.envers.internal.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:114)
at org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:96)
at org.hibernate.envers.internal.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:153)
at org.hibernate.envers.internal.synchronization.AuditProcessManager$1.doBeforeTransactionCompletion(AuditProcessManager.java:46)
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:928)
... 38 common frames omitted
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
... 50 common frames omitted
I would like to ignore this situation, because my intention in this case is fill the "user" information with something like "system". to indicate that this change was not directly made by the user (because there is no user envolved).
My code is below.
The RevisionEntityListener
(Hibernate Envers):
@Component
public class RevisionEntityListener implements RevisionListener, ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void newRevision(Object revisionEntity) {
RevEntity revEntity = (RevEntity) revisionEntity;
User user = applicationContext.getBean(User .class);
revEntity.setUserId(user.getUserId());
// code
}
private static void setStaticApplicationContext(ApplicationContext context) {
applicationContext = context;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
setStaticApplicationContext(applicationContext);
}
}
My UserConfiguration
:
@Configuration
public class UserConfiguration {
@Autowired
private OAuth2ClientContext context;
@Bean
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, scopeName = "request")
public User get() {
User user = null;
try {
String token = context.getAccessToken().getValue();
// code
return user;
}
@Getter
@Setter
@ToString
public static class User {
private Long userId;
// all user information
}
}
Solution
I dont' know if this is the best option, but I created an if
to see if the SecurityContextHolder.getContext().getAuthentication()
exists:
User user;
if (SecurityContextHolder.getContext().getAuthentication() != null) {
user = applicationContext.getBean(User .class);
} else {
user = createSystemUser();
}
revEntity.setUserId(user.getUserId());
Answered By - Dherik