1.EJB3简介:
EJB是企业级java bean(Enterprise Java Bean)开发技术,是基于IIOP协议的分布式远程方法调用技术(RMI),EJB3在JavaEE5中被正式引入,去掉了EJB2以前的复制度,使得EJB3更加轻量级,同时将实体Bean单独分拆成为JPA规范,从而使EJB3更加专注于会话Bean和消息驱动Bean的业务逻辑,同时EJB3中全面支持java注解方式,大大简化开发的难度提高开发效率。
2.在客户端调用一个简单EJB3程序:
首先使用一个简单例子演示客户端调用EJB3的基本过程,使用Jboss应用服务器为例。
(1).设置Jboss的JNDI连接:
Properties props = new Properties(); props.setProperty(“java.naming.factory,initial”, “org.jnp.interfaces.NamingContextFactory”); props.setProperty(“java.naming.provider.url”, “localhost:1099”); InitialContext context = new InitialContext(props);
(2).通过JNDI在客户端调用服务器端的Bean
HelloWorld hello = (HelloWorld)context.lookup(“HelloWorldBean/remote”);
通过hello对象调用会话Bean所实现接口的方法
其中:HelloWorld是接口,HelloWorldBean是实现了接口的服务器端会话Bean.
该调用过程中返回的实例对象并非写在服务器端的会话Bean,而是一个实现了HelloWorld接口的代理对象。
3.JNDI简介:
JNDI:java naming directory interface(java命名和目录接口),是EJB的核心,它为远程对象提供存储服务,调用者通过JNDI名称从JNDI服务器上获取目标对象。
(1).Jboss的JNDI树命名规则:
各个JavaEE服务器的JNDI命名和生成规则可能有所区别,这里以Jboss为例。
a. java:comp :此上下文环境和其子上下文环境仅能被应用组件内部访问和使用。
b. java: :子上下文环境和绑定的对象只能被处于同一个java虚拟机内的对象访问。
c. 全局JNDI命名空间:上下文环境可以被所有对象访问。
(2).JNDI连接信息:
a.JNDI驱动类:java.naming.factory.initial或者Context.INITIAL_CONTEXT_FACTORY。
b.JNDI提供者url:java.naming.provider.url或者Context.PROVIDER_URL。
c.用户标识:java.naming.security.principal或者Context.SECURITY_PRINCIPAL。
d.用户密码:java.naming.security.credentials或者Context.SECURITY_CREDENTIALS。
注意:后面两个主要在EJB使用安全服务时用到。
4.Jboss默认生成的JNDI名称规则:
(1).当EJB作为模块被打包进后缀为”.ear”的javaEE企业应用文件中时,默认的全局JNDI名称规则如下:
本地接口:Ear-file-basename(ear文件名)/ejb实现类名/local
远程接口:Ear-file-basename(ear文件名)/ejb实现类名/remote
(2). 当EJB作为模块被打包进后缀为”.jar”的模块文件中时,默认的全局JNDI名称规则如下:
本地接口: ejb实现类名/local
远程接口: ejb实现类名/remote
5.远程调用和本地调用:
(1).本地调用:
客户端和EJB在同一Java虚拟机进程中,使用本地接口调用EJB,本地接口和EJB在JVM内存中直接通信,不需要序列化。本地调用EJB时,客户端操作的EJB参数是个内存引用,对参数的修改会影响到EJB。
(2).远程调用:
客户端和EJB不在同一Java虚拟机进程中,使用远程接口调用EJB,远程接口调用EJB的过程如下:
Socket通信
客户端————————>EJB
<—————————
IIOP消息
远程访问时,数据需要序列化。远程地用EJB时,客户端操作的EJB参数其实是一份参数值的拷贝,因此对参数的修改不会影响到EJB。
(3).客户端和EJB交互的过程:
客户端通过远程/本地接口引用从EJB容器返回的存根(stub,在EJB部署期间使用JDK的反射机制生成的动态代理对象),调用EJB在服务器端生成骨架。从而实现远程方法调用。
本地客户端既能通过本地接口调用EJB,又可以通过远程接口调用EJB。
远程客户端只能通过远程接口调用EJB。
注意:由于远程调用比较慢,因此,尽量使用粗粒度的接口设计,即尽量减少方法的调用,并尽可能在一次方法调用中传输完毕所需要的数据。
6.会话bean:
会话Bean是EJB中的核心,主要用于业务逻辑处理,会话bean分为:有状态(stateful)会话bean和无状态(stateless)会话bean。
在EJB3.0中会话bean必须实现接口,接口也分为远程接口(remote)和本地接口(local)。
声明会话bean的过程:
(1).定义接口:
在接口上分别加:@Remote或者@Local注解来指定接口是远程接口或者本地接口。
(2).定义现实接口的会话bean:
会话bean的命名规则:接口名+Bean。
在会话bean上分别加:@Stateless或者@Stateful注解来指定是无状态会话bean或者是有状态会话bean。
注意:一个会话bean可以实现多个远程或者本地接口。
7.为会话bean指定JNDI名称:
应用服务器会为会话生成默认的JNDI名称,但是也可以通过javaEE服务器提供的注解指定会话bean的JNDI名称,这里以Jboss为例:
在会话bean上加如下注解:
@RemoteBinding(jndiBinding=”自定义JNDI名”):为远程调用指定JNDI名。
@LocalBinding(jndiBinding=”自定义JNDI名”):为本地调用指定JNDI名。
注意:这两个注解是Jboss的,其他javaEE服务器的需要使用时查找。
8.会话bean的两种管理技术:
(1).无状态会话bean使用实例化池技术管理bean,性能高,可共享。
无状态会话bean,javaEE容器不保存访问状态。
(2).有状态会话bean使用激活(activation)管理bean.。
对于有状态会话bean,javaEE容器会自动保存其访问状态,EJB能够为同一客户端在多次请求之间保持状态信息,通过Token令牌来定位到特定的EJB对象。有状态会话bean的生命周期中包含三种状态:does not exist,method-ready,passivated。
9.开发EJB会话bean的基本过程:
(1).定义EJB会话Bean接口,接口既可以是本地接口也可以是远程接口,一种比较好的做法是本地接口继承远程接口,这样本地接口同时是本地和远程接口。
(2).定义会话bean实现接口,会话bean的状态只能有一个,一般使用无状态会话bean。
(3).将EJB编译、打包,然后发布到javaEE服务器上。
(4).将第1步定义的EJB接口作为EJB客户端的存根(stub),开发EJB客户端,通过存根接口调用发布在javaEE服务器上的EJB会话bean。
10.EJB会话Bean发布成WebService:
EJB3以后,会话Bean可以很方便地发布成webservice,具体方法如下:
(1).在会话bean上加”@WebService”注解,即可将该会话bean的所有方法暴露为webservice方法。
@WebService注解的几个常用参数:
a.targetNameSpace:为webservice默认命名空间。
b.name:端点接口名称(接口名)。
c.serviceName:服务名称(接口实现类名)。
(2).若只指定某些特定方法为webservice方法的话,在要暴露为webservice的方法上加”@WebMethod”注解。
注意:只有无状态会话bean可以发布为webservice,webservice使用的是SOAP协议传输参数对象,因此对象不需要序列化。
11.会话bean的生命周期事件:
(1).PostConstruct:bean对象实例化完成。
(2).PreDestroy:bean对象实例销毁之前。
(3).PrePassivate:bean实例对象钝化之前。钝化是指bean对象从内存中保存到磁盘上。
(4).PostActivate:bean实例对象激活之后。激活是指bean对象从磁盘中恢复到内存中。
(5).Init:bean实例对象初始化,@PostConstruct在其之后发生。
(6).Remove:bean实例对象从容器中移除。
通过使用这些会话bean的生命周期事件注解,可以添加回调方法。
12.为会话bean指定拦截器:
拦截器主要用于监听会话bean的生命周期事件,并对这些事件做相应的处理,在EJB3中可以使用”@Interceptors”注解为会话bean指定拦截器。拦截器方法的写法:
@AroundInvoke public Object 方法名(InvocationContext context) throwsException
可以在会话bean上使用”@ExcludeDefaultInterceptors”注解禁用默认拦截器。
9. EJB的依赖注入:
若在一个会话bean中引用了另一个会话bean,有两种方式:
(1).JNDI方式查找。
(2).通过”@EJB(beanName=被引用ejb名称)”注解进行依赖注入。
14.ENC:
ENC(Enterprise Naming Context)是应用服务器中EJB容器内部注册表,EJB的依赖注入需要通过添加ENC来实现,ENC添加方式有以下三种:
(1).通过ejb配置文件ejb-jar.xml(在jar文件的MATE-INF目录下)添加注册项:
<enterprise-beans> <session> <ejb-name>EJB名称</ejb-name> <!--引用本地EJB接口--> <ejb-local-ref> <ejb-ref-name>引用ejb的jndi名</ejb-ref-name> <ejb-ref-type>session</ejb-ref-type> <local>本地接口全路径</local> <ejb-link>实现类名</ejb-link> </ejb-local-ref> <!--引用远程EJB接口--> <ejb-remote-ref> <ejb-ref-name>引用ejb的jndi名</ejb-ref-name> <ejb-ref-type>session</ejb-ref-type> <remote>远程接口全路径</remote> <ejb-link>实现类名</ejb-link> </ejb-remote-ref> </session> </enterprise-beans>
(2).通过注解方式:
在EJB上加如下的注解:
@EJB(name=引用ejb的JNDI名, beanName=实现类名, beanInterface=接口名.class)。
(3).注入其他资源,如数据源:
@Resource(mappedName=”数据源的JNDI名”)。
15.EJB的定时服务和安全服务:
(1).定时服务:
@Resource private javax.ejb.TimerService timer; timer.createTimer(Date 定时启动时间, long 间隔ms, Serializable 传入参数);
定时器会自动触发加了”@Timeout”注解的方法。
(2).安全服务:
使用”@SecurityDomain”注解指定安全域。
Jboss中默认使用other安全域,程序在运行时在classpath下寻找users.properties和roles.properties文件,可以将户用和角色配置这两个文件中,也支持访问数据库方式验证用户身份。
16.EJB和spring集成:
虽然Spring的理论起源于《Expert one-on-one J2EE Design and Development》和《Expert one-on-one J2EE development without EJB》,很多情况下Spring就是为了取得EJB,但是Spring并不能完全取代EJB,EJB在大型分布型应用方面有着很强大的优势,另外Spring和EJB还可以配合使用。由于在客户端调用EJB时必须通过JNDI来调用,频繁的使用JNDI访问EJB会造成很大的性能开销,Spring提供了EJB JNDI缓存机制,可以大大提供客户端访问EJB的性能。具体配置有以下两种:
(1).方法1:
a. 在spring中配置JNDI连接信息:
<bean id=”jndiTemplate” class=”org.springframework.jndi.JndiTemplate”> <property name=”environment”> <props> <prop key=”jndi联系属性”>jndi连接信息值</props> …… </props> </property> </bean>
b. spring容器通过JNDI名创建EJB对象:
<bean name=”……” class=”org.springframework.jndi.JndiObjectFactoryBean”> <!--配置JNDI连接信息--> <property name=”jndiTemplate” value=”jndiTemplate”/> <!--通过JNDI访问EJB对象--> <property name=”jndiName” value=”EJB JNDI名”/> </bean>
(2).方法2:
a.在spring配置文件中引入util和jee命名空间:
xmlns:util=http://www.springframework.org/schema/util xmlns:jee=http://www.springframework.org/schema/jee
b.在spring配置文件中指定JavaEE应用服务器的JNDI连接信息:
<util:properties id=”jndienviroment” location=”JNDI连接信息文件”/>
c.在spring容器启动时根据JNDI名初始化EJB,并且缓存:
<jee:jndi-lookup id=”……” jndi-name=”EJB JNDI名” cache=”true” Look-up-on-startup=”true” proxy-interface=”接口全路径” Environment-ref=” jndienviroment”/>