Executing Spring Initializing Beans in Parallel - java

I have multiple Spring InitializingBean classes, which I'd like them to all run afterPropertiesSet() in parallel. When I run a small example, however, they are being executed synchronously. Is there any way to execute them in parallel?
Below is an example initializing bean which can be used to test out what I'm referring to. When creating multiple classes like this (i.e. InitBeanOne, InitBeanTwo, ...), the logs show that they are being run synchronously.
One idea which I had in mind was to have a single initializing bean asynchronously initialize the desired classes. This is a last resort option, though, as I'd like to take advantage of the initializing beans for each class individually, and not have other dependent classes.
#Component
public class InitBean implements InitializingBean {
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("BEGIN: InitBean");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: InitBean");
}
}

You should relocate the code to an event listening method, and mark the method with #Async.
Make sure the Async functionality is correctly set up. See: How To Do #Async in Spring.
You should make the method be triggered when the Spring framework fires the ApplicationReadyEvent.
#Component
public class InitBean {
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Async
#EventListener
public void onApplicationReady(ApplicationReadyEvent event) throws Exception {
LOGGER.info("BEGIN: onApplicationReady");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: onApplicationReady");
}
}
Warning: By doing this, other methods may be called before/during the invocation of this method. If the method does any kind of initialization needed by those other methods, you need to handle that, e.g. using a CountDownLatch.
UPDATE
If you need for the application to delay the completion of the startup sequence until all asynchronous methods have completed, I think you need to handle it yourself.
Create interface AsyncInitializingBean with same method as InitializingBean, then create a #Component named AsyncBeanInitializer auto-wiring a AsyncInitializingBean[] (or List), then have it execute all the methods using an ExecutorService on ContextRefreshedEvent.
#Component
public class InitBean implements AsyncInitializingBean { // <== Change interface (only change needed)
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("BEGIN: InitBean");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: InitBean");
}
}
public interface AsyncInitializingBean {
void afterPropertiesSet() throws Exception;
}
#Component
public class AsyncBeanInitializer {
private final static Logger LOGGER = LoggerFactory.getLogger(AsyncBeanInitializer.class);
#Autowired(required = false)
private AsyncInitializingBean[] beans;
#EventListener
public void onContextRefreshed(#SuppressWarnings("unused") ContextRefreshedEvent event) throws Exception {
if (this.beans == null || this.beans.length == 0)
return;
ExecutorService executorService = Executors.newWorkStealingPool();
try {
AtomicInteger failed = new AtomicInteger();
for (AsyncInitializingBean bean : beans) {
executorService.submit(() -> {
try {
bean.afterPropertiesSet();
} catch (Exception e) {
failed.incrementAndGet();
LOGGER.error("Async afterPropertiesSet() method failed: " + e, e);
}
});
}
executorService.shutdown();
executorService.awaitTermination(60, TimeUnit.MINUTES);
if (failed.get() != 0)
throw new RuntimeException(failed.get() + " Async afterPropertiesSet() methods failed. See log for details.");
} finally {
executorService.shutdownNow();
}
}
}

Related

How to assert exceptions in #Async void methods?

