I manage a Spring project where I need to create a new thread to launch an asynchronous task. This project uses Spring Security and an Oracle proxy user (I will describe it in a future post), which means that, for each starting transaction, a call is made to the security context to get the current user.
The problem is that the new thread must access the database, then it tries to access the security context managed by Spring. But as Spring Security uses a ThreadLocal to store the security context, I receive the usual NullPointerException.
But fortunately, Spring is a well designed API and I can solve this issue by simply adding the security context to the thread:
public class CalculatorTask{ public CalculatorTask(final Data data, final MyDao dao, final SecurityContext context) { super(); this.data = data; this.myDao = dao; this.context = context; } @Override @Transactional public void run() { LOG.info("Starting asynchronous calculation"); SecurityContextHolder.setContext(context); myDao.doStuff(data); //Make here some amazing action ... LOG.info("Finishing asynchronous calculation"); } }
Note that the context is only set in the run() method.
And how I call it:
public class MyClass { private static final Logger LOG = LoggerFactory.getLogger(BsBillSetServiceImpl.class); @Autowired private TaskExecutor executor; @Autowired private MyDao myDao; @Override public void calcul(final Object data) { SecurityContext context = SecurityContextHolder.getContext(); CalculatorTask CalculatorTask = new CalculatorTask(data, myDao, context); executor.execute(CalculatorTask); LOG.info("The calculation has been launched"); } }
So simple even if at the first beginning, it was more like “What the f…!!!” 😀