EJB

EJB定义了三种企业Bean,分别是会话 Bean(Session Bean),实体Bean(Entity Bean)和消息驱动Bean(MessageDriven Bean)

Session Bean:用于实现业务逻辑,它分为有状态bean和无状态bean。每当客户端请求时,容器就会选择一个Session Bean来为客户端服务。

实体 Bean:存放数据和跟数据库表进行对象与关系映射(O/R Mapping)

消息驱动Bean(MDB):是设计用来专门处理基于消息请求的组件。它能够收发异步JMS消息,并能够轻易地与其他EJB交互。它特别适合用于当一个业务执行的时间很长,而执行结果无需实时向用户反馈的这样一个场合。

JNDI(The Java Naming and Directory Interface Java 命名和目录接口)是一组在Java应用中访问命名和目录服务的API。为开发人员提供了查找和访问各种命名和目录服务的通用、统一的方式。借助于JNDI提供的接口,能够通过名字定位用户、机器、网络、对象服务等。

命名服务:就像DNS一样,通过命名服务器提供服务,大部分的J2EE服务器都含有命名服务器。
目录服务:一种简化的RDBMS系统,通过目录具有的属性保存一些简单的信息。目录服务通过目录服务器实现,

JNDI 编程过程
因为JNDI是一组接口,所以我们只需根据接口规范编程就可以.要通过JNDI进行资源访问,我们必须设置初始化上下文的参数,主要是设置JNDI驱动的类名(java.naming.factory.initial)和提供命名服务URL(java.naming.provider.url).
java.naming.factory.initial(Context.INITIAL_CONTEXT_FACTORY)
环境属性名,用于指定 InitialContext工厂,类似于JDBC 指定数据库驱动类。

java.naming.provider.url(Context.PROVIDER) localhost:1099
提供命名服务的主机地址和端口号。它类似于JDBC指定数据库的连接URL。

除了上述两个环境属性外,还有两个环境属性是我们经常使用到的:
java.naming.security.principal(Context.SECURITY_PRINCIPAL)
java.naming.security.credentials(Context.SECURITY_CREDENTIALS)
这两个环境属性用于指定用户标识(如用户名)及凭证(如密码),当EJB 使用了安全服务时,你必须提供
这两个属性。它类似于JDBC指定连接到数据库的用户名及密码。

创建InitialContext对象时如果没有指定Properties参数,InitialContext还会在classpath下寻找jndi.properties文件,并从该文件中加载应用服务器的上下文信息
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
当InitialContext初始化后,我们使用EJB的Jndi名称通过 lookup()方法查找EJB

常见服务器参数
java.naming.factory.initial
Jboss服务器: org.jnp.interfaces.NamingContextFactory
Sun 应用服务器: com.sun.enterprise.naming.SerialInitContextFactory
Weblogic10服务器: weblogic.jndi.WLInitialContextFactory

java.naming.provider.url
Jboss服务器: host:1099
Sun 应用服务器: host:3700
Weblogic10服务器: t3:// host:7001

JBOSS 环境下 JNDI 树的命名约定:
java:copm
这个上下文环境和其子上下文环境仅能被与之相关的特定应用组件访问和使用
java:
子上下文环境和绑定的对象只能被 Jboss服务器虚拟机内的应用访问
其他上下文环境
只要实现序列化就可以被远程用户调用。

要开发一个Session Bean,我们需要定义一个接口和一个实现类
其中接口分为远程(remote)和本地(local)接口,一个Session Bean可以实现多个接口.
远程接口:定义了session bean的业务方法,这些方法可以被来自EJB容器之外的应用访问到
本地接口:同样定义了session bean的业务方法,这些方法可以被同处于EJB容器内的其它应用使用。因为local接口允许bean之间直接通过内存交互,没有分布式对象协议的开销,从而改善了性能

Session Bean编写规则
不能是final或abstract,必须有无参数建构子,可以是某个POJO的子类别
可以是某个Session Bean的子类别,但继承自某个Session Bean时, @Stateless、 @Stateful会被忽略。
所以在子类别中,必须再次标注Bean为 @Stateless或 @Stateful
所有方法必須是public、非static、非final
不可以使用ejb作为方法名称开头
若标示为 @Remote,则所有的参数或返回值必须实现java.io.Serializable接口的


