您的位置:首页 > 其它

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

2015-08-28 11:49 555 查看
 

 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=false

remote.connections=default

remote.connection.default.host=localhost
remote.connection.default.port = 4447
remote.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

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: