Definitely, especially in case of monolithic applications, the startup code needs to be modularized. Installers are a very good approach — then your
main() method just calls them. I’d still opt for explicitly specifying the order in which they should be run.
So I think this can be implemented quite easily using e.g. a simple list holding a number of
Installer instances, without the need for an IoC container :)
(by the way: you could probably argue that a well written monolith is in fact a number of microservices deployed together, communicating in-process instead of over HTTP)