关于EJB3.x的命名空间一直都很迷惑,阅读规范之后这里做一下笔记:
EJB reference,是指一个EJB引用另一个EJB的business interface, non-interface views或者home接口。
我们可以在部署描述符ejb-jar.xml中:
1、在同一ejb-jar.xml中一个EJB对另一个EJB的引用,因此大多数情况下,。
2、同一应用(企业应用)中一个EJB对另一个EJB的引用(它们在不同的ejb-jar.xml中被声明)。
3、java:global中的引用(这一点为什么规范中没有说?)。
JAVAEE中EJB的JNDI有下面几个命名空间:
java:global
java:app
java:module
java:comp
每个Bean拥有自己的java:comp,Bean与Bean之间java:comp是相互隔离的,同样module与module之间的java:module是相互隔离的,应用与应用之间java:app是相互隔离的。另外打包在war中的Bean比较特殊,所有的web组件(servlet/filter)与所有的Bean(包括Bean与Bean之间)共用同一个java:comp空间。
<ejb-link>在下面的情况下会使用:
Here are some scenarios that hopefully clarify why <ejb-link/> (or @EJB(beanName="...")) and EJB ref bindings are both useful and complementary: An application can itself be logically broken up into components, and the developer chooses to use EJBs to implement those components. In this case, the application developer knows the target EJB component that the client wants to use. If there are multiple components implementing the same interface, then some disambiguation is required, and <ejb-link/> can be used. An application has a dependency on an external service. In this case, the application knows it has a dependency on an external service, so <ejb-link/> cannot be used since the service implementation does not exist in the same application. An application has a dependency on an external service, but a minimal implementation is provided in the same application. In this case, the developer might use an <ejb-link/> as in #1, but the deployer has the flexibility to override that choice as in #2.
<resource-ref>和<resource-env-ref>
<resource-ref>与<resource-env-ref>本质上没有太大的区别:
1、他们都使用@Resource注解来标记,有些类型甚至还可以互换。
2、<resource-ref>与<resource-env-ref>不同之处在于,<resource-ref>是指引用我们在JavaEE应用服务器上配置的资源,比如jdbc,ConnectionFacotry等等这一类型的资源,通常来说这些资源具有Factory性质,当然不是Factory性质也可以,这没有明确的规定,有一些资源应用服务器会进行特殊处理,比如ConnectionFactory之类的。
但<resource-env-ref>一般是指引用我们应用服务器的组件,比如下面这些类型,它们很多是bean运行时涉及的上下组件,也有一些像Queue,Topic之类的配置性资源,它们大部分是直接的组件(非factory性质):
public static final Set<String> knownResourceEnvTypes = new TreeSet<String>(Arrays.asList( "javax.ejb.EJBContext", "javax.ejb.SessionContext", "javax.ejb.EntityContext", "javax.ejb.MessageDrivenContext", "javax.transaction.UserTransaction", "javax.jms.Queue", "javax.jms.Topic", "javax.xml.ws.WebServiceContext", "javax.ejb.TimerService", "javax.enterprise.inject.spi.BeanManager", "javax.validation.Validator", "javax.validation.ValidatorFactory" ));
下面有是JavaEE规范对<resource-env-ref>的描述:
This section describes the programming and deployment descriptor interfaces that
allow the Application Component Provider to refer to administered objects that are
associated with a resource (for example, a Connector CCI InteractionSpec
instance) by using “logical” names called resource environment references. The
resource environment references are special entries in the application component’s
environment. The Deployer binds the resource environment references to
administered objects in the target operational environment.
类似的还有@PersistenceContext,@PersistenceUnit:
@PersistenceContext用于注入/引用 EntityManager
@PersistenceUnit用于注入EntityManagerFactory
glassfish中的mappedName并不是指将ejb映射到java:global下,而是指全局jndi,全局jndi跟java:global并不是一个东西,而且从glassfish的jndi结构上来看,java:global只是全局jndi下面的一个子context。
在EJB中我们通常称JNDI为ENC,也就是Enterprise Naming Context的缩写。
resource-ref的ref-name:指程序代码中所使用的进行lookup的jndi name,如果我们不指定它所注入资源的jndi名称,则默认注入名为java:comp/env/full-qualified.class.name/member的资源。
resource-ref的mapped-name:指所引用的外部(全局)的资源的id。
resource-env-ref与resource-ref差不多,但resource-env-ref是直接的资源,针对 queue 和topic这一类的。
new InitialContext()的时候,这个InitialContext并不一定是指向java:comp/env,有的应用服务器会指向这个位置,但规范里面并没有这个规定,因为这样子的程序并不是portable的。比如Tomcat的InitialContext就不是(今天同事遇到这个问题了)。
ejb-ref(@Remote类型的接口/View引用), ejb-local-ref(Local类型的接口/View引用),(区别于env-entry,env-entry只能声明基本类型的引用如string, int, boolean等):
可以往bean的NamingContext(也就是java:comp命名空间下面)bind其它bean的reference。这样子我们可以lookup到这些引用,并在适当的时候可以通过修改ejb-jar.xml来改变bean的引用,而不需要去修改代码。
ejb规范建议,bean所有的对其它bean的引用都应该位于java:comp/env/ejb下面。但通过注解所声明的引用将不会在任何subContext下面。
另外,我们还可以使用注解来进行声明ejb-ref,如下:
@EJB(name="ejb/EmplRecord", beanInterface=EmployeeRecordHome.class) @Stateless public class EmployeeServiceBean implements EmployeeService { public void changePhoneNumber(...) { ... // Obtain the default initial JNDI context. Context initCtx = new InitialContext(); // Look up the home interface of the EmployeeRecord // enterprise bean in the environment. Object result = initCtx.lookup( "java:comp/env/ejb/EmplRecord"); // Convert the result to the proper type. EmployeeRecordHome emplRecordHome = (EmployeeRecordHome) javax.rmi.PortableRemoteObject.narrow(result, EmployeeRecordHome.class); ... } }
ejb-ref-name就是我们要绑定到java:comp下面的jndi名字,我们进行lookup的时候需要用这个name进行lookup,
ejb-ref-type是可选填写的,可以是Entity/Session
home/remote/local-home/local用于指定引用bean的接口类型,如果引用ejb2.x的bean的话,home是必须指定的。
ejb-link/lookup-name用于指定所引用的外部bean(target)。两者不能同时使用,ejb-link是可选的,如果不填写的话,则在当前的ejb-jar.xml(包括注解)中查找具有相应接口的bean。ejb-link的值是需要引用的bean的<ejb-name>,当然也可以用注解来进行声明 。
与<ejb-ref>/<ejb-local-ref>相对应的注解是@EJB
@EJB.name => <ejb-ref-name>
@EJB.beanName => <ejb-link>
@EJB.lookup => <lookup-name>
@EJB.mappedName => <mapped-name>
EJB的home接口的实现由JavaEE应用服务器提供,用户只需要提供接口。其中创建bean的方法必须是create<METHOD>(xxx,xxx)的形式,Stateless Session Bean只能是create(),而对于Stateful Session Bean而言,创建Bean实例后,服务器将会去调用Bean实例上的ejbCreate<Method>方法。