@Stateless @Stateful
name:属性用来指定Bean名称。该名称在EJB Jar包中必须是全局唯一。
而在 EAR 中却可以重复(因为EAR可以包含多个EJB Jar,而每个jar可以存在一个同名的EJB,在EAR中要定位某个EJB,可以这样使用:xxx.jar#HelloWorldBean)。
有的容器会将name属性与JNDI名称绑定在一起。Glassfish上单独指定name属性,则要用Bean的服务接口之全名方可取得Bean。不指定该属性,默认就是session bean的简单名称。
mappedName:属性是厂商特定属性,有的容器(如glassfish)会将mappedName属性与JNDI名称绑定在一起

在Jboss中自定义session Bean的JNDI名称,可以使用 @LocalBinding 和 @RemoteBinding 注释
@LocalBinding注释指定Session Bean的Local接口的JNDI名称,
@RemoteBinding注释指定Session Bean的Remote接口的JNDI名称

Jboss全局JNDI名称默认的命名规则
如果把EJB作为模块打包进后缀为*.ear的JAVA EE企业应用文件,默认的全局JNDI名称是
本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local
远程接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote
EAR-FILE-BASE-NAME为ear文件的名称,EJB-CLASS-NAME为EJB bean的简单名称
把HelloWorld应用作为EJB模块打包进名为HelloWorld.ear的企业应用文件
它的远程接口的JNDI名称是:HelloWorld/HelloWorldBean/remote

如果把 EJB 应用打包成后缀为*.jar的模块文件,默认的全局JNDI名称是
本地接口:EJB-CLASS-NAME/local
远程接口:EJB-CLASS-NAME/remote

Session Bean的生命周期
EJB容器负责创建和管理session bean实例,可能需要定制session bean的管理过程。
管理session bean可以通过在bean类中定义生命周期的回调方法来实现,这些方法将会被容器在生命周期的不同阶段调用
@PostConstruct:当bean对象完成实例化后,使用了这个注释的方法会被立即调用.这个注释同时适用于有状态和无状态的会话bean。

@PreDestroy:使用这个注释的方法会在容器从它的对象池中销毁一个无用的或者过期的 bean 实例之前调用。这个注释同时适用于有状态和无状态的会话 bean

@PrePassivate:当一个有状态的session bean实例空闲过长的时间,容器将会钝化(passivate)它,并把它的状态保存在缓存当中.使用这个注释的方法会在容器钝化bean实例之前调用.这个注释适用于有状态的会话bean。当钝化后,又经过一段时间该bean仍然没有被操作,容器将会把它从存储介质中删除.以后,任何针对该 bean方法的调用容器都会抛出例外

@PostActivate:当客户端再次使用已经被钝化的有状态session bean时,新的实例被创建,状态被恢复.使用此注释的 session bean 会在bean的激活完成时调用.这个注释只适用于有状态的会话 bean。

@Init:这个注释指定了有状态session bean初始化的方法,它区别于 @PostConstruct注释在于:多个 @Init注释方法可以同时存在于有状态session bean中,但每个 bean 实例只会有一个 @Init注释的方法会被调用。这取决于bean是如何创建的, @PostConstruct在 @Init之后被调用。

@Remove,特别是对于有状态session bean,当应用通过存根对象调用使用了 @Remove 注释的方法时,容器就知道在该方法执行完毕后,要把bean实例从对象池中移走。

拦截器(Interceptor)
拦截器可以监听程序的一个或所有方法。拦截器对方法调用流提供了细粒度控制。
sesion bean用 @Interceptors注释指定一个或多个在外部类中定义的拦截器
拦截器类用 @AroundInvoke注释指定了要用作拦截器的方法。
用 @AroundInvoke注释指定的方法必须遵守以下格式:
public Object XXX(InvocationContext ctx) throws Exception
XXX 代表方法名可以任意
除了可以在外部定义拦截器之外,还可以将Session Bean中的一个或多个方法定义为拦截器

Session Bean注入
Stateless Session Bean中可注入Stateless Session Bean,但不可注入Stateful Session Bean
Stateful Session Bean中可注入Stateless Session Bean,或其他Stateful Session Bean
注意若Stateful Session Bean被销毁了,被注入的Stateful Session Bean也会被销毁

使用 @EJB注释,你可以将EJB存根对象注入到任何EJB 3.0容器管理的POJO中.如果注释用在一个属性变量上,容器将会在它被第一次访问之前赋值给它.依赖注入只工作在本地命名服务中,因此你不能注入远程服务器的对象
@EJB注释的beanName属性指定EJB的名称(如果没有设置过 @Stateless 或 @Stateful的name属性,默认为不带包名的类名),他的另一个属性 mappedName 指定 EJB 的全局 JNDI名。
@EJB注释如果被用在JavaBean风格的setter方法上时,容器会在属性第一次使用之前,自动地用正确的参数调用bean的setter方法。
@EJB注释只能注入EJB存根对象,除 @EJB注释之外,EJB3.0也支持 @Resource注释来注入来自JNDI的任何资源
如果JNDI对象在本地(java:comp/env)JNDI目录中,你只需给定他的映谢名称即可,不需要带前缀
对于"well-known"对象, @Resource 注释可以不指定JNDI名就能注入他们,他通过变量的类型就能获得他的JNDI名
如: @Resource TimerService tms; @Resource SessionContext ctx

Jboss按默认的顺序先发布EJB,当一个EJB注入另一个尚未发布的EJB时,Jboss会抛出一个例外。
解决办法:在[JBOSS_HOME]/server/default/conf文件夹中找到jboss-service.xml
<attribute name="URLComparator">org.jboss.deployment.DeploymentSorter</attribute>
<!--
<attribute name="URLComparator">org.jboss.deployment.scanner.PrefixDeploymentSorter</attribute>
-->
修改为
<!—
<attribute name="URLComparator"> org.jboss.deployment.DeploymentSorter</attribute>
-->
<attribute name="URLComparator">org.jboss.deployment.scanner.PrefixDeploymentSorter</attribute>
给 jar文件编个号,格式为:01_XXX.jar
如:01_HelloWorld.jar 02_DependencyInjection.jar Jboss将根据编号按从小到大的顺序发布 jar文件

定时服务(Timer Service)
定时服务用作在一段特定的时间后执行某段程序
通过依赖注入 @Resource SessionContext ctx,通过SessionContext对象,调用ctx.getTimerService().createTimer
(Date arg0, long arg1, Serializable arg2)方法创建定时器,三个参数的含义如下:
Date arg0 定时器启动时间,如果传入时间小于现在时间,定时器会立刻启动。
long arg1 间隔多长时间后再次触发定时事件。单位:毫秒
Serializable arg2 你需要传给定时器的参数,该参数必须实现 Serializable 接口。

当定时器创建完成后,我们还需声明定时器方法。
只需在方法上面加入 @Timeout 注释,另外定时器方法必须遵守如下格式:
void XXX(Timer timer)在定时事件发生时,此方法将被执行
当定义多个 @Timeout 定时器发放,前面的会被覆盖

安全服务(Security service)
验证(Authentication):认证是完成用户名和密码的匹配校验;
授权(authorization):授权是决定用户可以访问哪些资源,授权是基于角色的
Jboss服务器提供了安全服务来进行用户认证和根据用户规则来限制对POJO的访问。对每一个POJO来说,你可以通过使用 @SecurityDomain 注释为它指定一个安全域, 安全域告诉容器到哪里去找密码和用户角色列表。
Jboss存在默认安全域"other","other"安全域告诉容器到 classpath 中的 users.propertes 和 roles.properties找密码和用户角色列表."other"安全域的定义在[JBOSS_HOME]/server/default/conf/login-config.xml文件
"other"安全域默认情况下是不允许匿名用户访问的,如果你想使匿名用户也可访问通过 @PermitAll 注释定义的资源,可以修改"other"安全域配置,增加如下配置
<module-option name = "unauthenticatedIdentity">AnonymousUser</module-option>

安全域的定义有两种方法:
第一种方法:通过 Jboss发布文件(jboss.xml)进行定义,定义内容如下:
jboss.xml(以Jboss默认的安全域"other"为例)
<?xml version="1.0" encoding="UTF-8"?>
<jboss>
<security-domain>other</security-domain>
<unauthenticated-principal>AnonymousUser</unauthenticated-principal>
</jboss>
jboss.xml文件需要打包到META-INF目录

第二种方法:通过 @SecurityDomain 注释进行定义(不推荐) 如: @SecurityDomain("other")
由于使用的是 Jboss安全注释,程序采用了硬编码,不利于日后迁移到其他 J2EE 服务器

程序可以通过 @RolesAllowed 注释定义允许访问方法的角色列表,如角色有多个,可以用逗号分隔。
@PermitAll注释定义所有的角色都可以访问此方法。

为了使用容器的安全服务,我们需要在 jboss-web.xml定义使用的安全域(例子使用 other域),该文件放置在WEB-INF目录下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值