详解JBOSS系列一(利用JNDI,EJB远程调用本地的Bean)

来源:互联网 发布:软件运营方案 编辑:程序博客网 时间:2024/05/16 15:16

 

 1.前言

最近在公司里面做项目,用的是SpringMVC+EJB+JBOSS+Jpa。在整个框架中,唯一难于理解的是JBOSS的相关配置,尤其是JBOSS从5以后,在版本上做了一个很大的改变,例如加入了一些安全认证,域模式等,于是想写几篇博客来学习一下JBOSS6的有关应用。整个过程用的的JBOSS EAP6.2的版本。本篇博客就先从一个例子来讲一下,有关通过JBOSS,远程调用EJB本地Bean。所有的知识内容翻译自官网。JBOSS官网

   

 2.从一个Demo讲起

先通过一个Demo,运行起来看一下效果,后面再来详细的解释一下,整个Demo中的配置。


2.1 建立远程Bean(限于篇幅限制,只把Bean的实现放在这里,接口就不在放置了

有状态远程CounterBean

<span style="font-family:SimSun;font-size:18px;">package com.tgb;import javax.ejb.Remote;import javax.ejb.Stateful;/** * @author LUCKY */@Stateful@Remote(RemoteCounter.class)public class CounterBean implements RemoteCounter {    private int count = 0;    @Override    public void increment() {        this.count++;    }    @Override    public void decrement() {        this.count--;    }    @Override    public int getCount() {        return this.count;    }}</span>

无状态远程CalculatorBean

<span style="font-family:SimSun;font-size:18px;">package com.tgb;import javax.ejb.Remote;import javax.ejb.Stateless;/** * @author LUCKY */@Stateless@Remote(RemoteCalculator.class)public class CalculatorBean implements RemoteCalculator {    @Override    public int add(int a, int b) {        return a + b;    }    @Override    public int subtract(int a, int b) {        return a - b;    }}</span>

2.2 部署远程服务端

把上面的远程的Bean,打成jar包,放置到jboss中,命名为ejb-service,并且启动jboss,出现下面,即为成功部署。另外JBOSS6.2的部署目录结构为JBOSS_HOME\standalone\deployments



 2.3 客户端远程调用

废话不多说了,直接上Demo吧

package main;import java.util.Hashtable;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import com.tgb.RemoteCalculator;import com.tgb.RemoteCounter;/** * A sample program which acts a remote client for a EJB deployed on AS7 server. This program shows how to lookup stateful and * stateless beans via JNDI and then invoke on them */public class RemoteEJBClient {    public static void main(String[] args) throws Exception {        // Invoke a stateless bean        invokeStatelessBean();        // Invoke a stateful bean        invokeStatefulBean();    }    /**     * Looks up a stateless bean and invokes on it     *      * @throws NamingException     */    private static void invokeStatelessBean() throws NamingException {        // Let's lookup the remote stateless calculator        final RemoteCalculator statelessRemoteCalculator = lookupRemoteStatelessCalculator();        System.out.println("Obtained a remote stateless calculator for invocation");        // invoke on the remote calculator        int a = 204;        int b = 340;        System.out.println("Adding " + a + " and " + b + " via the remote stateless calculator deployed on the server");        int sum = statelessRemoteCalculator.add(a, b);        System.out.println("Remote calculator returned sum = " + sum);        if (sum != a + b) {            throw new RuntimeException("Remote stateless calculator returned an incorrect sum " + sum + " ,expected sum was "                    + (a + b));        }        // try one more invocation, this time for subtraction        int num1 = 3434;        int num2 = 2332;        System.out.println("Subtracting " + num2 + " from " + num1                + " via the remote stateless calculator deployed on the server");        int difference = statelessRemoteCalculator.subtract(num1, num2);        System.out.println("Remote calculator returned difference = " + difference);        if (difference != num1 - num2) {            throw new RuntimeException("Remote stateless calculator returned an incorrect difference " + difference                    + " ,expected difference was " + (num1 - num2));        }    }    /**     * Looks up a stateful bean and invokes on it     *      * @throws NamingException     */    private static void invokeStatefulBean() throws NamingException {        // Let's lookup the remote stateful counter        final RemoteCounter statefulRemoteCounter = lookupRemoteStatefulCounter();        System.out.println("Obtained a remote stateful counter for invocation");        // invoke on the remote counter bean        final int NUM_TIMES = 5;        System.out.println("Counter will now be incremented " + NUM_TIMES + " times");        for (int i = 0; i < NUM_TIMES; i++) {            System.out.println("Incrementing counter");            statefulRemoteCounter.increment();            System.out.println("Count after increment is " + statefulRemoteCounter.getCount());        }        // now decrementing        System.out.println("Counter will now be decremented " + NUM_TIMES + " times");        for (int i = NUM_TIMES; i > 0; i--) {            System.out.println("Decrementing counter");            statefulRemoteCounter.decrement();            System.out.println("Count after decrement is " + statefulRemoteCounter.getCount());        }    }    /**     * Looks up and returns the proxy to remote stateless calculator bean     *      * @return     * @throws NamingException     */    private static RemoteCalculator lookupRemoteStatelessCalculator() throws NamingException {        final Hashtable jndiProperties = new Hashtable();        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");        final Context context = new InitialContext(jndiProperties);        // The JNDI lookup name for a stateless session bean has the syntax of:        // ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>        //        // <appName> The application name is the name of the EAR that the EJB is deployed in        // (without the .ear). If the EJB JAR is not deployed in an EAR then this is        // blank. The app name can also be specified in the EAR's application.xml        //        // <moduleName> By the default the module name is the name of the EJB JAR file (without the        // .jar suffix). The module name might be overridden in the ejb-jar.xml        //        // <distinctName> : AS7 allows each deployment to have an (optional) distinct name.        // This example does not use this so leave it blank.        //        // <beanName> : The name of the session been to be invoked.        //        // <viewClassName>: The fully qualified classname of the remote interface. Must include        // the whole package name.        // let's do the lookup        return (RemoteCalculator) context.lookup("ejb:/ejb-service/CalculatorBean!"                + RemoteCalculator.class.getName());    }    /**     * Looks up and returns the proxy to remote stateful counter bean     *      * @return     * @throws NamingException     */    private static RemoteCounter lookupRemoteStatefulCounter() throws NamingException {        final Hashtable jndiProperties = new Hashtable();        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");        final Context context = new InitialContext(jndiProperties);        // The JNDI lookup name for a stateful session bean has the syntax of:        // ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful        //        // <appName> The application name is the name of the EAR that the EJB is deployed in        // (without the .ear). If the EJB JAR is not deployed in an EAR then this is        // blank. The app name can also be specified in the EAR's application.xml        //        // <moduleName> By the default the module name is the name of the EJB JAR file (without the        // .jar suffix). The module name might be overridden in the ejb-jar.xml        //        // <distinctName> : AS7 allows each deployment to have an (optional) distinct name.        // This example does not use this so leave it blank.        //        // <beanName> : The name of the session been to be invoked.        //        // <viewClassName>: The fully qualified classname of the remote interface. Must include        // the whole package name.        // let's do the lookup        return (RemoteCounter) context.lookup("ejb:/ejb-service/CounterBean!"                + RemoteCounter.class.getName() + "?stateful");    }}


2.4 配置jboss-ejb-client.properties配置文件,放置到src下面

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=falseremote.connections=defaultremote.connection.default.host=localhostremote.connection.default.port = 4447remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false



 3 Demo详解

上面的Demo来自于官方网站,并且每一行都有详细的注释,下面的就带大家来分析一下,整个Demo中的关键点。

3.1 JNDI命名规则

For stateless beans

ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>

For stateful beans

ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful


首先ejb:命名空间,表明了,这是一个有关于EJB的远程调用的实例,其余的部分的解释如下


app-name:这是一个有关于.ear的前缀名称,如果我们部署在jboss中的是.ear结尾的文件的话,那么这个app-name就代表的是除去前缀的名称,例如如果我部署的是ejb-server.ear的话,那么app-name就代表的是ejb-server,如果没有的话,则为空表示,需要注意的是,前面没有斜线


module-name:这是有关于.jar包的前缀,正如我们这个例子中,我们把服务端最后打成了一个ejb-server.jar包,那么前缀就是ejb-server,这个模块的名称也可以为空,也可以重写


distinct-name:这是一个可选的名称,可以为空


bean-name:这是我们需要远程调用的bean的名称,记住这里是实现的bean的名称,不是接口的名称


viewClassName:这是我们所要调用bean的接口的全名,包括包的名称例如一个远程调用的bean的接口是RemoteCalculator,则这里必须是包名+类名,即为com.tgb.RemoteCalculator。再次需要注意的是,如果是有状态的bean的话,需要加上?stateful。下面再看我们上面例子的话,有状态的bean的全称为

ejb:/ejb-service/CounterBean!com.tgb.RemoteCounter?stateful

因为我们没有打ear包,所以名称可以省略。



3.2 jboss-ejb-client.properties详解

接下来我们来分析一下,有关JNDI properties的配置。

 jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

上面的Context.URL_PKG_PREFIXES是为了我们让JDNI API知道,我们目前带调用的是EJB命名空间的bean




 

0 0
原创粉丝点击