Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why I can't get result back in @Async method ? ("IllegalStateException: EntityManagerFactory is closed" is thrown)

I am trying to write a simple Spring Boot Program and practice @Async. I want to fetch all records of teacher entity asynchronously.

my database access objects:

public interface TeacherService {
    List<Teacher> findAll(Pageable pageable);
}

how it is implemented:

 public class TeacherServiceImpl implements TeacherService{
    
        @Autowired
        private TeacherRepository repository;
    
        @Override
        public List<Teacher> findAll(Pageable pageable) {
            Page<Teacher> page =  repository.findAll(pageable);
            return page.get().collect(Collectors.toList());
        }
}

my Async method:

@Component
public class PrintAllTeacherDataBaseResult {
    @Autowired
    TeacherService teacher;

    @Async
    public AsyncResult<List<Teacher>> printPage(Pageable page){
        return new AsyncResult<>(teacher.findAll(page));
    }
}

when I call printPage method without @Async annotation it works fine. but when I use it throws the following exception:

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:807) [spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:788) [spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) [spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.2.jar:2.4.2]
    at com.hatef.demo.DemoApplication.main(DemoApplication.java:97) [classes/:na]
Caused by: java.lang.ClassCastException: org.springframework.util.concurrent.ListenableFutureTask cannot be cast to org.springframework.scheduling.annotation.AsyncResult
    at async.PrintAllTeacherDataBaseResult$$EnhancerBySpringCGLIB$$ccbb6656.printPage(<generated>) ~[classes/:na]
    at com.hatef.demo.DemoApplication.run(DemoApplication.java:103) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:804) [spring-boot-2.4.2.jar:2.4.2]
    ... 5 common frames omitted


    java.lang.IllegalStateException: EntityManagerFactory is closed
    at org.hibernate.internal.SessionFactoryImpl.validateNotClosed(SessionFactoryImpl.java:513) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.SessionFactoryImpl.getMetamodel(SessionFactoryImpl.java:660) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.findEntityPersisterByName(SessionFactoryHelper.java:141) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:167) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:91) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.java:77) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:333) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3758) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3647) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:732) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:588) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:325) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:273) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:779) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.query.criteria.internal.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:314) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:165) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:742) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:113) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.3.jar:5.3.3]
    at com.sun.proxy.$Proxy101.createQuery(Unknown Source) ~[na:na]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:703) ~[spring-data-jpa-2.4.3.jar:2.4.3]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:654) ~[spring-data-jpa-2.4.3.jar:2.4.3]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:444) ~[spring-data-jpa-2.4.3.jar:2.4.3]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:411) ~[spring-data-jpa-2.4.3.jar:2.4.3]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:524) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:531) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:156) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) [spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) [spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) [spring-data-jpa-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) [spring-aop-5.3.3.jar:5.3.3]
    at com.sun.proxy.$Proxy105.findAll(Unknown Source) [na:na]
    at services.TeacherServiceImpl.findAll(TeacherServiceImpl.java:33) [classes/:na]
    at async.PrintAllTeacherDataBaseResult.printPage(PrintAllTeacherDataBaseResult.java:23) [classes/:na]
    at async.PrintAllTeacherDataBaseResult$$FastClassBySpringCGLIB$$ccfcfab4.invoke(<generated>) [classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) [spring-core-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) [spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) [spring-aop-5.3.3.jar:5.3.3]
    at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_151]
    at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_151]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_151]

and how I call it:

@Autowired
ApplicationContextProvider applicationContextProvider;

public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
}

@Override
public void run(String...args) throws Exception {
    PrintAllTeacherDataBaseResult p = applicationContextProvider.getApplicationContext().getBean(PrintAllTeacherDataBaseResult.class);
    AsyncResult<List<Teacher>> a = p.printPage(PageRequest.of(0, 2));
    a.get().stream().forEach(System.out::println);
}

but my question is why it throws exception.


update

I don't know why but I changed @EnableAsync to @EnableAsync(mode = AdviceMode.ASPECTJ) and everything worked! but it is not created new thread

now my question is why it throws exception when using @EnableAsync and why it works when @EnableAsync(mode = AdviceMode.ASPECTJ)


update

I could solve my problem by applying these changes to my code: first revert @EnableAsync(mode = AdviceMode.ASPECTJ) to @EnableAsync and then:

public interface TeacherService {
    @Async
    Future<List<Teacher>> findAll(Pageable pageable);
}

and how it is implemented:

public class TeacherServiceImpl implements TeacherService{

        @Autowired
        private TeacherRepository repository;

        @Override
        public Future<List<Teacher>> findAll(Pageable pageable) {
             Page<Teacher> page =  repository.findAll(pageable);
             return new AsyncResult<>(page.get().collect(Collectors.toList()));
    }
}

and how I ran above methods:

@Autowired
ApplicationContextProvider applicationContextProvider;

public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
}

@Override
public void run(String...args) throws Exception {
    PrintAllTeacherDataBaseResult p = applicationContextProvider.getApplicationContext().getBean(PrintAllTeacherDataBaseResult.class);
    Future<List<Teacher>> a = p.printPage(PageRequest.of(0, 2));
    a.get().forEach(System.out::println);
}

I appreciate any help that clarifies exactly what is going on.

like image 732
hatef alipoor Avatar asked Feb 02 '21 08:02

hatef alipoor


People also ask

How do you enable the use of @async Annotation in query method?

To enable the asynchronous processing, add the @EnableAsync annotation to the configuration class. The @EnableAsync annotation switches on Spring's ability to run @Async methods in a background thread pool.

Does @async work on private method?

Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work.

What does @async annotation do?

Simply put, annotating a method of a bean with @Async will make it execute in a separate thread. In other words, the caller will not wait for the completion of the called method. One interesting aspect in Spring is that the event support in the framework also has support for async processing if necessary.


1 Answers

You should take a look on this article https://www.baeldung.com/spring-async

First of all async method with return type should be wrapped in Future. Each time you call get() on feature object you subscribe on the result and your current thread will wait until the result will be calculated.

UPD: First of all try to read javadoc for AsyncExecutionInterceptor and Async.

<p>In terms of target method signatures, any parameter types are supported.
However, the return type is constrained to either {@code void} or
{@link java.util.concurrent.Future}. In the latter case, you may declare the
more specific {@link org.springframework.util.concurrent.ListenableFuture} or
{@link java.util.concurrent.CompletableFuture} types which allow for richer
interaction with the asynchronous task and for immediate composition with
further processing steps.

And it's an API, you should follow it. In case 1 you were using AsyncResult. It's not allowed type, but it inheritances from ListenableFuture.

Now inside this method of AsyncExecutionAspectSupport

@Nullable
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
    if (CompletableFuture.class.isAssignableFrom(returnType)) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return task.call();
            }
            catch (Throwable ex) {
                throw new CompletionException(ex);
            }
        }, executor);
    }
    else if (ListenableFuture.class.isAssignableFrom(returnType)) {
        return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
    }
    else if (Future.class.isAssignableFrom(returnType)) {
        return executor.submit(task);
    }
    else {
        executor.submit(task);
        return null;
    }
}

you got into second else statement and later it provided ClassCastException (you can debug it deeper).

About version 2:

Future<List<Teacher>> a = p.printPage(PageRequest.of(0, 2));

Actually You didn't call printPage, you just created a future which will call it inside as soon as you started to execute it. And it will start on a.get() and execution will be started in separate thread (in case you configured thread executor with more than 1 thread).

like image 82
DamienMiheev Avatar answered Sep 29 '22 23:09

DamienMiheev