0

I am attempting to convert an existing spring weblogic application to a spring boot embedded tomcat application.

There are lots of moving parts so it's hard to show any code, I'm hoping there is some general answer that might clue me in to the issue.

Under weblogic, using the spring-framework 4.3.6.RELEASE libraries, the application deploys fine. It has no problems creating the different service, repository and component beans.

However, when I migrate it to Spring Boot 1.5.1.RELEASE, I get the following error:

2017-06-21 17:08:16,402 [ERROR] SpringApplication reportFailure (815) - Application startup failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'alertEventServiceImpl': Unsatisfied dependency expressed through field 'alertEventDao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'alertEventDaoImpl' defined in URL [jar:file:/Users/username/Development/source/carma-war/target/carma-war-2.0.0-SNAPSHOT.war!/WEB-INF/lib/protocol-manager-1.8.0-SNAPSHOT.jar!/org/ihc/hwcir/protocol/dao/AlertEventDaoImpl.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.ihc.hwcir.protocol.dao.AlertEventDaoImpl]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class org.ihc.hwcir.protocol.dao.AlertEventDaoImpl

Many of our service classes are final as they shouldn't be extended. Since there are so many that are final, I wanted to minimize the amount of code in our different libraries that we modify to make this work.

I thought because the bean creation process works under weblogic, it should work under spring boot.

Things I have tried to force not using the cglib proxies:

  1. All implementations implement interfaces already
  2. In beans created via xml, added <aop:scoped-proxy proxy-target-class="false"/>
  3. In beans created through annotations, added (example for service bean)

@Service @Scope(proxyMode = ScopedProxyMode.INTERFACE)

However, in the end, I'm perplexed as to why spring can create beans (the classes marked as final) under the weblogic container but unable to do so under the embedded tomcat spring-boot container.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Johnnie
  • 305
  • 2
  • 16
  • In your web logic container it doesn't use CGLIB but JDK Dynamic proxies which are interface based. Spring Boot forces class proxies and to disable that you need to modify the configuration. Also you aren't using scoped proxies so setting that to attribute to false doesn't make a difference. You will have to change transaction processing, override some configuration for JPA setup etc. to have interface based proxies. See for instance [this](https://github.com/spring-projects/spring-boot/issues/8434) issue. – M. Deinum Jun 22 '17 at 06:57
  • For Spring Boot 1.5 you should set `spring.aop.proxy-target-class=false` in your `application.properties` and you should be good to go. The default is `true`. – M. Deinum Jun 22 '17 at 07:03

2 Answers2

0

Spring Boot by default uses class based proxies, which will not work with final classes/methods.

To disable this add spring.aop.proxy-target-class=false to the application.properties to enable JDK Dynamic Proxies instead of class based proxies. (And revert your modifications).

NOTE: To have everything take into account the spring.aop.proxy-target-class you might need to upgrade to Spring Boot 1.5.3 as some final patches where made to include this property in parts that were missed in previous versions.

See the following issues for more information 8434, 8869 and 8887.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • Unfortunately that didn't do it. What did make it work was this setting, not sure why. spring.dao.exceptiontranslation.enabled=false ... do you know? However - your link to another issue for dealing with transaction managers was right on. I'm happy to accept this answer if you add your link to it and give me an understand of why the exceptiontranslation.enabled=false worked instead of the aop.proxy-target-class. – Johnnie Jun 25 '17 at 21:22
  • That basically disables exception translation for repositories and as such the need for proxy creation for repositories. Instead of disabling that I suggest configuring the `PersistenceExceptionTranslationPostProcessor` yourself and set the `proxyTargetClass` property to false. (in addition to the `spring.aop.proxy-target-class=true`. – M. Deinum Jun 26 '17 at 05:41
  • That basically disables exception translation for repositories and as such the need for proxy creation for repositories. Instead of disabling that I suggest configuring the `PersistenceExceptionTranslationPostProcessor` yourself and set the proxyTargetClass property to false. (in addition to the `spring.aop.proxy-target-class=false`).The `PersistenceExceptionTranslationAutoConfiguration` takes into account this property, so weird that it doesn't work. (ah this was added Spring Boot 1.5.3, so you might want to upgrade to the latest 1.5.x version instead of disabling this). – M. Deinum Jun 26 '17 at 05:56
0

I was unable to make this work using M. Deinums' answer using spring.aop.proxy-target-class=false.

What worked for me was to add in the application.properties file

spring.dao.exceptiontranslation.enabled=false

Please note that this option disables proxy creation for repositories.

And in my spring boot application configurer the annotation to handle transactions without using a proxy class.

@EnableTransactionManagement(proxyTargetClass = false)

This is using Spring Boot version 1.5.1.RELEASE.

Johnnie
  • 305
  • 2
  • 16