Two things:
- They require extra tool support to check that the configuration is valid.
For example, IntelliJ (commercial edition) has support for checking the validity of a Spring configuration, and will flag up errors such as type violations in the configuration. Without that kind of tool support, you can't check whether the configuration is valid before running tests.
This is one reason why the 'cake' pattern (as it's known to the Scala community) is a good idea: the wiring between components can be checked by the type checker. You don't have that benefit with annotations or XML.
- It makes global static analysis of programs very difficult.
Frameworks like Spring or Guice make it difficult to determine statically what the object graph created by the container will look like. Although they create an object graph when the container is started up, they don't provide useful APIs that describe the object graph that /would/ be created.