Change #ManagedResource objectName dynamically - java

I am creating prototype beans programatically/dynamically. I want those beans after initiation to be in the jmx console. How I can distinguish between them? I am using anotations in order to add my beans to the jmx and I have
#ManagedResource(objectName="bean:name=MybBean")
I need to inject the objectName dynamically. Any idea how could I do it?
Here's my jmx configuration:
<context:mbean-export server="mbeanServer" />
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"
lazy-init="false">
<property name="beans">
<map>
<entry key="Server:name=HttpAdaptor">
<bean class="mx4j.tools.adaptor.http.HttpAdaptor">
<property name="port" value="8000" />
<property name="host" value="0.0.0.0" />
<property name="processor">
<bean class="mx4j.tools.adaptor.http.XSLTProcessor" />
</property>
</bean>
</entry>
</map>
</property>
<property name="listeners">
<list>
<!--
-->
<bean class="com.fixgw.jmx.HttpAdaptorMgr">
<property name="mbeanServer" ref="mbeanServer" />
</bean>
</list>
</property>
</bean>
<bean id="sessionMDB" class="com.fixgw.mdb.SessionMDB"
scope="prototype" lazy-init="true">
<constructor-arg ref="0" />
<constructor-arg ref="0" />
</bean>

You can do this by just implementing org.springframework.jmx.export.naming.SelfNaming:
#Component("MyPrototypeScopedBeanName")
#ManagedResource
public class MyPrototypeScopedBeanName implements SelfNaming
{
#Override
public ObjectName getObjectName() throws MalformedObjectNameException {
return new ObjectName("com.foobar", "name", this.toString());
}
}

You can use a a JMX naming strategy to do this. At work we use an interface:
public interface RuntimeJmxNames {
/** this is the name= part of the object name */
public String getJmxName();
/** this sets the folders as 00=FirstFolder,01=Second */
public String[] getJmxPath();
}
I've posted the code to implement the RuntimeMetadataNamingStrategy naming strategy.
And then something like the following Spring beans:
<bean id="jmxAttributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
<bean id="jmxAssembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<bean id="jmxNamingStrategy" class="com.j256.jmx.RuntimeMetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="autodetect" value="true" />
<property name="assembler" ref="jmxAssembler" />
<property name="namingStrategy" ref="jmxNamingStrategy" />
<property name="ensureUniqueRuntimeObjectNames" value="false" />
<property name="excludedBeans" ref="excludedJmxBeans" />
</bean>
In your code you do something like:
#ManagedResource(objectName = "foo.com:name=replaced", description = "...")
public class Foo implements RuntimeJmxNames {
...
public String getJmxName() {
// here's where you can make the name be dynamic
return toString();
}
#Override
public String[] getJmxPath() {
return new String[] { "folder" };
}
}
Here's the Spring documentation on JMX naming although I'm not 100% sure it covers the custom naming stuff.
Also, my SimpleJMX package does a this as well. It uses a JmxSelfNaming interface which allows each instance of an object to define it's own bean-name to make them unique and works well with Spring.

Related

