spring-cloud-commons icon indicating copy to clipboard operation
spring-cloud-commons copied to clipboard

Properties not resolved on FactoryBean initialization for beans defined in XML

Open krysz-clgx opened this issue 3 years ago • 0 comments

Describe the bug Spring Cloud Commons: 4.0.0 Spring Boot: 3.0.1

This issue is strictly related to: https://github.com/spring-cloud/spring-cloud-commons/issues/439 and https://github.com/spring-cloud/spring-cloud-config/issues/1167

I've been using the Spring Cloud to connect to a config server on PCF, unfortunately it is some legacy code with beans declared in old-XML fashion way. We have theorg.springframework.transaction.interceptor.TransactionProxyFactoryBean as an abstract bean (defined in beans.xml file) which is parent to couple of specific bean instances. One of them does not contain the class attribute in definition. All of these instances contains transactionManager which has the sessionFactory which has our OracleDataSource class as property. The last one needs username/password/url to be properly initialized. They should be resolved from application.yml file. Everything was working correctly until we migrated to the PCF. For some reason the SpringBoot started to throw the BeanCreationException:

Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.sql.SQLException: Invalid Oracle URL specified: OracleDataSource.makeURL

This URL is indeed null.

It is caused by calling this instruction: https://github.com/spring-cloud/spring-cloud-commons/blob/097959a64af4d4c1a3a45c90d150ea2455d817dd/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/RefreshAutoConfiguration.java#L231

it starts the cascade of bean creation if it cannot predict type or the type is assignable to FactoryBean. It turned out the the DefaultListableBeanFactory used here does not have properly initialized properties (or PostProcessors?)

To wrap it up: it can happen only if:

  • we have the spring-cloud enabled
  • the bean is defined in XML without the class attribute
  • the bean implements org.springframework.beans.factory.FactoryBean<> interface

The simplest workaround is just defining the missing attribute but since it is not required by default I consider it as a bug.

Sample The complete application to recreate this issue: https://github.com/krysz/spring-cloud-commons-xml-bug

It contains BaseBean which is the instance of FactoryBean, the ChildBean defined in XML without class attribute and the DataSource bean with injected property. If you disable spring-cloud or add the class attribute the whole application runs fine and prints 42 as property value but with my provided configuration it fails with error: Caused by: java.lang.InstantiationException: Could not initialize dataSource with someProperty!

I think @D0rmouse correctly identified the root cause of it:

They fixed a initialization cascade, but the log from the demo project shows that the properties are loaded and should be resolvable when the FactoryBean is initialized.

And he also proposed the solution:

I would say you first load the properties and then instantiate any FactoryBeans that require properties, or not even load any FactoryBeans before loading the properties. The latter is probably not possible, because FactoryBeans are involved in loading properties.

krysz-clgx avatar Jan 17 '23 14:01 krysz-clgx