4

When I'm working on write some spring code, I'm using spring 4 with class and annotation-config. I have declared a bean implements an interface as a component. And I'm trying to make another bean to depends on it with its interface time. But it doesn't work because spring throws an error with no bean found in that name. I think it may because depends on is only work with concretive class auto wire, but I don't know why it set in this way? Is anyone could explain why depends on annotation don't allow type auto wire to an interface?

The simple sample code is like this

@Component
class A implement B{
}

@Component
@DependsOn("B")
class C {
}

the code above cannot work unless I change @DependsOn("B") to @DependsOn("A")

Liyuan
  • 85
  • 1
  • 1
  • 6
  • To my knowledge, `@DependsOn` does not autowire anything. Could you clarify what you're trying to do? – CollinD Apr 21 '17 at 19:54
  • Because `DependsOn` works on names not on types. – M. Deinum Apr 21 '17 at 20:46
  • Thank you for all your help. After doing some search, I found, dependsOn is only working with classes. When using dependsOn we need give code a classId, because Spring has to instantiate that class. – Liyuan Apr 25 '17 at 15:12
  • @M.Deinum - DependsOn works with class names too - it just doesn't work with interfaces. You use it with bean names when you're using it with bean Configuration. You use it with class names when you annotate components with it. This is the problem we get into when there are 20 sites out there that all copy each other's examples - by the time you're done re-reading all the copies, you begin to believe that's the only way to do something. – John Calcote Jul 16 '19 at 16:44
  • 1
    `@DependsOn` doesn't work with classnames, it works with beannames only. The default in Spring is that the classname is turned into a beanname (check the default `BeanNameGenerator` implementation for that). And it uses the simple classname NOT the FQN. – M. Deinum Jul 17 '19 at 05:43

3 Answers3

9

In general DependsOn should never be used. If you ever need to it, you have probably done something wrong, or you have an extreme corner case. I have used Spring since 2006 and have not needed it yet.

The JavaDoc says

Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialization.

This basically means you only use DependsOn if you or some one else have written bad code. For instance one beans constructor creates a resource on disk that another bean needs when constructed. Springs IoC container and declarative wiring lets you control dependencies between beans, but in the extremely rare case where some legacy code has undeclared dependencies DependsOn lets you control the order unrelated spring beans are constructed.

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
Klaus Groenbaek
  • 4,820
  • 2
  • 15
  • 30
  • 2
    Legacy code is not the only example of good spring code requiring DependsOn. Consider an http service component that uses jersey ioc with spring. If you don't want your application to "open for business" before some data acquisition component has completed its initialization and data gathering process, then you might use DependsOn on your http service component to indicate that it depends on this data acquisition component. There's no direct spring dependency, but you still need the server to not start until after the data is ready. – John Calcote Jul 16 '19 at 16:39
  • 1
    @John Calcote This case is covered by the `SmartInitializingSingleton` interface https://stackoverflow.com/a/48771885/355438 – Ilya Serbis Aug 09 '19 at 13:37
  • Rather pedantic answer. There are use cases of course that warrant the use of this annotation, otherwise it wouldn't be available. One example that comes to mind is a bean that depends on an external server to be available, but which you might want to mock/stub during a (cucumber) test. In which case the server isn't already available because you spin it up during the test (examples: embedded DB, JMS, FTP, MailServer, etc. etc.) – Benny Bottema May 20 '21 at 08:08
  • 2
    @BennyBottema I built spring test infrastructure for several large Spring based projects, and I still have not used DependsOn. If you depend on external resources such as testcontainers `JdbcDatabaseContainer` I prefer to link them to Spring beans, so the dependency is explicit. If I need to populate an external resource I will do so using SmartLifeCyle beans, so there is a clear separation of the bean instantiation phase, and lifecycle start, where you can interact with the resources, and start background threads. – Klaus Groenbaek May 20 '21 at 17:21
0

For simple autowiring, use @Autowired either on field or constructor. Starting with Spring 4.3 you can omit the @Autowired when using constructor injection.

@Component
class A implement B {
}

@Component
class C {
    private final B b;

    public C(B b) {
        this.b = b;
    }
}
Abdullah Khan
  • 12,010
  • 6
  • 65
  • 78
Svante
  • 311
  • 2
  • 8
0

I had same problem when I tried to used depends on, but after doing my research I found that the best way is to remove the dependency of B in class C constructor and use this logic in a method init annotated by @PostConstruct, so after initializing all the constructors this method will be executed. Hope my answer helps you.

Chris Sim
  • 4,054
  • 4
  • 29
  • 36