Cannot convert value of type [com.sun.proxy.$ProxyXX ScopedObject

I am getting this error when a bean of my project is initializated:
Could not convert constructor argument value of type [com.sun.proxy.$Proxy42] to required type [org.springframework.batch.item.file.MultiResourceItemReader]
This MultiResourceItemReader is a property of a FlatFileItemReader. In other spring batch jobs I have it the same without problems, but I can't localize the cause of the proxy conversion here. This is the bean definition of the linemapper.:
<bean id="updateStateBlocksReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="strict" value="false" />
<property name="recordSeparatorPolicy" ref="skipBlankLinesPolicy" />
<property name="comments">
<array value-type="java.lang.String">
<value>HEADER</value>
<value>FOOTER</value>
</array>
</property>
<property name="lineMapper">
<bean class="com.telefonica.gest.jt.nuc.myjob.reader.MyCustomLineMapper">
<constructor-arg ref="updateStateBlocksMultiReader" /> *****----> Error line
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value=";" />
<property name="names" value="field1,field2" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" ref="readerDTO" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- This is the MultiResourceItemReader used as argument in the constructor of the lineMapper (To extract the current fileName) -->
<bean id="updateStateBlocksMultiReader" class="org.springframework.batch.item.file.MultiResourceItemReader" scope="step">
<property name="resources" value="file:#{jobExecutionContext['PATH_IN']}/#{jobExecutionContext['FILENAME_IN']}"/>
<property name="delegate" ref="updateStateBlocksReader"/>
</bean>
I tried adding a StepScope bean with a proxyTargetClass property setted to "true" but not works. Finally I leave here the java of "MyCustomLineMapper.java" so you can see the constructor:
public class MyCustomLineMapper<T> implements LineMapper<BaseDTO>, InitializingBean {
private LineTokenizer tokenizer;
private BeanWrapperFieldSetMapper<BaseDTO> fieldSetMapper;
private MultiResourceItemReader<T> delegator;
public MyCustomLineMapper(final MultiResourceItemReader<T> delegator) {
this.delegator = delegator;
}
public BaseDTO mapLine(final String line, final int lineNumber) throws Exception {
...
I am tried moving the bean scopes and config the proxyTargetclass property without effect. Not sure how continue with this. Sorry my bad english and Thanks.

Spring MVC 3.2.8: Create a new FileSystemXmlApplicationContext and loading the definitions from the given XML files

I have an Spring MVC 3.2.8 app, and I want to run StandAlone process to generate a PDF. I want to initialize the container and manage beans from an stand-alone app.
I have this piece of code:
public class CreatePDF {
private static final Logger LOGGER = Logger.getLogger (ImportEcolabelToolboxToECAT.class);
public static void main(String[] args) {
String[] configLocations = new String[] {
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/dao/dataAccessContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/dao/databaseMessageSource.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/services/impl/servicesContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/applicationContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/controller/propertyeditors/propertyeditorsContext.xml"};
FileSystemXmlApplicationContext ctx =
new FileSystemXmlApplicationContext(configLocations, true);
}
}
But I have this error when running the app.
Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
and here the definition from the file dataAccessContext.xml :
<!-- The PropertyPlaceholderConfigurer replaces placeholders in Spring bean definitions with the values from the chosen properties files. -->
<!-- There is an example use in the datasource definition below. Look for the $\{jdbc.*} values. -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/nicinc/dao/jdbc-test.properties</value>
<value>classpath:com/nicinc/dao/dbMessageSource.properties</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="generateDdl" value="false"/>
<property name="showSql" value="false" />
</bean>
</property>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
The javax.naming package comprises the JNDI Api. Since it is just an API its implementation you will have to provide. Generally the implementation is provided by App server. As per the error you are Missing the JNDI implementation.
Possible solution:
If you dont have any javaee related requirement then you should directly use DriverManagerDataSource.
You need to provide your own implementation.Below link might help.
using application data source locally.

SPRING MVC - IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required

I have this maven project with its modules
Parent
|_____Model
|_____Persistence
|_ persistence-context.xml
|_____Service
|_ service-context.xml
|_____View
|_ spring/app-config.xml
And in persistence-context.xml have the next:
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName">
<tx:annotation-driven transaction-manager="persistence.transactionManager" proxy-target-class="true" />
<bean id="persistence.propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/jdbc.properties</value>
<value>classpath*:META-INF/hibernate.properties</value>
</list>
</property>
</bean>
<bean id="persistence.transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="jdbcExceptionTranslator" ref="persistence.jdbcExceptionTranslator" />
</bean>
<bean name="persistence.jdbcExceptionTranslator" class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
<constructor-arg>
<ref bean="persistence.dataSource" />
</constructor-arg>
</bean>
<bean id="persistence.dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.db.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="defaultAutoCommit" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<property name="maxIdle" value="25" />
</bean>
<bean id="persistence.sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="persistence.dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>
</props>
</property>
<property name="mappingLocations">
<list>
<value>classpath:mappings/items/servicio.hbm.xml</value>
<value>classpath:mappings/items/stockable.hbm.xml</value>
<value>classpath:mappings/items/bigstockable.hbm.xml</value>
</list>
</property>
</bean>
<!-- Daos beans -->
<bean id="servicioDao" class="daos.ServicioDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
<bean id="stockableDao" class="daos.StockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
<bean id="bigStockableDao" class="daos.BigStockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
In that xml i make my daos with it sessionFactory, but when i startup the project i got java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required, because my hibernateTemplate is null.
My daos extends from HibernateDaoSupport and i know that if you give to your dao a sessionFactory it will create automatically an hibernateTemplate, and idk what could be happening.
My daos have a #Repository (example #Repository(value="servicioDao"))
And the services the #Service with the #Autowired in the setter
and i am adding them in the contex
<context:component-scan base-package="controllers" />
<context:component-scan base-package="servicios" />
<context:component-scan base-package="daos" />
I just add this in the persistence-context.xml
<!-- Daos beans -->
<bean id="servicioDao" class="daos.ServicioDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="stockableDao" class="daos.StockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="bigStockableDao" class="daos.BigStockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
I get the same error.
Some of my daos code:
#Repository(value="servicioDao")
#SuppressWarnings("serial")
public class ServicioDao extends GenericHome<Servicio>{
public ServicioDao(){}
#Override
protected Class<Servicio> getDomainClass() {
return Servicio.class;
}
}
public abstract class GenericHome<T> extends HibernateDaoSupport implements Serializable{
protected Class<T> persistentClass = this.getDomainClass();
protected abstract Class<T> getDomainClass();
}
public class ServicioService {
private ServicioDao servicioDao;
public ServicioService(){}
public ServicioDao getServicioDao() {
return servicioDao;
}
#Autowired
public void setServicioDao(ServicioDao servicioDao) {
this.servicioDao = servicioDao;
}
}
I noticed that when i use #Service and #Repository, beans arent created by the xml, so when it gave me the error "'sessionFactory' or 'hibernateTemplate' is required" was because the dao was created but never filled its sessionFactory, so to use my xml files i created the controller like a normal bean
Try changing your bean definitions for this:
<bean id="servicioDao" class="daos.ServicioDao" >
<constructor-arg>
<ref bean="persistence.sessionFactory" />
</constructor-arg>
</bean>
It means that you are passing the sessionFactory in the constructor of your DAO class.
You also have to write the full pass in your "class" parameter.
<bean id="servicioDao" class="full.package.path.to.ServicioDao" >
Next, in your DAO class write something like this:
#Repository
public class ServicioDao{
private SessionFactory sessionFactory;
public ServicioDao() {
}
/**
* Constructor.
*
* #since 1.0
*/
public ServicioDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
...
}
Finally, in your controllers, you can use the DAO class as follows:
...
#Autowired
ServicioDao servicioDao;
...
servicioDao.getServicioDao();
Notice that you don't need to make new ServicioDao();.
Do it for every DAO class.

dynamically change Spring data source

I have a Spring application, i want to change the data source dynamically,ie. when input a DS URL, the Spring beans and all dependency will get updated automatically.I know this is somewhat strange, but anyway i want to achieve that.
My Spring configuration as following:
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.serverName}" />
<property name="portNumber" value="${jdbc.portNumber}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="databaseName" value="${jdbc.databaseName}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="majorDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="majorDataSource"/>
<property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>
The questions are:
The JDBC URL is stored in properties, which could be changed runtime.
Once the URL is changed, i need to re-create the data source and maybe the dependent objects. I could not figure out how to do it elegantly in Spring?
I have known that Spring did could dynamically route data source based on one key, but the data source URL is predefined in Spring and will not change runtime. It is not my case.
You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey() that should return the key referencing the datasource's spring bean to be used.
Take a look at this blog article on spring source's blog which will show you an example of how to use that feature.
Basically to answer your questions, what you will need to do is to define the two datasources as different spring bean in your XML config. There is no need to create one dynamically, spring will load both, and use one or the other dynamically depending on your criteria in the determineCurrentLookupKey() method.
This would lead to something like:
XML config
<!-- first data source -->
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.major.serverName}" />
<property name="portNumber" value="${jdbc.major.portNumber}" />
<property name="user" value="${jdbc.major.username}" />
<property name="password" value="${jdbc.major.password}" />
<property name="databaseName" value="${jdbc.major.databaseName}" />
</bean>
<!-- second data source -->
<bean id="minorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.minor.serverName}" />
<property name="portNumber" value="${jdbc.minor.portNumber}" />
<property name="user" value="${jdbc.minor.username}" />
<property name="password" value="${jdbc.minor.password}" />
<property name="databaseName" value="${jdbc.minor.databaseName}" />
</bean>
<!-- facade data source -->
<bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">
<property name="targetDataSources">
<map>
<entry key="MINOR" value-ref="minorDataSource"/>
<entry key="MAJOR" value-ref="majorDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="majorDataSource"/>
</bean>
<!-- wiring up -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>
Java
public class MyRoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
// get the current url
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
if (request.getRequestURL().toString().endsWith("/minor"))
return "MINOR";
else
return "MAJOR";
}
}
I am not sure if this is the correct Way of doing this but what you can do is something like this.
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="dummydata" />
<property name="portNumber" value="dummydata" />
<property name="user" value="dummydata" />
<property name="password" value="dummydata" />
<property name="databaseName" value="dummydata" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="majorDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
and in Java Class
public class TestTransaction {
#Autowired
private DataSourceTransactionManager manager;
private PlatformTransactionManager transactionManager;
public testExecution(DataSource ds) {
manager.setDataSource(ds);
transactionManager = manager;
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
jdbcTemplate.update();
transactionManager.commit(status);
} catch (Exception ex) {
transactionManager.rollback(status);
}
}
}
Please suggest if this Approach could Work as i am Still new to Spring

