Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Retryable annotation ClassNotFoundException

I would like to use @Retryable annotation for restTemplate. I've added:

<dependency>
       <groupId>org.springframework.retry</groupId>
       <artifactId>spring-retry</artifactId>
       <version>1.2.1.RELEASE</version>
</dependency>

as well as @EnableRetry to config class. I've marked method:

restTemplate.exchange(url, HttpMethod.POST, request, String.class);

with (in a new thread)

@Retryable(maxAttempts=4,value=Exception.class,backoff=@Backoff(delay = 2000))

But I'm getting error from catalina:

27-Oct-2017 18:11:41.023 SEVERE [http-nio-8080-exec-1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener]
 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
    at 
<ommitted>
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:154)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1103)
    ... 61 more
Caused by: java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
    at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.<clinit>(ReflectiveAspectJAdvisorFactory.java:76)
    at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.<init>(AnnotationAwareAspectJAutoProxyCreator.java:53)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
    ... 63 more
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Around
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
    ... 70 more

27-Oct-2017 18:11:41.038 INFO [http-nio-8080-exec-1] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext

What I'm doing wrong ?

EDITED: I moved a little bit forward. Found that Spring Retry makes use of AOP so I added:

<dependency>
  <groupid>org.springframework</groupid>
  <artifactid>spring-aop</artifactid>
  <version>4.2.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.8</version>
</dependency>

Now I'm getting different error:

27-Oct-2017 21:11:12.071 SEVERE [http-nio-8088-exec-5] org.springframework.web.servlet.DispatcherServlet.initServletBean Context initialization failed
 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController' defined in file [(...)\HomeController.class]: Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.aop.framework.ObjenesisCglibAopProxy
    <ommitted>
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.springframework.aop.framework.ObjenesisCglibAopProxy
    at org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(DefaultAopProxyFactory.java:60)
    at org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy(ProxyCreatorSupport.java:105)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:468)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:349)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:298)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1558)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    ... 35 more

To isolate the problem I created small springMVC project and it's the same. To keep everything simple used only few dependencies. This is output from mvn dependency:tree:

[INFO] com.example:store:war:0.0.1-SNAPSHOT
[INFO] +- org.springframework:spring-webmvc:jar:4.0.3.RELEASE:compile
[INFO] |  +- org.springframework:spring-beans:jar:4.0.3.RELEASE:compile
[INFO] |  +- org.springframework:spring-context:jar:4.0.3.RELEASE:compile
[INFO] |  +- org.springframework:spring-core:jar:4.0.3.RELEASE:compile
[INFO] |  |  \- commons-logging:commons-logging:jar:1.1.3:compile
[INFO] |  +- org.springframework:spring-expression:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.springframework:spring-web:jar:4.0.3.RELEASE:compile
[INFO] +- javax.servlet:jstl:jar:1.2:compile
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] +- org.springframework.retry:spring-retry:jar:1.2.1.RELEASE:compile
[INFO] +- com.mashape.unirest:unirest-java:jar:1.4.9:compile
[INFO] |  +- org.apache.httpcomponents:httpasyncclient:jar:4.1.1:compile
[INFO] |  |  +- org.apache.httpcomponents:httpcore:jar:4.4.4:compile
[INFO] |  |  \- org.apache.httpcomponents:httpcore-nio:jar:4.4.4:compile
[INFO] |  +- org.apache.httpcomponents:httpmime:jar:4.5.2:compile
[INFO] |  \- org.json:json:jar:20160212:compile
[INFO] +- org.springframework:spring-aop:jar:4.2.5.RELEASE:compile
[INFO] |  \- aopalliance:aopalliance:jar:1.0:compile
[INFO] \- org.aspectj:aspectjweaver:jar:1.8.8:compile
like image 710
user3529850 Avatar asked Oct 27 '17 16:10

user3529850


2 Answers

It worked for me after adding the spring-boot-starter-aop dependency like below:

compile ("org.springframework.boot:spring-boot-starter-aop:1.5.10.RELEASE")
like image 98
Sahil Chhabra Avatar answered Oct 10 '22 12:10

Sahil Chhabra


I will answer my own question 'cause it seems to be working now. All dependencies that are necessary:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.10</version>
</dependency>

check if there is no duplicate dependencies (f.e. by mvn dependency:tree, use <exclusions> where necessary). Be sure you decorated your config class with @EnableRetry. For some reason you need to separate the caller from the method itself. F.e.this:

@Retryable(maxAttempts = 4, value = {ResourceAccessException.class}, backoff = @Backoff(delay = 5000))
public ResponseEntity<String> tryToSendAndReturnResponseByRestTemplate(final RestTemplate restTemplate,
                                                                       final HttpEntity<MyObjDTO>
                                                                               request) {

    return restTemplate.exchange(resolveUrl(ENDPOINT_ADDRESS), HttpMethod.POST, request, String.class);
}

goes to SenderManager class marked as f.e. @Service and in a different class f.e. PhoneDirector class you call:

senderManager.tryToSendAndReturnResponseByRestTemplate(restTemplate, request);

It should work. (If you need to specify what supposed to be returned if after 4 (only here) attempts you're still getting an exception, you can create another method (in SenderManager class) marked with @Recover, like this:

@Recover
public ResponseEntity<String> recoverWhenSendingMessageFailed(final ResourceAccessException e) {
    return new ResponseEntity<>(e.getMessage(), HttpStatus.REQUEST_TIMEOUT);
} 

But If you needed args from @Retryable (in @Recover method) remeber that arguments are populated from the argument list of the failed method in the same order as the failed method, and with the same return type

like image 25
user3529850 Avatar answered Oct 10 '22 12:10

user3529850