I want to assert an exception that should be thrown within an #Async void method.
The following fails, even though I already add a SyncTaskExecutor explicit.
org.opentest4j.AssertionFailedError: Expected RuntimeException to be thrown, but nothing was thrown.
#TestConfiguration
public class SyncTaskExecutorTestConfiguration {
#Bean
#Primary
public TaskExecutor asyncExecutor() {
return new SyncTaskExecutor();
}
}
#SpringBootTest
#Import(SyncTaskExecutorTestConfiguration.class)
public class MyTest {
#Test
public void test() {
assertThrows(RuntimeException.class, () -> service.run());
}
}
#Service
#Async //also #EnableAsync existing on #Configuration class
public class AsyncService {
public void run() {
//of course real world is more complex with multiple sub calls here
throw new RuntimeException("junit test");
}
}
I'm facing the same problem.
bilak's post gave the idea of having my custom AsyncUncaughtExceptionHandler declared with a #Component annotation.
Then, in my custom implmentation of AsyncConfigurer I was injecting my custom AsyncUncaughtExceptionHandler.
In my tests, I used the #MockBean annotation on my custom AsyncUncaughtExceptionHandler, so I was able to verify that the handleUncaughtException was called with the appropriate exception.
Code sample:
AsyncExceptionHandler
#Slf4j
#Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.error("Exception while executing with message: {} ", throwable.getMessage());
log.error("Exception happen in {} method ", method.getName());
}
}
CustomAsyncConfigurer
#Configuration
public class CustomAsyncConfigurer implements AsyncConfigurer {
final private AsyncExceptionHandler asyncExceptionHandler;
#Autowired
public TaskExecutorConfiguration(AsyncExceptionHandler asyncExceptionHandler) {
this.asyncExceptionHandler = asyncExceptionHandler;
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("AsyncThread::");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
My unit test:
class FooServiceTest extends FooApplicationTests {
#MockBean
private AsyncExceptionHandler asyncExceptionHandler;
#Autowired
private FooService fooService;
#Test
void testCreateEnrollmentBioStoreException() throws Exception {
fooService.doBar();
ArgumentCaptor<FooException> argumentCaptor = ArgumentCaptor.forClass(FooException.class);
verify(asyncExceptionHandler, times(1)).handleUncaughtException(argumentCaptor.capture(), any(), any());
FooException exception = argumentCaptor.getValue();
assertEquals("Foo error message", exception.getMessage());
}
}
I'm not sure if this is the right way, but I have a void method that was turned into async, so I didn't want to change the return value just for the tests.
Since the #Async method get executed asynchronously by a thread from asyncExecutor and it is terminated due to RuntimeException which doesn't have any impact on Main thread, the actually Main-Test thread competes successfully with the rest of flow once after it trigger the async call. So i will recommend to use the CompletableFuture to hold the reference of Async process always even it's required or not and truthfully will help in test cases
#Service
#Async
public class AsyncService {
public CompletableFuture<Void> run() {
//of course real world is more complex with multiple sub calls here
throw new RuntimeException("junit test");
}
}
So in the test you can wait for Async thread to complete assert the cause from ExecutionException, Since the get method throws ExecutionException if this future completed exceptionally
CompletableFuture.allOf(wait);
One more note you can refer link for asserting wrapped exceptions
What about using AsyncUncaughtExceptionHandler that will be defined for your AsyncConfigurer?
So basically when you execute your method which throws exception you can verify that exception was handled inside handler? Just an idea, didn't tried this.

Why does adding Spring AOP aspects break this asynchronous call during Spring context initialization?

I am having a hard time understanding the issue at hand, which I believe is a problem with the way how Spring proxies get created.
In this minimal example, I have two classes, AccountLoader and BankImpl, which implements an interface Bank. Upon start-up, AccountLoader executes some concurrent calls to an autowired Bank-instance, where the method in BankImpl is advised with an aspect.
In this setup the call to complete the future (Future.get) finishes with a TimeoutException, because the call appears to never terminate. However, if I call the same method before the callables get submitted to the executor, all calls finish successfully.
What is going on with Spring here? Why does this async call not terminate? And why in all seven hells does it terminate, if I add a synchronous call before the async one?
You may find the code below, a complete working example is also available on Github
public interface Bank {
Map<String, String> getAccounts(String q);
}
The simple implementation
#Service
public class BankImpl implements Bank {
private static final Logger LOGGER = LoggerFactory.getLogger(BankImpl.class);
#Override
public Map<String, String> getAccounts(String q) {
LOGGER.info("Listing accounts for {}", q);
return Collections.singletonMap(q, "q");
}
}
And finally the caller
#Service
public class AccountLoader {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountLoader.class);
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
#Autowired
private Bank bank;
#PostConstruct
public void refresh() {
LOGGER.info("Refreshing accounts");
// Uncommenting the following line will let the calls terminate
// bank.getAccounts("sync");
try {
executorService.submit(() -> { bank.getAccounts("async"); })
.get(5L, TimeUnit.SECONDS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
For the sake of completeness, here are the aspect
#Aspect
#Component
public class SomeAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(SomeAspect.class);
#AfterReturning(pointcut = "execution(* com.github.mtritschler.aspects.BankImpl.getAccounts(..))", returning = "returnValue")
public Map<String, String> logCallee(Map<String, String> returnValue) {
LOGGER.info("Result is {}", returnValue);
return returnValue;
}
}
and last but not least the configuration
#EnableAspectJAutoProxy
#Configuration
public class MyConfig {
}
Update: if I remove the #EnableAspextJAutoProxy, I also don't get an exception. Switching to load-time weaving did not change anything either.
It turned out that there was a race condition between the application initialization in the main thread and the concurrent access to the injected dependency.
Once we switched the #PostConstruct for a listener on ContextRefreshedEvent it worked just fine.

How to start (and eventually stop) a daemon thread in Spring-Boot?

I'm writing a Spring-Boot application to monitor a directory and process files that are being added to it. I start a thread by creating a ApplicationRunner in my Application class that calls a method annotated with #Async:
#SpringBootApplication
#EnableAsync
public class Application {
#Autowired
private DirectoryMonitorService directoryMonitorService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ApplicationRunner startDirectoryMonitorService() {
return args -> directoryMonitorService.monitorSourceDirectoty();
}
}
Here is the code for DirectoryMonitorService that has a method annotated with #Async:
#Service
public class DirectoryMonitorService {
private static final Logger logger = LogManager.getLogger(DirectoryMonitorService.class);
#Value("${timeout}")
private long timeout;
#Autowired
private WatchService watchService;
#Async
public void monitorSourceDirectoty() {
while (true) {
WatchKey watchKey;
try {
watchKey = watchService.poll(timeout, TimeUnit.SECONDS);
} catch (ClosedWatchServiceException | InterruptedException e) {
logger.error("Exception occured while polling from source file", e);
return;
}
// process the WatchEvents
if (!watchKey.reset()) {
break;
}
}
}
}
Finally here is where I create the ThreadPoolTaskExecutor:
public class AsyncConfig extends AsyncConfigurerSupport {
private static final Logger logger = LogManager.getLogger(AsyncConfig.class);
private static final String THREAD_NAME_PREFIX = "Parser-";
#Value("${corePoolSize}")
public int corePoolSize;
#Value("${maxPoolSize}")
public int maxPoolSize;
#Value("${queueCapacity}")
public int queueCapacity;
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (Throwable ex, Method method, Object... params) -> {
logger.error("Exception message - " + ex.getMessage());
logger.error("Method name - " + method.getName());
for (Object param : params) {
logger.error("Parameter value - " + param);
}
};
}
}
Somehow I feel this is not most elegant way of starting a main thread. Does anybody have a better solution?
Also I would rather have replace while (true) with a Boolean variable that I can set to false when Spring-Boot shuts down. Does anybody know which interface I need to implement for this?
This is correct if you want a very simple implementation and nothing more reliable.
Use #Async to a shorter tasks and it has very limited capability in terms of restarts etc.
And also, #Async will keep creating the separate threads at every watch sequence activation, and it will overwhelm the thread pool and start trowing exceptions, This is quite noticeable, if you have long running task as,
// process the WatchEvents
Other than that your implementation is correct (In my opinion).
Some suggestions (If you want to make things interesting/ complex):
So you can keep track of the files obviously using some sort of persistence mechanism and trigger decoupled batch (can use Spring Batch) to handle the execution and, get those batches into a separate UI or something and there you can have each of these batch process stopped, start, resume on the UI.

Weld is not injecting

I'm trying to set up a very simple implementation of weld in java SE.
I have the extension class:
public class MyExtension implements Extension {
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
System.out.println("Starting scan...");
}
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> annotatedType, BeanManager beanManager) {
System.out.println("Scanning type: " + annotatedType.getAnnotatedType().getJavaClass().getName());
}
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd) {
System.out.println("Finished the scanning process");
}
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
new Test();
}
}
I then have a simple class that I want to inject:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
}
And lastly the class I want to inject it in:
public class Test {
#Inject
private SimpleClass simple;
#PostConstruct
public void initialize() {
simple.doSomething();
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
The resulting output is:
80 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.10 (Final)
272 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of #Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Starting scan...
Scanning type: test.Test
Scanning type: test.SimpleClass
Scanning type: test.MyExtension
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Finished the scanning process
Starting application
I would expect the simple class to be injected when Test() is constructed and the postconstruct method to be called which should output the expected text.
What exactly am I doing wrong?
There's two issues with your code:
Problem 1:
CDI does not manage beans created with new. For the most part you need to #Inject a bean in order for its life cycle to be managed by the container
Problem 2:
For the most part, you cannot inject bean instances into observers of container events. That's because the events are firing as the container is being initialized, aka before it can actually begin managing object life cycles.
You could hook the container initializer observer directly into your Test class. Something like this:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
#PostConstruct
public void initialize() {
System.out.println("Starting");
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
public class Test {
#Inject
private SimpleClass simple;
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
simple.doSomething();
}
}
What you're doing wrong is calling new Test(). This constructs a new instance of Test, but in the back of CDI. For CDI to inject your Test instance, CDI has to create it itself.
See the documentation for how to boostrap Weld in a Java SE environment.
Create a utils class with #ApplicationScoped. This class can produce objects of every type. In your case this is just like this:
#Produces
static SimpleClass generateSimpleClass(){
return new SimpleClass();
}
Otherwise, if simpleclass for you is going to be a unique class in the application, set its class as #ApplicationScoped. Problem is that weld does not know that the class belongs to the container if there is neither annotation nor producer

How to bind method interceptor to provider?

Is there way to bind a method interceptor to a provider rather than an instance?
e.g. I use the code below to bind interceptors how would I bind INTERCEPTOR to a provider and then to the annotation?
bindInterceptor(
Matchers.any(), Matchers.annotatedWith(ANNOTATION.class), new INTERCEPTOR());
Guice does not allow AOP on instances not built by Guice: Guice AOP Limitations
"Instances must be created by Guice by an #Inject-annotated or no-argument constructor"
This means that instances created with a provider will not be candidates for AOP.
On the flip side, as long as your Provider is instantiated by Guice under the conditions mentioned, your Provider may be a candidate for AOP.
Here's an example that demonstrates this:
AOP Annotation:
#Retention(RetentionPolicy.RUNTIME) #Target(ElementType.METHOD)
#interface AOPExample {}
Provider:
public class ExampleProvider implements Provider<Example> {
#AOPExample
public Example get() {
System.out.println("Building...");
return new Example();
}
}
Target Example:
public class Example {
#AOPExample
public void tryMe() {
System.out.println("example working...");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Module:
public class ExampleModule extends AbstractModule {
#Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), new LoggingAOP());
bind(Example.class).toProvider(ExampleProvider.class);
}
}
Test Code:
public class Test {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new TestModule());
ExampleProvider exampleProvider = injector.getInstance(ExampleProvider.class);
Example example = exampleProvider.get();
example.tryMe();
Example directExample = injector.getInstance(Example.class);
directExample.tryMe();
}
}
Test Output:
start
Building...
end took: 3
example working...
start
Building...
end took: 0
example working...
Notice that the "example working..." is not surrounded by the timer code. The Provider.get ("Building...") is however.
If your question is: can the interceptor (new INTERCEPTOR()) be provided through a Guice Provider, the answer is no. The closest you may get to this functionality is calling the requestInjection() in the module configure method. This will inject your Interceptor with the appropriate code. From your interceptor you may be able to use Providers to avoid any sort of overhead that is causing you slowness during startup.
Here's what I mean:
Module:
public class TestModule extends AbstractModule {
#Override
protected void configure() {
bind(String.class).toInstance("One");
bind(String.class).annotatedWith(Names.named("two")).toInstance("Two");
LoggingAOP loggingAOP = new LoggingAOP();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), loggingAOP);
requestInjection(loggingAOP);
bind(Example.class).toProvider(ExampleProvider.class);
}
}
Interceptor:
public class LoggingAOP implements MethodInterceptor {
#Inject
private Provider<SomethingThatTakesALongTimeToInit> provider;
public Object invoke(MethodInvocation invocation) throws Throwable {
provider.get()...
System.out.println("start");
long start = System.currentTimeMillis();
Object value = invocation.proceed();
System.out.println("end took: " + (System.currentTimeMillis() - start));
return value;
}
}
Hope this answers your question.
The question, as I read it, is, how does one bind the interceptor type itself to a provider, rather than having to instantiate the interceptor at configuration time.
I don't think there's an easy way to do that, but one could write an interceptor that itself accepts a Provider for an implementation type. An example of this is shown in the Guice AOP documentation:
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
bindInterceptor(any(),
annotatedWith(NotOnWeekends.class),
new WeekendBlocker(getProvider(Calendar.class)));
}
}

Categories

Resources