I have a web application running on JBoss 4.2.2. In order to monitor performance I have enabled the internal platform JMX server that ships with Java 5. In other words, I added:
-Dcom.sun.management.jmxremote
to JBoss' launch script. This works as expected. However, as a result of this, all MBeans are now registered on the platform MBeanServer. I don't want that, I want them to be registered on JBoss' MBeanServer.
The difficulty lies in the fact that I use Spring to register my managed beans. For this, MBeanExporter is used. Thus, I need to tell my MBeanExporter to use JBoss' MBeanServer when registering beans. However, the only exposed method in MBeanExporter to affect what server is used is setServer(MBeanServer mBeanServer). The problem is that I only know how to get a reference to the correct MBeanServer programmatically, and not in Spring's XML, where the MBeanExporter is declared.
My options appears to be:
Write a subclass to MBeanExporter, overriding certain methods, so the correct MBeanServer is loaded
Write a PostBeanProcessor that finds JBoss' MBeanServer and then calls setServer
JNDI? Only works if the MBeanServer is exposed in JNDI, and I haven't been able to find it.
What is the most idiomatic way? Am I doing something really silly?
You can use the static factory method from the JBoss API to inject the MBeanServer into the MBeanExporter:
<bean class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
<bean class="org.jboss.mx.util.MBeanServerLocator" factory-method="locateJBoss"/>
</property>
<!-- Add the rest of your MBeanExporter properties here -->
</bean>
The problem is that I only know how to
get a reference to the correct
MBeanServer programmatically
If you can get the reference programmatically, why can't you wire it in through the MBeanExporter#server property?
Related
Is there a decent way to read a spring application context from xml without initializing the beans right away, so they can be mocked or not, before they are actually created?
Yes, I know about lazy-init, but the actual applicationContext.xml is taboo for me.
The situation is that I have to create some JUnit tests on an application which has been created in a way that puts some difficulties in the way:
the configuration file must not be altered, nor the code that is to be tested
there are a lot of beans, some of them rather complex and hard to mock
part of the test is to use as many of the beans un-mocked as possible
some of the beans implement InitializingBean, verifying the environment on initialization and throw errors when Jenkins tries to build.
new FileSystemXmlApplicationContext("config.xml") immediately initializes the beans and throws errors if not in an appropriate environment.
What I have tried:
I have tried Powermock whenNew to mock the offending beans but to do that I would have to know the class which actually creates the beans. As this class belongs to the spring framework, it may change with future versions. When using #PrepareEverythingForTest it results in an StackOverflow exception. The application is real life, not a small piece of code from some tutorial.
I also searched for something like ForceLazyFileSystemXmlApplicationContext but didn't find anything.
Pleas don't start nagging about bad design, I know about that.
You can write your own applicationContext for your testing purpose. There you need to write your own BeanFactory. In that factory you can replace some of beans with mocks.
I just remembered about an option. Evaluate if you can use spring profiles. It will allow to choose a different implementation based on profiles.
Example:
<!-- This is the default myBean -->
<beans>
<bean id="myBean" class="mypackage.MyBean" />
</beans>
<!-- This is the mocked myBean for testing purposes, it will take place when testingProfile is active -->
<beans profile="testingProfile">
<bean id="myBean" class="mypackage.MyBeanMock" />
</beans>
You can indicate which profile to use via properties or environment variables. Example, if you are using maven in your project you could run the tests as:
mvn test -Dspring.profiles.active="testingProfile"
Take a look at:
http://www.baeldung.com/spring-profiles
https://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
How to exclude beans, or packages from Spring AOP processing scope?
I encountered this, while fixing Spring Integration JMX support issue on JBoss.
As a development environment, we are using Spring 3.2.0.RELEASE, Spring Integration 2.2.0.RELEASE and Jboss AS 7.1.1.
When enabling Spring Integration JMX, you are actually creating IntegrationMBeanExporter, which extracts all Spring Integration related beans from the underlying ApplicationContext and creates appropriate managed MBeans. For assigning created MBeans to server MBeanServer required, which must be defined in ApplicationContext, which is generally done using standard MBeanServerFactoryBean, which returns platform related MBeanServer.
The problem appeared, because we were using Spring AOP for some enhanced operations, and AOP post processing mechanism was trying to process platform mbeanServer like regular bean, validating initial platform ClassLoader against internal pointcuts, which it eventually failed to do.
This seems to be similar to https://jira.springsource.org/browse/SPR-9335, but with generic specifics.
So as a solution, I prevented spring from processing mbeanServer as a part ApplicationContext :
<bean id="jmxIntegration" scope="singleton" class="org.springframework.integration.monitor.IntegrationMBeanExporter">
<property name="server" value="#{ T(org.springframework.jmx.support.JmxUtils).locateMBeanServer() }"/>
</bean>
This worked, but this seems to be of a more generic problem, with AOP.
Also interesting note is that MBeanExporter in spring also refers to JmxUtils instead of context's MBeanServer.
Is there any way to enable or disable a java bean definition in application context?
<bean id="enBean" classs="com.en.bean.BeanName">
<property name="prop1"/>
</bean>
Or, is there any way to load the bean conditionally defined in application context?
There is a new feature #Profile in spring 3.1 that would do the job
From here
Spring 3.1 introduces the concept of environment profiles. A common
use case is the setting up of beans that are different between
development, QA and production environments. A typical example is
going against a standalone DataSource in development versus looking up
the DataSource from JNDI in production. Another example is a beans
profile for profiling that can easily be turned on or off. You can add
a profile attribute on a beans element in XML or add #Profile
annotation in code. Note that a Spring bean can be assigned to
multiple profiles.
<beans profile="dev">
...
</beans>
#Profile("dev")
public class Bean {
...
}
These profiles can be activated through the spring.profiles.active
property which may be specified through an environment variable, a JVM
system property, a Servlet in web.xml or JNDI. These
profiles can also be activated through code using
Environment.setActiveProfiles(String ...). To make bean profiles work,
nested beans elements are now allowed in the Spring XML, although
constrained only at the end of the file. Note that it's recommended to
keep your bean topology as close as possible between environments, so
your application gets properly tested across environments. You also
use the Environment.containsProperty() method to search for properties
across the different property sources. This property resolution also
works for ${placeholder} variables in XML bean definitions.
I'm currently migrating a JBoss service class from AS5.1 to AS6 (not going to AS7 for a variety of reasons).
For AS5.1, the service implements a {serviceName}MBean and has a jboss-service.xml with attribute values. It's packaged in a jboss-sar, which is packaged in an EAR to be deployed. When deployed, the service fields are populated with the values from jboss-service.xml, and the service is automatically registered into JMX.
I would like to achieve the same thing using AS6, but would like the service to support CDI - so I'd like its new #Inject injection points to be satisfied. I need these to be satisfied in the object registered with JMX, so that methods called via JMX can reference injected fields, but I'm struggling to achieve this.
I've had to package the service in a jar, instead of a jboss-sar, for classloader reasons, but let's say it's otherwise unchanged. When deployed to AS6, all works as before - service goes into JMX, values from XML propagate to the object. However, the instance created does not have its CDI injection points satisfied, and neither does the object registered in JMX.
If I annotate the service class with #Startup and #javax.ejb.Singleton, but keep its interface and the jboss-service.xml, the object registered into JMX still does not have its CDI injection points satisfied. However if I programmattically deregister that bean, and re-register the instance in a #PostConstruct method, then the bean in JMX DOES have its injection points satisfied. However that bean no longer has the values specified in the jboss-service.xml.
So how can I get the best of both worlds? CDI and the usual JBoss service behaviour? What is the correct way to implement a JBoss service with CDI? I've been unable to find documentation on this. Hope someone can help.
Thanks,
Ben
As a worst-case fallback, you should be able to use the CDI extension API to get your service to be injected. I don't think you would need to write a fully-fledged extension, but if you have an initialisation hook in the service object, you can do this (lifted with minor editing from the docs, not compiled or tested):
public static <T> void inject(T object) {
BeanManager beanManager = (BeanManager)new InitialContext().lookup("java:comp/BeanManager");
AnnotatedType<T> type = beanManager.createAnnotatedType(object.getClass());
InjectionTarget<T> it = beanManager.createInjectionTarget(type);
CreationalContext ctx = beanManager.createCreationalContext(null);
it.inject(object, ctx);
it.postConstruct(object);
}
Basically, any object to that method will get injected. All the usual CDI annotations should work. Hopefully.
As mentioned in the comments above, it seems Tom's right - there's no 'nice' way of created a CDIed, JMX bean in one go, you either have to put your JMX bean in CDI, as is suggested above, or put you CDIed bean into JMX. We tried the former, but it appears the BeanManager isn't bound to JNDI at the point the service starts up.
So instead we went with CDI bean -> JMX. We're creating the services as Singleton EJBs, so their injection points are satisfied, and they then get registered/unregistered to JMX in their PostConstruct/PreDestroy methods, using German Escobar's excellent CDI portable extension (germanescobar.net/2010/01/cdi-portable-extension-jmx.html, community.jboss.org/thread/148750 is also helpful).
May try to use ApplicationScoped beans and get them to start by observing a ContainerInitialized(?) event, however, as we don't need all the features of an EJB. Haven't tried that yet, mind...
Is there a way that I can configure a WebBindingInitializer for a bean in Spring XML? I can configure the binder easily using the #InitBinder command, and then settings whatever state I want on it (typically this involves setting up a validator).
An example would be...
<bean id="fooController" class="com.foobar.controller.FooController">
<property name="binder" ref="globalBinder" />
<bean/>
Where the reference is too a WebBindingInitializer that has global properties.
Not sure if this exactly meets your needs, but you can create your own WebBindingInitializer that will allow you to externalize the initialization of the WebDataBinder used by your application. See the Spring Documenation for specifics on how you setup the configuation. This technique will allow you to reuse your databinding initialization code, rather than implement it in every Controller class.