No EJB receiver available for handling ...
在Jboss EAP 6中,调用远程EJB时出现这个错误, 原因可能是JNDI格式写错了。EJB JNDI的格式如下:
ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful
注意appName前是没有"/"的!如没有distinctName,留空,即连续两个”//“。
在jboss-eap-quickstarts-6.4.0.GA提供了样例代码ejb-remote:
public interface RemoteCalculator {
int add(int a, int b);
int subtract(int a, int b);
}
@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;
}
}
public class RemoteEJBClient {
public static void main(String[] args) throws Exception {
// Invoke a stateless bean
invokeStatelessBean();
// Invoke a stateful bean
invokeStatefulBean();
}
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));
}
}
...
private static RemoteCalculator lookupRemoteStatelessCalculator() throws NamingException {
final Hashtable<String, String> jndiProperties = new Hashtable<String, String>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
return (RemoteCalculator) context.lookup("ejb:/jboss-ejb-remote-server-side/CalculatorBean!" + RemoteCalculator.class.getName());
}
...
}
jboss-ejb-client.properties(放在resources根目录下)
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
Client pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>${version.jboss.spec.javaee.6.0}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ejb-client-bom</artifactId>
<version>${version.jboss.as}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Import the transaction spec API, we use runtime scope because we aren't using any direct
reference to the spec API in our client code -->
<dependency>
<groupId>org.jboss.spec.javax.transaction</groupId>
<artifactId>jboss-transaction-api_1.1_spec</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Import the EJB 3.1 API, we use runtime scope because we aren't using any direct
reference to EJB spec API in our client code -->
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.1_spec</artifactId>
<scope>runtime</scope>
</dependency>
<!-- We depend on the EJB remote business interfaces of this application -->
<dependency>
<groupId>org.jboss.quickstarts.eap</groupId>
<artifactId>jboss-ejb-remote-server-side</artifactId>
<type>ejb-client</type>
<version>${project.version}</version>
</dependency>
<!-- JBoss EJB client API jar. We use runtime scope because the EJB client API
isn't directly used in this example. We just need it in our runtime classpath -->
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-ejb-client</artifactId>
<scope>runtime</scope>
</dependency>
<!-- client communications with the server use XNIO -->
<dependency>
<groupId>org.jboss.xnio</groupId>
<artifactId>xnio-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.jboss.xnio</groupId>
<artifactId>xnio-nio</artifactId>
<scope>runtime</scope>
</dependency>
<!-- The client needs JBoss remoting to access the server -->
<dependency>
<groupId>org.jboss.remoting3</groupId>
<artifactId>jboss-remoting</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Remote EJB accesses can be secured -->
<dependency>
<groupId>org.jboss.sasl</groupId>
<artifactId>jboss-sasl</artifactId>
<scope>runtime</scope>
</dependency>
<!-- data serialization for invoking remote EJBs -->
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-river</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
例子是以jar包的形式部署到jboss中的,查看jboss日志,能查找到:
java:jboss/exported/jboss-ejb-remote-server-side/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator
以jar包的形式部署,访问时写法:
context.lookup("ejb:/jboss-ejb-remote-server-side/CalculatorBean!" + RemoteCalculator.class.getName());
若将其移到ear中,改为如下写法:
context.lookup("ejb:/myear/myejb/CalculatorBean!" + RemoteCalculator.class.getName());
就出现了No EJB receiver available for handling ...,注意要去掉"/"!
注意:By default WildFly uses 8080 as the remoting port. The EJB client API uses the http port, with the http-upgrade functionality, for communicating with the server for remote invocations(unless the server is configured for some other http port)
参考文档
Invoke a Session Bean Remotely using JNDI(EAP 6)
EJB invocations from a remote client using JNDI(Wildfly 8)
Remote EJB invocations via JNDI - EJB client API or remote-naming project