One quick note before I begin - obviously, this ties your application to Tomcat so you might want to look at ways of abstracting this out if server portability is a concern.
The first thing you need to do is make sure that a jvmRoute value is being set. This is as simple as adding something like -DjvmRoute=jvm1 to your VM arguments.
Next up is adding a MBeanProxyFactoryBean to your application context. To inject a proxy for the Engine, you need
<bean id="tomcatEngineProxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="objectName" value="Catalina:type=Engine" />
<property name="proxyInterface" value="org.apache.catalina.Engine" />
<property name="useStrictCasing" value="false" />
You may or may not need to play about with the objectName value depending on how you have configured your Engine in server.xml - have a look here.
Setting useStrictCasing to false is especially important. For some reason Spring's default behaviour is to set useStrictCasing to true. What this means is that when you access a property via a getter (in our case, getJvmRoute) causing the proxy to ask for the property value over JMX, by default it ignores normal Javabean style conventions and asks for the "JvmRoute" property. Apache is expecting to be asked for the "jvmRoute" property and you'll be on the receiving end of a "cannot find property" error. Setting useStrictCasing to false makes Spring ask for "jvmRoute" instead. I'd really like to know why useStrictCasing is set to true by default, as it seems to violate the principle of least surprise.
Now that we have a proxy for the Tomcat Engine in the context, we can autowire it where it's needed -
@Autowired private Engine engine;
and getting the jvmRoute is as simple as
Thanks go out to Joachim Sauer on stackoverflow for pointing me in the right direction.