JMX MBean registration using Spring on a standalone JVM

Following various example configurations from Spring documentation as well as some forums on the Internet, my application context file looks like:
<beans>
<bean id="dH" class="abc.def.ghi.DH">
<constructor-arg>
<value>0</value>
</constructor-arg>
<property name="num" value="100"/>
</bean>
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=dH1" value-ref="dH"/>
</map>
</property>
</bean>
<bean class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
</beans>
I'm running this without any container and on plain JVM. I'm able to connect to my process via JConsole but the MBean doesn't show up. However registering the bean programmatically exposes it successfully.
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
DH dh = new DH(0);
mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1"));
I've tried playing with the Spring configuration without success. I think the bean is not registering to the already running MBean server that was accessible from ManagementFactory.getPlatformMBeanServer().
Any ideas on the issue?
In addition to defining an MBeanServerFactory bean (as Nicholas noted in their answer) using ...
<bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
... you need to tell the MBeanExporter what to manage:
If a bean implements one of the JMX management interfaces, MBeanExporter can simply register the MBean with the server through its autodetection process.
If a bean does not implement one of the JMX management interfaces, MBeanExporter will create the management information using the supplied MBeanInfoAssembler.
Assuming your abc.def.ghi.DH class does not implement any JMX interface, try defining your MBeanExporter as:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="assembler">
<bean
class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler"
>
<property name="managedMethods">
<list>
<value>getNum</value>
</list>
</property>
</bean>
</property>
<property name="beans">
<map>
<entry key="bean:name=dH1" value-ref="dH"/>
</map>
</property>
</bean>
Looking at the OpenJDK 7, update 2, build 21 DefaultMBeanServerInterceptor.java source, line 898 creates a DynamicMBean for regular objects:
DynamicMBean mbean = Introspector.makeDynamicMBean(object);
I haven't debugged it, but I bet mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1")) eventually calls DefaultMBeanServerInterceptor.registerObject(), which creates a DynamicMBean for you and properly registers your standard JavaBean properties' setters and getters.
Here are some test files that work using Spring Framework 3.0.5 and Oracle HotSpot Java 1.6.0_24. After setting your CLASSPATH environment variable, just run javac *.java and java Main and use VisualVM (or similar application) to connect to the running java application to see the registered MBeans.
ac.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true"
>
<bean id="test" class="Test" />
<bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="assembler">
<bean
class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler"
>
<property name="managedMethods">
<list>
<value>getVal</value>
<value>setVal</value>
</list>
</property>
</bean>
</property>
<property name="beans">
<map>
<entry key="bean:name=Test" value-ref="test"/>
</map>
</property>
</bean>
</beans>
Test.java:
public class Test {
private String val = "";
public String getVal() {
return val;
}
public void setVal(String v) {
val = v;
}
}
Main.java:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(final String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ac.xml");
try {
Thread.sleep(1000 * 60 * 5);
} catch (final Throwable t) {}
}
}
The issue is with the MBeanServerFactoryBean.
From the javadoc:
By default, MBeanServerFactoryBean will always create a new
MBeanServer even if one is already running. To have the
MBeanServerFactoryBean attempt to locate a running MBeanServer first,
set the value of the "locateExistingServerIfPossible" property to
"true".
Try this config:
<bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
=================================================
Try specifying the MBeanServer in the exporter bean:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=dH1" value-ref="dH" />
</map>
</property>
<property name="server" ref="MBeanServer" />
</bean>
<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
========================================================================
Ok, let's take the brute force approach and acquire the platform MBeanServer directly:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=dH1" value-ref="dH" />
</map>
</property>
<property name="server">
<bean id="MBeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer"/>
</property>
</bean>

Categories