What I've done is on init of the control, query the DI container and populate those references. You could nest this logic in a specialized base class that your custom server control can inherit from, so then it's reused. OR: There is a special AddedControl method that is called everytime a control is added to the control tree. The caveat here is that it probably only calls the method on the parent control, and does not propogate up. It may work depending on your scenario.
There isn't much in the lifecycle that lets you know when a control is created (other than the AddedControl method or the Init method that runs at the beginning of the process) to be able to tap into, and you can't customize the constructor of the control.
In regards to #1, to use the markup approach would require tapping into the design-time aspect of controls, and leveraging the design time attributes to the fullest. But #1 means defining the mappings in markup, which is not quite the point of a DI container. The designer still needs the property or something to assign the reference to, so it would essentially be double work of defining the property, then defining something in the designer, when the DI container takes care of that for you.