Doing significant work in static code blocks leads to nothing but trouble, as the Random situation demonstrates.
I thought it would be useful to describe what CXF does to avoid this. While CXF does use Spring, we don't require users CXF to use Spring. Instead, we use a simpler internal organization called a bus, and then users have the option to configure with Spring. (I don't know anything about Guice, so I'll use Spring as the example.) The Bus, at its core, is a map from Class<T> to T. That is, the bus can have one item of each class on it. Objects on the bus are configurable blobs of functionality. If Mahout had a bus, the RNG would be an object on it. If we wanted to be flexible about Hadoop versions, perhaps we could create an interface that abstracted and put an object on a bus, and have several available for different versions of Hadoop. As a code pattern, objects that use facilities from the bus all have (at least) two constructors: one that takes a Bus, and one that doesn't. If constructed without a bus, they use the default bus. The default bus, then, is the one static. (OK, in fact, classes have local statics for some optimizations, but they are carefully arranged not to be time consuming or source of configuration trouble). The default bus has code to configure itself without an IoC framework at all. It looks for XML files in META-INF with a name pattern, and parses them for configuration instructions that push objects onto the bus. It also supports some @Annotations for this purpose, I confess that I'm not as clear on that. It definitely supports @Resource annotations to inject bus resources, including the bus itself. The default configuration, however, is for the bus to configure with Spring. It create an app context and loads XML files into it (again via a classpath pattern in META-INF). I am not especially in favor of my own Random patch. If people are willing to run in 'fork-once' mode to get the clock time down, and prefer to stick with the uncommons RNG, then it's not useful.