从目前EJB3来看,EJB其实只有两类
1,会话(Session)Bean
2,消息驱动Bean(Message Driven Bean,MDB)
开发远程调用无状态Session Bean
@Remote
public interface Hello {
public String hello(String name);
}
@Stateless(mappedName = "Hello")
public class HelloBean implements Hello {
@Override
public String hello(String name) {
return name + ",hello,now time is " + new Date();
}
}
@Remote专门用于修饰支持远程调用的EJB,即可以修饰接口,也可以修饰Bean的实现类。
@Remote和@Local用法几乎完全一样,@Remote允许远程调用,@Local只允许本地调用。
如果EJB的Bean实现类需要实现多个接口,就必须使用@Local、@Remote来修饰。
@Stateless用于修饰支持无状态Session Bean的Bean实现类,可以指定一个mappedName属性,用于为该EJB指定名称。这个名称并不是该EJB的JNDI名。但是EJB容器会根据其属性值生成该EJB的JNDI绑定名。
WebLogic的规则是<mappedName>#<业务接口的全限定类名>,如Hello#com.kingdz.service.Hello。
JBoss允许开发者不指定其属性值。如果没有指定则为<Bean类名>/remote。如果指定了则为mappedName。
对于使用@Local修饰的本地调用的EJB,为@Stateless指定的mappedName属性对于生成JNDI没有任何影响。
注意:如果不是直接将EJB部署在JBoss服务器中,而是先将EJB打包在JavaEE中,然后把这个应用整体部署在JBoss服务器中,那么JBoss为该EJB自动生成JNDI为<EAR文件名>/<Bean类名>/remote(远程调用的EJB)或<EAR文件名>/<Bean类名>/local(本地调用的EJB)。
下面是调用的方法:
public class EjbClient {
public void test() throws Exception {
Context ctx = getJBossInitialContext();
Hello h1 = (Hello) ctx.lookup("Hello");
System.out.println(h1.hello("123"));
}
private Context getJBossInitialContext() {
final String INIT_FACTORY = "org.jnp.interfaces.NamingContextFactory";
final String SERVER_URL = "localhost:1099";
Context ctx = null;
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, INIT_FACTORY);
props.put(Context.PROVIDER_URL, SERVER_URL);
try {
ctx = new InitialContext(props);
} catch (NamingException e) {
e.printStackTrace();
}
return ctx;
}
public static void main(String[] args) {
try {
new EjbClient().test();
} catch (Exception e) {
e.printStackTrace();
}
}
}
本地的@Local的无状态Session Bean与开发远程的相似。区别是需要使用@Local修饰代替@Remote。
但是注意,在调用的时候不能使用和远程一样的方式调用,需要部署在服务器上才可以调用。否则会出现
Caused by: java.lang.RuntimeException: Could not find InvokerLocator URL at JNDI address "CatServiceBean/local"; looking up local Proxy from Remote JVM?
可以编写JSP
<%
InitialContext ctx=new InitialContext();
Object stub=ctx.lookup(“CatServiceBean/local”);
CatService cs=(CatService)stub;
Person p=new Person(1,”haha”);
Cat[] cats=cs.getCats(new Person(2,”hehe”));
%>
当将本地调用的Session Bean发布在WebLogic服务器后,实际上该Session Bean不仅不能通过远程调用,甚至不能通过该WebLogic中的其他Web程序调用,只能通过与它位于同一个JavaEE应用程序的其他组件来调用,也就是说需要将EJB组件和Web程序打包到一个EAR文件中。
注意:依然保证参数和返回值可以序列化。
这里介绍的两个无状态的Session Bean没有持有任何实例变量,但实际上Session Bean也可以持有实例变量。需要注意的是,不要让Session Bean的实例变量与任何客户机关联——也就是该实例变量可用于记录整个应用的状态,而不能用于记录某个客户机的状态,否则会引起错误。
EJB3提供了大量的Annotation,其中用于修饰EJB的业务接口、EJB Bean类的Annotation有如下几个:
@Remote:修饰远程调用的EJB的业务接口或Bean类,修饰业务接口时无须指定任何属性,修饰Bean实现类时则要指定业务接口的类名。
@Local:修饰本地调用的EJB的业务接口或Bean类,修饰业务接口时无须指定任何属性,修饰Bean的实现类时则要指定业务接口的类名。
@Stateful:修饰有状态会话EJB的Bean类,使用该Annotation时可指定name和mappedName两个属性,其中name指定该EJB的名字;mapperedName指定该EJB的全局名。
@Stateless:修饰无状态会话EJB的Bean类,使用该Annotation时可指定name和mappedName两个属性,其中name指定该EJB的名字;mapperedName指定该EJB的全局名。
@MessageDriven:修饰消息驱动EJB的Bean类,使用该Annotation时可指定name和mappedName两个属性,其中name指定该EJB的名字;mapperedName指定该EJB的全局名。除此之外,该Annotation还可指定activationConfig属性,该属性值是多个@ActivationConfigProperty Annotation。
@ActivationConfigProperty:也是一个修饰消息驱动Bean的Annotation。
public class Cat {
private String name;
private Integer age;
}
@Local
public interface CatService {
Cat[] getCats(Person owner);
}
@Stateless(mappedName="CatService")
public class CatServiceBean implements CatService {
static Map<Person, Cat[]> catsInfo;
static {
catsInfo = new HashMap<Person, Cat[]>();
catsInfo.put(new Person(1, "p1"), new Cat[] { new Cat("Kitty", 2), new Cat("Garfield", 4) });
}
@Override
public Cat[] getCats(Person owner) {
return catsInfo.get(owner);
}
}
public class Person {
private Integer id;
private String name;
public Person() {
}
public Person(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object target) {
if (this == target) {
return true;
}
if (target.getClass() == Person.class) {
Person p = (Person) target;
if (p.getId() == this.getId()) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.getId();
}
}
上面的注解也可以使用XML来配置。
src\META-INF\ejb-jar.xml
<ejb-jar>
<enterprise-beans>
<session>
<!--指定该EJB的名称-->
<ejb-name>catService</ejb-name>
<!--指定该EJB的mappedName-->
<mapped-name>cs</mapped-name>
<!--指定该EJB的本地访问的业务接口-->
<business-local>CatService</business-local>
<!--指定该EJB的Bean实现类-->
<ejb-class>CatServiceBean</ejb-class>
<!--指定该EJB是无状态的Session Bean-->
<session-type>Stateless</session-type>
</session>
</enterprise-beans>
</ebj-jar>
不管是使用Annotation修饰还是XML配置,其实所配置的信息本质上没有改变,只是承载信息的形式不同而已。