42

I have a problem getting a Spring Data based application to run in my environment. I am running Debian, but my co-workers are either using Mac or Ubuntu. I have nothing special set up in my environment variables, and am using the exact same version of Java as others.

I have seen this in the logs, suggesting that it is a circular reference problem that is leading to the instantiation failure:

nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'flyway.CONFIGURATION_PROPERTIES':
Initialization of bean failed;
...
nested exception is
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'flyway': Requested bean is currently in
creation: Is there an unresolvable circular reference?

So the problem appears to be that flyway needs some dependencies and they need flyway.

The question is, why does this only happen on my environment not anyone elses? Even on the tests using H2 in memory, I see the problem, so its not my database that is at fault.

Is it possible that Spring autowiring is confused somehow, and tries to do things in the wrong order, so that the repository is null when it tries to set it?

Does Spring have a badly implemented topological sort for ordering dependencies?

Why would it misbehave on my environment?

Could ordering of the classpath influence its behaviour?

======================

The application will not start with this error:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contentItemRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Repository interface must not be null on initialization!
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:127)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1127)

============================

The ContentItemRepository signature is:

@Repository
@Transactional
public interface ContentItemRepository extends JpaRepository<ContentItem, String>, JpaSpecificationExecutor<ContentItem> {

============================

This used to work for me, and I was able to identify the commit that broke the build, by iterating through all commits, doing a mvn clean install, and trying to start the server, until I found the delta that broke it.

The 'contentItemRepository' that cannot be null is this one:

@Component
+public class UrlAliasRequestConverter implements Mapper<UrlAliasRequest, UrlAlias> {
+
+    /**
+     * The content item contentItemType repository.
+     */
+    @Autowired
+    private ContentItemRepository contentItemRepository;
user2800708
  • 1,890
  • 2
  • 18
  • 31
  • 2
    Its a shame that Spring errors say "Error creating bean with name 'yourField'", but do not list the class that contains the field. Surely "Error creating bean YourClass.yourField" would be possible and significantly more helpful. In many cases the same field name 'yourField' might appear many times in the code; which one? – user2800708 Mar 31 '15 at 08:04
  • Could you add the full stacktrace + the flyway bean-config + datasource(s) bean-config (including `@Profile`s or `@Conditional`s used)? – fateddy Apr 06 '15 at 08:19
  • What class implements ContentItemRepository? – Jimmy T. Apr 07 '15 at 17:10
  • There's not enough to get a full picture here yet...can you post your ContentItemRepository implementation like Jimmy T. asked? Also, can you please post the flyway beans that you have concerns about? _Last_ request, I promise: can we get a little more of the logs too? Just comb them for "repository"; I have a feeling your repository might be failing creation and the logs might show why. – wholevinski Apr 08 '15 at 11:12

10 Answers10

10

I've the same issue on Ubuntu 16.04.

I found that the problem with

@ComponentScan(basePackages = "com.my.app")

The code is running at least 5 different machine (windows, ubuntu 15.04 and ubuntu 16.04 desktop) but doesn't start our CI server (ubuntu 16.04 server).

After I changed

@ComponentScan(basePackages = "com.my.app")

to

@ComponentScan(basePackages = {"com.my.app.service", "com.my.app.config", "com.my.app"})

the code is running on CI server too.

I think this is a Spring issue with beans loader...

UPDATE:

https://github.com/spring-projects/spring-boot/issues/6045

https://jira.spring.io/browse/SPR-14307

István Pató
  • 351
  • 3
  • 7
5

This is very likely related to the order in which the class files are read in line

dir.listFiles() in PathMatchingResourcePatternResolver.doRetrieveMatchingFiles()

Since the order of file listing (class files) is dependent on the platform, and there is no sorting done on the array, the order the classes are loaded in is dependent on how the platform returns them.

ref (archived): http://forum.spring.io/forum/spring-projects/container/115998-circular-dependency-identification-inconsistent

JohnEye
  • 6,436
  • 4
  • 41
  • 67
vikx01
  • 53
  • 3
  • 6
3

I don't understand why this happened, but here is the only solution that I came up with:

Install Debian 8, and it works.

I tried it in another clean install of Debian 7, and got less errors there, but still had some. A clean install of Debian 8 seemed to work.

I can only conclude that Java must be calling some system library, that in some way affects the order in which Spring dependencies are resolved. That library must be upgraded in Debian 8, bringing me in-line with the Ubuntu installs that other devs and production are using.

I don't know what that library might be... Something that scans the files in the filesystem, reporting them in a different order? Something that unpacks a .jar file, reporting its contents in a different order?

It seems wrong to me that our code is so sensitive to the exact order of dependency resolution and injection, but that would appear to be the case. It also does not look like there is anything in our code that should make it sensitive to the ordering, we're not doing anything crazy, and following pretty standard patterns of usage.

Too much Spring magic keeping the house of cards standing if you ask me. My other projects are on DropWizard, and there the dependency injection is manually coded up, so no surprises.

=== Update

I upgraded the Debian 7 box to 8, and the problem still persists. Therefore my hypothesis about it being library version is wrong. Must be something about my environment.

I created a new user on the box. The problem is still there for that user. There is something about this box it really does not like, but I cannot figure out what it is.

I'd like to get to the real cause and understand it, but I don't think I can really dedicate any more time to figuring it out.

Anyway, a clean install of Debian 8 solves the problem.

user2800708
  • 1,890
  • 2
  • 18
  • 31
  • I know that you have stopped investigating, but do you know in the meantime what may have caused the problem? – gillesB Oct 16 '15 at 09:21
  • No, but I suspect the Java install on that machine got messed up somehow. A clean environment and new install of Java fixed it, or at least made my machine behave the same way as others. So if you have a problem, I'd recommend trying on another environment - if it behaves the same then maybe you have a genuine Spring dependency resolution problem. – user2800708 Oct 16 '15 at 09:39
  • 1
    Our projects worked on 2 PCs with Windows but did not on a PC with Ubuntu. Anyway we located the class which caused the problem and renamed (!) it. Afterwards the project works again on all three systems. – gillesB Oct 16 '15 at 10:50
  • Something to do with the order of the classes in the class loader? – user2800708 Oct 18 '15 at 16:42
  • The weird part about this problem is that it depends on compilation and execution environments. In our case, compiling and running in my machine (Ubuntu, Java 1.8.0_144) worked, compiling and running in a teammate's machine (Mac, Java 1.8.0_144) also worked, but compiling in our machines and running in a third machine through docker (Debian, Java 1.8.0_151) only worked with the Mac compilation, not with the Ubuntu compilation ... – Alex Vazquez Fente Jan 05 '18 at 14:25
3

While all answers focus on the failing machine and how to fix it, I would like to point out that we should wonder about the machines that are NOT failing. If there is a cycle, the DI should fail! We would like this to happen in all environments consistently.

We came across the same behavior where production fails but staging, dev and CI are all fine. That is so sad. We were not able to create a minimal example with that issue.

Stuck
  • 11,225
  • 11
  • 59
  • 104
  • 1
    Its true, the problem seems non-deterministic. It is not that hard to implement a topological sort that is deterministic. For example all classes are always fully orderable alphabetically, and that could be used to make the top-sort deterministic. – user2800708 Aug 22 '20 at 12:15
  • I woted for this answer not because it is an answer but because of the fact that the true problem is not to get around the circular dependency but to have all env's fail in the same way – PlickPlick Jul 06 '21 at 11:51
2

What is your repository interface extending? You can look at the Spring source code and see why the exception is thrown:

https://github.com/spring-projects/spring-data-commons/blob/master/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java

@SuppressWarnings("unchecked")
public Class<? extends T> getObjectType() {
    return (Class<? extends T>) (null == repositoryInterface ? Repository.class : repositoryInterface);
}

Here's an example of my repository:

@Repository
public interface GameRepository extends JpaRepository<Game, Long> {
Brian Kates
  • 480
  • 4
  • 14
2

I got the same problem yesterday. I don't know why, but I found a way to solve the problem: mark all the beans involved in the circular dependency tree as lazy-init. Not only the ones directly circular dependent to each other, but all the beans that reference them!

The project is an old one thus it only uses spring 3. I am not sure whether the later versions of spring still get this problem.

fifman
  • 369
  • 4
  • 4
  • I can confirm that Spring 4 still has this non deterministic behaviour. I fixed a similar problem that was driving me crazy by using the `@Lazy` annotation on the field reported by the error `Error creating bean with name CLASS: Unsatisfied dependency expressed through field FIELD;` – Alex Vazquez Fente Jan 05 '18 at 14:12
2

We came across this problem today, in a nearly identical situation - application failing to start due to a circular reference, apparently while constructing Spring Data @Repository instances, and only on one developer's machine.

In our case the solution was to refactor our configuration so that an ApplicationListener<BeforeSaveEvent> was moved from being an anonymous class defined within a @Configuration class, and turned into a top-level @Component.

It seems that in some non-obvious way Spring Data repositories keep some sort of handle to these application listeners, and by having ours as an anonymous inner class the repository was implicitly maintaining a reference to its enclosing @Configuration (and thus a dependency loop being detected due to beans instantiated via that @Configuration which eventually autowired the repository).

All of the answers describing changing lazy init, changing your component scan order, reinstalling your OS, turning it off and on again etc. are only hiding rather than really addressing the problem, and I would suggest instead fixing it at its source :) The reason things work or don't work on various machines is just that, as @xki alludes to, the object graph construction order is non-deterministic.

ryanp
  • 4,905
  • 1
  • 30
  • 39
0

I do not know why this particular issue would occur on one machine and not another, but I think the issue is most likely that both beans are using constructor injection to pass references to each other which is creating the unresolvable circular dependency- A needs B for its construction which in turn needs A- neither can be created without the other already having been created. If the both objects require a reference to the other, you need to instead pass it via setter injection after the objects have already been created. The answers to this question are relevant to the problem you are having.

Community
  • 1
  • 1
JacksonWeekes
  • 312
  • 3
  • 11
  • 2
    This isn't the answer. It does work on some machines and not others. If it were constructor injection, it would not work on any machine, no matter what. – user2800708 Apr 20 '15 at 10:04
0

For us the the problem was high CPU utilization and this error appeared out of nowhere.

Run the below command in linux to find cpu utilization:

top -b -n1 | grep ^%Cpu | awk '{cpu+=$9}END{print "Current CPU Utilization is : " 100-cpu/NR}'

If it's 100 or near, it means we have to kill some other microservice not currently used or upgrade our system capacity.

nanospeck
  • 3,388
  • 3
  • 36
  • 45
0

Temporary crutch solution: ENV spring.main.lazy-initialization=true

Alexey Stepanov
  • 561
  • 6
  • 15