- 浏览: 31471 次
- 性别:
- 来自: 广州
最新评论
-
meler:
有问题不理解:<value>rmi://serve ...
spring 远程接口访问及集群方案(三) -
djy1135:
东西实在是太多了
【转】Java开源项目(备查)
Here is an outline of the steps I took in order to use HASingletons in a clustered JBoss application. I hope it will be helpful to others who try to use HASingletons for the first time. The below is based on the approach explained by Ivelin Ivanov in the ONJava article found here: http://www.onjava.com/pub/a/onjava/2003/08/20/jboss_clustering.html. Additional information is provided in order to explain the steps necessary for accessing the HASingleton's operations from other classes.
Bear in mind that a JBoss HASingleton is not a true Singleton per se in that you won't get a reference to it and call methods on it like you would with a normal Singleton. Instead it is a JMX service (MBean) with managed operations that you invoke somewhat indirectly. Once I finally understood this the whole approach made a whole lot more sense to me.
The below is working for me using JBoss 3.2.6.
First you create the HASingleton MBean and configure it to be controlled by a HASingletonController.
1. Create an MBean which has lifecycle methods for use by JBoss for initialization and shutdown of the service. Name them whatever you like, I used the names startSingleton() and stopSingleton() as in Ivanov's example. Other methods which return values shoud return Objects instead of primitives, due to the mechanism used for invoking them, as we'll see later. Below is an simple example HASingleton MBean interface and class:
| // -------- ExampleMBean interface --------------------------------------------------
| package com.example.mbean;
|
| import org.jboss.system.ServiceMBean;
|
| public interface ExampleMBean
| extends ServiceMBean
| {
| //===================================================================================
| // Managed MBean operations which control the lifecycle of the HASingleton service
| //===================================================================================
|
| /**
| * Starts the service.
| */
| public void startSingleton ();
|
|
| /**
| * Stops the service.
| */
| public void stopSingleton ();
|
|
| //================================================================================
| // Managed MBean operations
| //================================================================================
|
| /**
| * Determine whether or not a user ID is present in the collection.
| *
| * @param userId the user ID to check
| * @return whether or not the specified user ID is present in the collection
| */
| public Boolean isUserIdPresent (String userId);
|
|
| /**
| * Add a user ID to the collection.
| *
| * @param userId the user ID to add to the collection
| */
| public void addUserId (String userId);
|
|
| /**
| * Remove a user ID from the collection.
| *
| * @param userId the user ID to remove from the collection
| */
| public void removeUserId (String userId);
| }
|
|
|
| // -------- Example MBean class ------------------------------------------------------
|
| package com.example.mbean;
|
| import java.util.Vector;
| import org.jboss.system.ServiceMBeanSupport;
|
|
| public class Example
| extends ServiceMBeanSupport
| implements ExampleMBean
| {
| // collection of user IDs
| private Vector m_userIds;
|
| //==================================================================================
| // Managed MBean operations which control the lifecycle of the HASingleton service
| //==================================================================================
|
| /**
| * Starts the service.
| */
| public void startSingleton ()
| {}
|
| /**
| * Stops the service.
| */
| public void stopSingleton ()
| {}
|
|
| /**
| * Constructor.
| */
| public Example ()
| {
| // create the collection of user IDs
| m_userIds = new Vector();
| }
|
|
| //================================================
| // Managed MBean operations
| //================================================
|
| /**
| * Determine whether or not a user ID is present in the collection.
| *
| * @param userId the user ID to check
| * @return whether or not the specified user ID is present in the collection
| */
| public Boolean isUserIdPresent (String userId)
| {
| return new Boolean(m_userIds.contains(userId));
| }
|
|
| /**
| * Add a user ID to the collection.
| *
| * @param userId the user ID to add to the collection
| */
| public void addUserId (String userId)
| {
| // add the user ID if not already present
| if (! m_userIds.contains(userId))
| {
| m_userIds.add(userId);
| }
| }
|
|
| /**
| * Remove a user ID from the collection.
| *
| * @param userId the user ID to remove from the collection
| */
| public void removeUserId (String userId)
| {
| // remove the user ID if it's present
| if (m_userIds.contains(userId))
| {
| m_userIds.remove(userId);
| }
| }
| }
|
2. In the SAR which contains the HASingleton MBean declare the MBean and an HASingletonController to control it. This is done in the META-INF/jboss-service.xml file of the SAR. For example the below is a jboss-service.xml for the above HASingleton MBean:
| <?xml version="1.0" encoding="UTF-8"?>
|
| <server>
|
| <!-- MBean to hold all user messages received from the queue -->
| <mbean code="com.example.mbean.Example"
| name="example.mbean:service=Example">
| </mbean>
|
| <!-- HASingletonController to run the above MBean as a HASingleton -->
| <mbean code="org.jboss.ha.singleton.HASingletonController"
| name="jboss.hasingleton:service=ExampleSingletonController">
| <depends>jboss:service=DefaultPartition</depends>
| <depends>example.mbean:service=Example</depends>
| <attribute name="TargetName">example.mbean:service=Example</attribute>
| <attribute name="TargetStartMethod">startSingleton</attribute>
| <attribute name="TargetStopMethod">stopSingleton</attribute>
| </mbean>
|
| </server>
|
3. Put the SAR with the HASingleton MBean classes into the JBOSS/server/all/deploy-hasingleton directory on every node of your cluster.
To be able to access the HASingleton you need to use a RMIAdaptor which also runs as a HASingleton. This HASingleton RMIAdaptor will locate your HASingletons and enable you to invoke their operations. Essentially it's running on the same node/JVM by virtue of it being an HASingleton itself, so it can "see" the other HASingletons. This is in contrast to the normal approach of using an MBeanServer, which may or may not be running on the same node/JVM as the HASingletons and hence may not be able to see them since they may not be registered.
1. Copy the jmx-invoker-adaptor-server.sar directory from JBOSS/server/all/deploy into JBOSS/server/all/deploydeploy-hasingleton.
2. Modify JBOSS/server/all/deploy-hasingleton/jmx-invoker-adaptor-server.sar/META-INF/jboss-service.xml:
a) rename the JRMPProxyFactory MBean as SingletonInvoker
b) change the JndiName for the JRMPProxyFactory MBean to jmx/invoker/SingletonRMIAdaptor
c) add a HASingletonController for the SingletonInvoker
d) remove the NamingAlias MBean for /jmx/rmi/RMIAdaptor
Below is the jboss-service.xml I am using:
| <?xml version="1.0" encoding="UTF-8"?>
|
| <!-- $Id: jboss-service.xml,v 1.1.2.10 2004/09/09 04:19:30 osdchicago Exp $ -->
| <server>
|
| <!-- The JRMP invoker proxy configuration for the InvokerAdaptorService -->
| <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory"
| name="jboss.jmx:type=adaptor,name=SingletonInvoker,protocol=jrmp,service=proxyFactory">
| <!-- Use the standard JRMPInvoker from conf/jboss-service.xxml -->
| <depends optional-attribute-name="InvokerName">jboss:service=invoker,type=jrmp</depends>
| <!-- The target MBean is the InvokerAdaptorService configured below -->
| <depends optional-attribute-name="TargetName">
| jboss.jmx:type=adaptor,name=SingletonInvoker
| </depends>
| <!-- Where to bind the RMIAdaptor proxy -->
| <attribute name="JndiName">jmx/invoker/SingletonRMIAdaptor</attribute>
| <!-- The RMI compabitle MBeanServer interface -->
| <attribute name="ExportedInterfaces">org.jboss.jmx.adaptor.rmi.RMIAdaptor,
| org.jboss.jmx.adaptor.rmi.RMIAdaptorExt
| </attribute>
| <attribute name="ClientInterceptors">
| <interceptors>
| <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
| <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
| <interceptor>
| org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor
| </interceptor>
| <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
| </interceptors>
| </attribute>
| </mbean>
|
|
| <!-- This is the service that handles the RMIAdaptor invocations by routing
| them to the MBeanServer the service is deployed under. -->
| <mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService"
| name="jboss.jmx:type=adaptor,name=SingletonInvoker"
| xmbean-dd="">
| <xmbean>
| <description>The JMX Detached Invoker Service</description>
| <class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>
|
| <!-- Attributes -->
| <attribute access="read-only"
| getMethod="getName">
| <description>The class name of the MBean</description>
| <name>Name</name>
| <type>java.lang.String</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getState">
| <description>The status of the MBean</description>
| <name>State</name>
| <type>int</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getStateString">
| <description>The status of the MBean in text form</description>
| <name>StateString</name>
| <type>java.lang.String</type>
| </attribute>
| <attribute access="read-write"
| getMethod="getExportedInterfaces"
| setMethod="setExportedInterfaces">
| <description>The interfaces the invoker proxy supports</description>
| <name>ExportedInterfaces</name>
| <type>[Ljava.lang.Class;</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getMethodMap">
| <description>Map(Long hash, Method) of the proxy interface methods</description>
| <name>MethodMap</name>
| <type>java.util.Map</type>
| </attribute>
| <!-- Operations -->
| <operation>
| <description>The start lifecycle operation</description>
| <name>start</name>
| </operation>
| <operation>
| <description>The stop lifecycle operation</description>
| <name>stop</name>
| </operation>
| <operation>
| <description>The detyped lifecycle operation (for internal use only)</description>
| <name>jbossInternalLifecycle</name>
| <parameter>
| <description>The lifecycle operation</description>
| <name>method</name>
| <type>java.lang.String</type>
| </parameter>
| <return-type>void</return-type>
| </operation>
|
| <operation>
| <description>The detached invoker entry point</description>
| <name>invoke</name>
| <parameter>
| <description>The method invocation context</description>
| <name>invocation</name>
| <type>org.jboss.invocation.Invocation</type>
| </parameter>
| <return-type>java.lang.Object</return-type>
| <!-- Uncomment to require authenticated users . Also an AuthorizationInterceptor
| is provided which whill help in authorizing users to make JMX calls at the
| MBean operations level. You will need to write a class that overrides a method
| with the signature
| "public Boolean authorize( Principal caller, Collection roles,String objectname
| ,String opname)"
| is needed to be defined in the attribute 'authorizingClass'
| <descriptors>
| <interceptors>
| <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor"
| securityDomain="java:/jaas/jmx-console"/>
| <interceptor code="org.jboss.jmx.connector.invoker.AuthorizationInterceptor"
| authorizingClass="CustomAuthorizationClass"
| securityDomain="java:/jaas/jmx-console"/>
| </interceptors>
| </descriptors>
| -->
| </operation>
| </xmbean>
| <attribute name="ExportedInterfaces">
| org.jboss.jmx.adaptor.rmi.RMIAdaptor,
| org.jboss.jmx.adaptor.rmi.RMIAdaptorExt
| </attribute>
| </mbean>
|
|
| <!-- HASingletonController to run the InvokerAdaptorService MBean as a HASingleton -->
| <mbean code="org.jboss.ha.singleton.HASingletonController"
| name="jboss.hasingleton:service=RMIAdaptorSingletonController">
| <depends>jboss:service=DefaultPartition</depends>
| <depends>jboss.jmx:type=adaptor,name=SingletonInvoker</depends>
| <attribute name="TargetName">jboss.jmx:type=adaptor,name=SingletonInvoker</attribute>
| <attribute name="TargetStartMethod">start</attribute>
| <attribute name="TargetStopMethod">stop</attribute>
| </mbean>
|
| </server>
|
Now to access the HASingleton in client code (EJBS, Servlets, other MBeans, etc.) I use the following approach:
1. Lookup the HASingleton RMIApdaptor
2. Make sure that the HASingleton I want to use is registered
3. Invoke the operation and cast the returned object, if any, to the expected class (RMIAdaptor.invoke() returns an object, which is why all of our MBean operations must return Objects and not primitives)
For example:
| String userId = "elvis";
| try
| {
| // create a HashTable of environment properties for the InitialContext
| //
| // NOTE -- These are hard-coded since the using jndi.properties with a URL containing
| // the HA-JNDI port causes the NamingService to fail on start up; hopefully this
| // issue can be resolved and these properties can again be set in jndi.properties.
| Hashtable jndiProperties = new Hashtable();
| jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
| "org.jnp.interfaces.NamingContextFactory");
| // use the port specified in the HANamingService entry (currently set in cluster-service.xml)
| jndiProperties.put(Context.PROVIDER_URL, "localhost:11100");
| jndiProperties.put("java.naming.factory.url.pkgs",
| "org.jboss.naming:org.jnp.interfaces");
|
| // get the InitialContext and lookup the SingletonRMIAdaptor
| Context context = new InitialContext(jndiProperties);
| RMIAdaptor rmiAdaptor = (RMIAdaptor) context.lookup("jmx/invoker/SingletonRMIAdaptor");
|
| // if we have an RMIAdaptor and the Example MBean is registered with it then we can invoke operations
| if ((rmiAdaptor != null) && (rmiAdaptor.isRegistered(new ObjectName("example.mbean:service=Example"))))
| {
| // add the message to the list for this user ID
| Boolean isUserIdPresent = rmiAdaptor.invoke(new ObjectName("example.mbean:service=Example"),
| "isUserIdPresent",
| new Object[]{userId},
| new String[]{"java.lang.String"});
|
| // show our result
| if (isUserIdPresent.booleanValue())
| {
| System.out.println("User ID " + userId + " is in the collection");
| }
| else
| {
| System.out.println("User ID " + userId + " is not in the collection");
| }
| }
| else
| {
| // log the error
| m_logger.error("Unable to find an RMIAdaptor with a registered Example HASingleton MBean");
|
| // throw an exception
| throw new Exception("Unable to find an RMIAdaptor with a registered Example HASingleton MBean");
| }
| }
| catch (MBeanException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (ReflectionException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (InstanceNotFoundException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (MalformedObjectNameException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (NamingException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (RemoteException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
|
The above approach works well for me except in the case when the master node of the cluster goes down and the HASingletons are restarted on the new master node of the cluster. The state of the HASingletons is lost since they are started fresh. For example in the above example if the master node running the HASingleton goes down then the collection of user IDs will be lost. For this reason I would not recommend using HASingletons if you need to maintain state, I have learned this lesson the hard way. My understanding at this point is that a stateful Singleton is not a good idea and instead an Entity Bean should be used. If anyone can suggest a solution to this problem, other than rewriting everything using Entity Beans (which, I fear, might in fact be the only solution) then I'd certainly appreciate it. You can post suggestions in the following thread:http://www.jboss.org/index.html?module=bb&op=viewtopic&t=55787
I hope the above is helpful.
Bear in mind that a JBoss HASingleton is not a true Singleton per se in that you won't get a reference to it and call methods on it like you would with a normal Singleton. Instead it is a JMX service (MBean) with managed operations that you invoke somewhat indirectly. Once I finally understood this the whole approach made a whole lot more sense to me.
The below is working for me using JBoss 3.2.6.
First you create the HASingleton MBean and configure it to be controlled by a HASingletonController.
1. Create an MBean which has lifecycle methods for use by JBoss for initialization and shutdown of the service. Name them whatever you like, I used the names startSingleton() and stopSingleton() as in Ivanov's example. Other methods which return values shoud return Objects instead of primitives, due to the mechanism used for invoking them, as we'll see later. Below is an simple example HASingleton MBean interface and class:
| // -------- ExampleMBean interface --------------------------------------------------
| package com.example.mbean;
|
| import org.jboss.system.ServiceMBean;
|
| public interface ExampleMBean
| extends ServiceMBean
| {
| //===================================================================================
| // Managed MBean operations which control the lifecycle of the HASingleton service
| //===================================================================================
|
| /**
| * Starts the service.
| */
| public void startSingleton ();
|
|
| /**
| * Stops the service.
| */
| public void stopSingleton ();
|
|
| //================================================================================
| // Managed MBean operations
| //================================================================================
|
| /**
| * Determine whether or not a user ID is present in the collection.
| *
| * @param userId the user ID to check
| * @return whether or not the specified user ID is present in the collection
| */
| public Boolean isUserIdPresent (String userId);
|
|
| /**
| * Add a user ID to the collection.
| *
| * @param userId the user ID to add to the collection
| */
| public void addUserId (String userId);
|
|
| /**
| * Remove a user ID from the collection.
| *
| * @param userId the user ID to remove from the collection
| */
| public void removeUserId (String userId);
| }
|
|
|
| // -------- Example MBean class ------------------------------------------------------
|
| package com.example.mbean;
|
| import java.util.Vector;
| import org.jboss.system.ServiceMBeanSupport;
|
|
| public class Example
| extends ServiceMBeanSupport
| implements ExampleMBean
| {
| // collection of user IDs
| private Vector m_userIds;
|
| //==================================================================================
| // Managed MBean operations which control the lifecycle of the HASingleton service
| //==================================================================================
|
| /**
| * Starts the service.
| */
| public void startSingleton ()
| {}
|
| /**
| * Stops the service.
| */
| public void stopSingleton ()
| {}
|
|
| /**
| * Constructor.
| */
| public Example ()
| {
| // create the collection of user IDs
| m_userIds = new Vector();
| }
|
|
| //================================================
| // Managed MBean operations
| //================================================
|
| /**
| * Determine whether or not a user ID is present in the collection.
| *
| * @param userId the user ID to check
| * @return whether or not the specified user ID is present in the collection
| */
| public Boolean isUserIdPresent (String userId)
| {
| return new Boolean(m_userIds.contains(userId));
| }
|
|
| /**
| * Add a user ID to the collection.
| *
| * @param userId the user ID to add to the collection
| */
| public void addUserId (String userId)
| {
| // add the user ID if not already present
| if (! m_userIds.contains(userId))
| {
| m_userIds.add(userId);
| }
| }
|
|
| /**
| * Remove a user ID from the collection.
| *
| * @param userId the user ID to remove from the collection
| */
| public void removeUserId (String userId)
| {
| // remove the user ID if it's present
| if (m_userIds.contains(userId))
| {
| m_userIds.remove(userId);
| }
| }
| }
|
2. In the SAR which contains the HASingleton MBean declare the MBean and an HASingletonController to control it. This is done in the META-INF/jboss-service.xml file of the SAR. For example the below is a jboss-service.xml for the above HASingleton MBean:
| <?xml version="1.0" encoding="UTF-8"?>
|
| <server>
|
| <!-- MBean to hold all user messages received from the queue -->
| <mbean code="com.example.mbean.Example"
| name="example.mbean:service=Example">
| </mbean>
|
| <!-- HASingletonController to run the above MBean as a HASingleton -->
| <mbean code="org.jboss.ha.singleton.HASingletonController"
| name="jboss.hasingleton:service=ExampleSingletonController">
| <depends>jboss:service=DefaultPartition</depends>
| <depends>example.mbean:service=Example</depends>
| <attribute name="TargetName">example.mbean:service=Example</attribute>
| <attribute name="TargetStartMethod">startSingleton</attribute>
| <attribute name="TargetStopMethod">stopSingleton</attribute>
| </mbean>
|
| </server>
|
3. Put the SAR with the HASingleton MBean classes into the JBOSS/server/all/deploy-hasingleton directory on every node of your cluster.
To be able to access the HASingleton you need to use a RMIAdaptor which also runs as a HASingleton. This HASingleton RMIAdaptor will locate your HASingletons and enable you to invoke their operations. Essentially it's running on the same node/JVM by virtue of it being an HASingleton itself, so it can "see" the other HASingletons. This is in contrast to the normal approach of using an MBeanServer, which may or may not be running on the same node/JVM as the HASingletons and hence may not be able to see them since they may not be registered.
1. Copy the jmx-invoker-adaptor-server.sar directory from JBOSS/server/all/deploy into JBOSS/server/all/deploydeploy-hasingleton.
2. Modify JBOSS/server/all/deploy-hasingleton/jmx-invoker-adaptor-server.sar/META-INF/jboss-service.xml:
a) rename the JRMPProxyFactory MBean as SingletonInvoker
b) change the JndiName for the JRMPProxyFactory MBean to jmx/invoker/SingletonRMIAdaptor
c) add a HASingletonController for the SingletonInvoker
d) remove the NamingAlias MBean for /jmx/rmi/RMIAdaptor
Below is the jboss-service.xml I am using:
| <?xml version="1.0" encoding="UTF-8"?>
|
| <!-- $Id: jboss-service.xml,v 1.1.2.10 2004/09/09 04:19:30 osdchicago Exp $ -->
| <server>
|
| <!-- The JRMP invoker proxy configuration for the InvokerAdaptorService -->
| <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory"
| name="jboss.jmx:type=adaptor,name=SingletonInvoker,protocol=jrmp,service=proxyFactory">
| <!-- Use the standard JRMPInvoker from conf/jboss-service.xxml -->
| <depends optional-attribute-name="InvokerName">jboss:service=invoker,type=jrmp</depends>
| <!-- The target MBean is the InvokerAdaptorService configured below -->
| <depends optional-attribute-name="TargetName">
| jboss.jmx:type=adaptor,name=SingletonInvoker
| </depends>
| <!-- Where to bind the RMIAdaptor proxy -->
| <attribute name="JndiName">jmx/invoker/SingletonRMIAdaptor</attribute>
| <!-- The RMI compabitle MBeanServer interface -->
| <attribute name="ExportedInterfaces">org.jboss.jmx.adaptor.rmi.RMIAdaptor,
| org.jboss.jmx.adaptor.rmi.RMIAdaptorExt
| </attribute>
| <attribute name="ClientInterceptors">
| <interceptors>
| <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
| <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
| <interceptor>
| org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor
| </interceptor>
| <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
| </interceptors>
| </attribute>
| </mbean>
|
|
| <!-- This is the service that handles the RMIAdaptor invocations by routing
| them to the MBeanServer the service is deployed under. -->
| <mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService"
| name="jboss.jmx:type=adaptor,name=SingletonInvoker"
| xmbean-dd="">
| <xmbean>
| <description>The JMX Detached Invoker Service</description>
| <class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>
|
| <!-- Attributes -->
| <attribute access="read-only"
| getMethod="getName">
| <description>The class name of the MBean</description>
| <name>Name</name>
| <type>java.lang.String</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getState">
| <description>The status of the MBean</description>
| <name>State</name>
| <type>int</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getStateString">
| <description>The status of the MBean in text form</description>
| <name>StateString</name>
| <type>java.lang.String</type>
| </attribute>
| <attribute access="read-write"
| getMethod="getExportedInterfaces"
| setMethod="setExportedInterfaces">
| <description>The interfaces the invoker proxy supports</description>
| <name>ExportedInterfaces</name>
| <type>[Ljava.lang.Class;</type>
| </attribute>
| <attribute access="read-only"
| getMethod="getMethodMap">
| <description>Map(Long hash, Method) of the proxy interface methods</description>
| <name>MethodMap</name>
| <type>java.util.Map</type>
| </attribute>
| <!-- Operations -->
| <operation>
| <description>The start lifecycle operation</description>
| <name>start</name>
| </operation>
| <operation>
| <description>The stop lifecycle operation</description>
| <name>stop</name>
| </operation>
| <operation>
| <description>The detyped lifecycle operation (for internal use only)</description>
| <name>jbossInternalLifecycle</name>
| <parameter>
| <description>The lifecycle operation</description>
| <name>method</name>
| <type>java.lang.String</type>
| </parameter>
| <return-type>void</return-type>
| </operation>
|
| <operation>
| <description>The detached invoker entry point</description>
| <name>invoke</name>
| <parameter>
| <description>The method invocation context</description>
| <name>invocation</name>
| <type>org.jboss.invocation.Invocation</type>
| </parameter>
| <return-type>java.lang.Object</return-type>
| <!-- Uncomment to require authenticated users . Also an AuthorizationInterceptor
| is provided which whill help in authorizing users to make JMX calls at the
| MBean operations level. You will need to write a class that overrides a method
| with the signature
| "public Boolean authorize( Principal caller, Collection roles,String objectname
| ,String opname)"
| is needed to be defined in the attribute 'authorizingClass'
| <descriptors>
| <interceptors>
| <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor"
| securityDomain="java:/jaas/jmx-console"/>
| <interceptor code="org.jboss.jmx.connector.invoker.AuthorizationInterceptor"
| authorizingClass="CustomAuthorizationClass"
| securityDomain="java:/jaas/jmx-console"/>
| </interceptors>
| </descriptors>
| -->
| </operation>
| </xmbean>
| <attribute name="ExportedInterfaces">
| org.jboss.jmx.adaptor.rmi.RMIAdaptor,
| org.jboss.jmx.adaptor.rmi.RMIAdaptorExt
| </attribute>
| </mbean>
|
|
| <!-- HASingletonController to run the InvokerAdaptorService MBean as a HASingleton -->
| <mbean code="org.jboss.ha.singleton.HASingletonController"
| name="jboss.hasingleton:service=RMIAdaptorSingletonController">
| <depends>jboss:service=DefaultPartition</depends>
| <depends>jboss.jmx:type=adaptor,name=SingletonInvoker</depends>
| <attribute name="TargetName">jboss.jmx:type=adaptor,name=SingletonInvoker</attribute>
| <attribute name="TargetStartMethod">start</attribute>
| <attribute name="TargetStopMethod">stop</attribute>
| </mbean>
|
| </server>
|
Now to access the HASingleton in client code (EJBS, Servlets, other MBeans, etc.) I use the following approach:
1. Lookup the HASingleton RMIApdaptor
2. Make sure that the HASingleton I want to use is registered
3. Invoke the operation and cast the returned object, if any, to the expected class (RMIAdaptor.invoke() returns an object, which is why all of our MBean operations must return Objects and not primitives)
For example:
| String userId = "elvis";
| try
| {
| // create a HashTable of environment properties for the InitialContext
| //
| // NOTE -- These are hard-coded since the using jndi.properties with a URL containing
| // the HA-JNDI port causes the NamingService to fail on start up; hopefully this
| // issue can be resolved and these properties can again be set in jndi.properties.
| Hashtable jndiProperties = new Hashtable();
| jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
| "org.jnp.interfaces.NamingContextFactory");
| // use the port specified in the HANamingService entry (currently set in cluster-service.xml)
| jndiProperties.put(Context.PROVIDER_URL, "localhost:11100");
| jndiProperties.put("java.naming.factory.url.pkgs",
| "org.jboss.naming:org.jnp.interfaces");
|
| // get the InitialContext and lookup the SingletonRMIAdaptor
| Context context = new InitialContext(jndiProperties);
| RMIAdaptor rmiAdaptor = (RMIAdaptor) context.lookup("jmx/invoker/SingletonRMIAdaptor");
|
| // if we have an RMIAdaptor and the Example MBean is registered with it then we can invoke operations
| if ((rmiAdaptor != null) && (rmiAdaptor.isRegistered(new ObjectName("example.mbean:service=Example"))))
| {
| // add the message to the list for this user ID
| Boolean isUserIdPresent = rmiAdaptor.invoke(new ObjectName("example.mbean:service=Example"),
| "isUserIdPresent",
| new Object[]{userId},
| new String[]{"java.lang.String"});
|
| // show our result
| if (isUserIdPresent.booleanValue())
| {
| System.out.println("User ID " + userId + " is in the collection");
| }
| else
| {
| System.out.println("User ID " + userId + " is not in the collection");
| }
| }
| else
| {
| // log the error
| m_logger.error("Unable to find an RMIAdaptor with a registered Example HASingleton MBean");
|
| // throw an exception
| throw new Exception("Unable to find an RMIAdaptor with a registered Example HASingleton MBean");
| }
| }
| catch (MBeanException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (ReflectionException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (InstanceNotFoundException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (MalformedObjectNameException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (NamingException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
| catch (RemoteException e)
| {
| // log the error
| m_logger.error("Unable to invoke the Example.isUserIdPresent() method", e);
|
| // throw an exception
| throw new Exception("Unable to invoke the Example.isUserIdPresent() method", e);
| }
|
The above approach works well for me except in the case when the master node of the cluster goes down and the HASingletons are restarted on the new master node of the cluster. The state of the HASingletons is lost since they are started fresh. For example in the above example if the master node running the HASingleton goes down then the collection of user IDs will be lost. For this reason I would not recommend using HASingletons if you need to maintain state, I have learned this lesson the hard way. My understanding at this point is that a stateful Singleton is not a good idea and instead an Entity Bean should be used. If anyone can suggest a solution to this problem, other than rewriting everything using Entity Beans (which, I fear, might in fact be the only solution) then I'd certainly appreciate it. You can post suggestions in the following thread:http://www.jboss.org/index.html?module=bb&op=viewtopic&t=55787
I hope the above is helpful.
发表评论
-
C#客户端调用Axis2 Java webservice int参数传值问题
2012-08-16 09:40 1654现象: 采用C# webservice studio工具调试a ... -
Linux下JfreeChart中文乱码问题解决
2012-07-17 15:28 924JFreeChart和中文验证码的乱码问题和jsp的编码无关, ... -
spring 注解式事务管理
2010-08-16 13:46 1108最近在开发一项目时使用了spring注解式事务管理,现介绍如下 ... -
spring 事务管理
2010-08-16 13:43 828Spring配置文件中关于事务配置总是由三个组成部分,分别是D ... -
[转]关于spring声明式事务管理异常处理的测试和小结(二)
2010-08-16 13:37 1007测试情形二: web层捕获异常并处理,Service捕获异常 ... -
[转]关于spring声明式事务管理异常处理的测试和小结一
2010-08-16 13:36 1070关于spring事务管理以及异常处理的帖子,本论坛争论颇多,各 ... -
JBOSS 端口修改说明
2010-07-30 16:32 13421.jboss 的端口修改位置总结 Jboss通常占用的端口 ... -
jboss4.0.4 GA+EJB环境部署
2010-07-29 16:44 10941,开发环境 jbossIDE myclipse ... -
EJB3.0与JBOSS4.0.4GA集群部署实战(二)
2010-07-09 14:41 1021环境 MyEclipse5.5 JBoss4.0.4 测试 ... -
EJB3.0与JBOSS4.0.4GA集群部署实战(一)
2010-07-09 14:34 1203EJB中的三种bean 会话bean(session bea ... -
spring 远程接口访问及集群方案(三)
2010-07-09 14:03 3607前两篇文章已经对spring rmi方式的远程接口调用进行了说 ... -
spring 远程接口访问及集群方案(二)
2010-07-09 11:02 1617针对spring远程接口访问,本文给出一个实际的例子供参考,如 ... -
spring 远程接口访问及集群方案(一)
2010-07-09 10:46 1921Spring提供类用于集成各种远程访问技术。这种对远程访问的支 ... -
Java应用从集中式步入分布式
2010-07-07 14:02 673记得Martin大叔在《企业 ...
相关推荐
**JBOSS 4.2.2GA 使用指南** JBOSS是一款开源的企业级Java应用服务器,基于Java 2企业版(J2EE)规范。JBOSS 4.2.2GA是其一个特定的稳定版本,发布于2007年,提供了一个全面的平台来部署和管理各种Java应用程序和...
**JBoss 4.2.2 GA 中文文档详解** JBoss 4.2.2 GA 是一个基于Java的企业级应用服务器,它提供了全面的中间件服务,支持Java EE(Enterprise Edition)规范,包括EJB(Enterprise JavaBeans)、JMS(Java Message ...
jboss4.2.2.GA java开发的好帮手
**EJB 3.0 和 JBoss 4.2.2 GA 集群详解** EJB(Enterprise JavaBeans)3.0 是Java EE(Java Platform, Enterprise Edition)中的一个核心组件,它提供了用于构建可扩展、分布式和事务处理的企业级应用程序的框架。...
"Jboss4.2.2+Spring2.5.6+Hibernate+JTA事务的实现"就是一个典型的例子,它涉及到四个关键的技术栈,即JBoss Application Server 4.2.2、Spring 2.5.6、Hibernate ORM以及Java Transaction API(JTA)。这些技术的...
JBoss 4.2.2.GA是该平台的一个稳定版本,发布于2007年,包含了对Java EE 5的支持。 **一、JBoss 4.2.2.GA核心特性** 1. **Java EE 5兼容性**:JBoss 4.2.2.GA支持Java Platform, Enterprise Edition 5(Java EE 5...
【JBoss4.2.3GA + EJB3.0 + JAAS】是企业级Java应用服务器、EJB(Enterprise JavaBeans)版本和安全性框架JAAS(Java Authentication and Authorization Service)的一个经典组合。这个组合在Java开发领域具有重要的...
- 从JBoss官方网站或者镜像站点下载JBoss AS 4.2.2 GA的zip文件。 - 解压缩文件,将解压后的目录移动到你希望存放的位置,如`/Users/your_username/Documents/JBoss`. - 在终端中,通过cd命令进入JBoss目录,启动...
**JBoss 4.2.2 GA英文文档详解** JBoss AS(Application Server)是Red Hat公司开发的一个开源Java EE应用服务器,版本4.2.2 GA是它的一个重要里程碑。这个版本提供了全面的支持,包括对Java Enterprise Edition 5...
共5个压缩包,全部下载才能够解压 jboss jboss4.2 jboss4.2.2 jboss-4.2.2 jboss-4.2.2.GA
共5个压缩包,全部下载才能够解压 jboss jboss4.2 jboss4.2.2 jboss-4.2.2 jboss-4.2.2.GA............
经典Java EE企业应用实战:基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 part3
在本文中,我们将深入探讨如何在JBoss 4.2.2.GA版本中修改默认的端口设置,这是一个常见的需求,尤其是在端口被其他服务占用时。 ### JBoss 4.2.2.GA端口路径与配置 JBoss 4.2.2.GA版本在运行时,默认监听在8080...
经典JAVA EE企业应用实战 基于WEBLOGIC JBOSS的JSF+EJB 3+JPA整合开发.part2
jboss 4.2.2.GA part2,办公区上不了官网,只能先传到这里了。和我一样杯具的码农可以下了使用。
经典JAVA EE企业应用实战基于WEBLOGIC JBOSS的JSF+EJB 3+JPA整合开发——源码.part1 其他部分详见我的上传列表,全部分卷下载完成才能解压。 本书介绍了Java EE规范的三大主要规范JSF、EJB 3和JPA,其中JSF是Sun...