The springification is what I mean by it being externalized and you generally don't see that in C, no. The pre-processor might be sort of the same thing but you generally don't bootstrap the entire thing using it.
But this is absolutely domain-specific, Java the language is indifferent to exposing a library that will handle incoming request and dispatch them based on some library logic, or creating a “traditional” program for the litany of other domains where java is used st.
If you'd chosen languages that permit abstractions in a real and usable sense, then you would not need this. In fact: with _one_ exception, I've never had a container in any Haskell, Scala or F# project ever. Do you think we ever needed one?
And this is my point: those other languages have seen _tons_ of development in the "abstraction arena" with (internal) DSL:s and super powerful frameworks for making powerful DSL:s. Java has had none of this because these concerns har all (poorly) handled at the container level.
The tacked on "functional stuff" is for sure cool coming from a Java backround, but they're pretty much useless.
This "containerizing" is very unique to Java -- I've never seen anything like it in the other various languages I've used. I won't even mention the total disaster of JavaEE containers.
My point, though, is not to throw up all over Java but rather to quibble with the statement that Java has somehow evolved since then. It really hasn't!