Test -- 远程接口(Stub----Skeleton-拦截器) -- EJB
JVM1 --- --- --- --- --- JVM2
两个EJB运行在一个进程中, 就通过本地接口调用;
1, EJB调用同一个JVM中运行的另一个EJB, 要使用本地接口;
可以避免使用远程接口中,必须要处理网络调用带来的性能的损失;(Stub, Skeleton)
使用RMI-IIOP协议;
本地接口直接使用引用来进行调用, 速度很快;
2, EJB可以同时提供本地(业务)接口和远程(业务)接口;
因为有可能被远程调用,也有可能被本地EJB调用;
本地业务接口用@Local
远程业务接口用@Remote
方式一:
使用缺省的JNDI的上下文进行查找;
JNDI服务器就在应用服务器里面, 不需要提供JNDI的服务器入口的信息;
Context ctx=new InitialContext();
(EJBRemote)ctx.lookup(EJBRemote.class)
方式二: 首选的方式
使用EJB标注进行注入;@EJB TaxRate tr; (业务接口,可以是本地的也可以是远程的)
1) @EJB(name="ejbref") (远程的)
需要在配置文件中配置;在sun-ejb-jar.xml中;
ejb-ref配置
ejb-ref-name : ejbref
jndi-name: 被调用的EJB的jndi的名字
2) @EJB用在类前:
@EJB(name="ejbref",beanInterface=EJBRemote.class)
@PostConstruct方法中找到ejbref;
@SessionContext sctx;
sctx.lookup("ejbref");
使用EJBContext(父接口)来查找;
是一个EJB上下文对象, 提供我们的EJB与容器进行交互的方法;
对于会话bean : SessionContext ; 提供给会话bean的上下文;
实体Bean: EntityContext(不用了), 提供给实体bean的EJB上下文;
消息驱动Bean: MessageDrivenContext; 提供给消息驱动bean的上下文;
EJB上下文是由容器生成的, 使用依赖注入机制 @Resource , 注入到相应的bean中;
API: getCallerPrincipal() ; 得到一个身份;
3) @EJB注入本地接口,直接使用
@EJB
private EJBLocal el;
EJB调用同在一个JVM中(在一个容器中)运行的其他EJB, 用本地接口,减少RMI-IIOP所带来的性能的损失;
例子: chapter07
PriceBean : 默认绑定的是远程业务接口的全限命名;
如果实现了两个接口, 会用 "#"+远程接口的全限命名;
public interface TaxRate{
public double getTaxRate(String name);
}
@Stateless
@Remote(TaxRate.class)
public class TaxRateBean implements TaxRate{
public double getTaxRate(String name){
if(name.equals("bj")){
return 0.8
}
if(name.equals("sh")){
return 0.075;
}
return 0;
}
}
两个接口:
public interface PricerInjection {
public double getTaxInjection(double cost , String province);
}
public interface PricerLookup{
public double getTaxLookup(double cost , String province);
}
写一个bean, 实现两个接口;
@Stateless
@Remote({PricerInjection.class,PricerLookup.class })
public class PricerBean implements PricerInjection, PricerLookup{
@EJB(name="taxRate1")
TaxRate1 taxRate1; //通过注入得到; 需要配置文件;
TaxRate2 taxRate2; //通过JNDI得到;
public double getTaxInjection(double cost , String province){
return cost*taxRate1.getTaxRate(province);
}
public double getTaxLookup(double cost , String province){
return cost*taxRate2.getTaxRate(province);
}
@PostConstruct
public void postConstruct{
try {
Context ctx = new InitialContext();
taxRate2 = (TaxRate) ctx.lookup(TaxRate.class.getName());
} catch (NamingException ex) {
ex.printStackTrace();
}
}
}
taxRate1: 工程, 右键, 文件, sun部署文件, sun-ejb-jar.xml
使用xml进行配置;
@EJB
<enterprise-beans>
<ejb>
<ejb-name>PriceBean</ejb-name> <!-- 默认是类名, 在@Stateless(name="")可以改-->
<ejb-ref>
<ejb-ref-name>lab.mfunc.PriceBean/taxRate1</ejb-ref-name><!--默认是 包名.(bean)类名(PriceBean)/引用名(taxRate1) -->
<jndi-name>lab.mfunc.taxRate</jndi-name><!-- 远程接口的全限命名-->
</ejb-ref>
</ejb>
</enterprise-beans>
修改:
@EJB(name="taxRate1")
lab.mfunc.PriceBean/taxRate1 改成 taxRate1 即可;
EJB是组件, 1)业务接口,
2)Bean类; Bean类可以带上标注;
3)ejb-jar.xml(可选), 标准的部署描述文件; 与容器无关的信息; 业务接口,bean名字等等;
4)sun-ejb-jar.xml(可选), 厂商独有的部署文件;
用来配置依赖于容器的一些资源, 比如EJB的引用, Resource引用等等;
一起打jar包,部署在发布的目录下;
部署;写text类:
PricerInjection pi=(PricerInjection)ctx.lookup("#"+PricerInjection.class.getName());
PricerLookup pl=(PricerLookup)ctx.lookup("#"+PricerLookup.class.getName());
pi.getTaxInjection(1000, "sh");
pl.getTaxLookup(1000, "sh");
测试结果一样的话就对了;
例2: chapter07_2
LevelBean 本地接口和远程接口都实现;
LevelLocal
LevelRemote
{
public double getSarlary(int age){
return age*100;
}
}
本地接口和远程接口的方法可能不一样; 本地接口可能提供的方法多一点;
本地接口可以继承远程接口;
SalaryBean {//只实现远程接口;
@EJB
private LevelLocal levelRef; //因为实现了本地接口,所以不需要再配置文件;
double countSalary(double baseSarlary, double posotionSarlary, int age){
return (baseSarlary+posotionSarlary)*levelRef.getSarlary(age);
}
}
Test客户端测试;
改进 : IE -- > web容器(显示逻辑,接收请求, 流程控制) -- > EJB容器(业务逻辑) --> DB
servlet 调用 EJB ; 是远程调用; 两个容器, 跨进程调用;
新建一个web客户端应用; 在库中: 把EJB的jar包导进来;
countPrice.jsp
<font color="red" size="6">计算产品最终价格</font>
<form action="Constroller"><!-- 配置文件的url路径, 不加"/"表示是相对路径 -->
<table>
<tr>
<td>产品价格:</td> <td><input type="text" name="price"></td>
</tr>
<tr>
<td>省份:</td> <td><input type="text" name="province"></td>
</tr>
<tr>
<td colspan="2"> <td><input type="submit" name="确认"></td>
</tr>
</table>
</form>
在源包中建一个servlet ; Constroller
@EJB
private PricerInjection pi;
processRequest{
String province = request.getParameter("province");
String priceStr=request.getParameter("price");
double price=Double.parseDouble(priceStr);
double rst=pi.getTaxInjection(price,province);
request.setAttribute("rst",rst);
request.getRequestDispatcher("/rst.jsp").forward(request,response);
}
另一个页面: rst.jsp
最终价格: ${rst}
部署web项目;
在ie浏览器上运行: 端口号查, http-service; http-listener: 8080
http://localhost:8080/chapter07_client/countPrice.jsp
注:
将chapter07的 PricerBean 改为:
@Remote(PricerInjection.class)//只实现一个接口,怕带#号找不到;
JVM1 --- --- --- --- --- JVM2
两个EJB运行在一个进程中, 就通过本地接口调用;
1, EJB调用同一个JVM中运行的另一个EJB, 要使用本地接口;
可以避免使用远程接口中,必须要处理网络调用带来的性能的损失;(Stub, Skeleton)
使用RMI-IIOP协议;
本地接口直接使用引用来进行调用, 速度很快;
2, EJB可以同时提供本地(业务)接口和远程(业务)接口;
因为有可能被远程调用,也有可能被本地EJB调用;
本地业务接口用@Local
远程业务接口用@Remote
方式一:
使用缺省的JNDI的上下文进行查找;
JNDI服务器就在应用服务器里面, 不需要提供JNDI的服务器入口的信息;
Context ctx=new InitialContext();
(EJBRemote)ctx.lookup(EJBRemote.class)
方式二: 首选的方式
使用EJB标注进行注入;@EJB TaxRate tr; (业务接口,可以是本地的也可以是远程的)
1) @EJB(name="ejbref") (远程的)
需要在配置文件中配置;在sun-ejb-jar.xml中;
ejb-ref配置
ejb-ref-name : ejbref
jndi-name: 被调用的EJB的jndi的名字
2) @EJB用在类前:
@EJB(name="ejbref",beanInterface=EJBRemote.class)
@PostConstruct方法中找到ejbref;
@SessionContext sctx;
sctx.lookup("ejbref");
使用EJBContext(父接口)来查找;
是一个EJB上下文对象, 提供我们的EJB与容器进行交互的方法;
对于会话bean : SessionContext ; 提供给会话bean的上下文;
实体Bean: EntityContext(不用了), 提供给实体bean的EJB上下文;
消息驱动Bean: MessageDrivenContext; 提供给消息驱动bean的上下文;
EJB上下文是由容器生成的, 使用依赖注入机制 @Resource , 注入到相应的bean中;
API: getCallerPrincipal() ; 得到一个身份;
3) @EJB注入本地接口,直接使用
@EJB
private EJBLocal el;
EJB调用同在一个JVM中(在一个容器中)运行的其他EJB, 用本地接口,减少RMI-IIOP所带来的性能的损失;
例子: chapter07
PriceBean : 默认绑定的是远程业务接口的全限命名;
如果实现了两个接口, 会用 "#"+远程接口的全限命名;
public interface TaxRate{
public double getTaxRate(String name);
}
@Stateless
@Remote(TaxRate.class)
public class TaxRateBean implements TaxRate{
public double getTaxRate(String name){
if(name.equals("bj")){
return 0.8
}
if(name.equals("sh")){
return 0.075;
}
return 0;
}
}
两个接口:
public interface PricerInjection {
public double getTaxInjection(double cost , String province);
}
public interface PricerLookup{
public double getTaxLookup(double cost , String province);
}
写一个bean, 实现两个接口;
@Stateless
@Remote({PricerInjection.class,PricerLookup.class })
public class PricerBean implements PricerInjection, PricerLookup{
@EJB(name="taxRate1")
TaxRate1 taxRate1; //通过注入得到; 需要配置文件;
TaxRate2 taxRate2; //通过JNDI得到;
public double getTaxInjection(double cost , String province){
return cost*taxRate1.getTaxRate(province);
}
public double getTaxLookup(double cost , String province){
return cost*taxRate2.getTaxRate(province);
}
@PostConstruct
public void postConstruct{
try {
Context ctx = new InitialContext();
taxRate2 = (TaxRate) ctx.lookup(TaxRate.class.getName());
} catch (NamingException ex) {
ex.printStackTrace();
}
}
}
taxRate1: 工程, 右键, 文件, sun部署文件, sun-ejb-jar.xml
使用xml进行配置;
@EJB
<enterprise-beans>
<ejb>
<ejb-name>PriceBean</ejb-name> <!-- 默认是类名, 在@Stateless(name="")可以改-->
<ejb-ref>
<ejb-ref-name>lab.mfunc.PriceBean/taxRate1</ejb-ref-name><!--默认是 包名.(bean)类名(PriceBean)/引用名(taxRate1) -->
<jndi-name>lab.mfunc.taxRate</jndi-name><!-- 远程接口的全限命名-->
</ejb-ref>
</ejb>
</enterprise-beans>
修改:
@EJB(name="taxRate1")
lab.mfunc.PriceBean/taxRate1 改成 taxRate1 即可;
EJB是组件, 1)业务接口,
2)Bean类; Bean类可以带上标注;
3)ejb-jar.xml(可选), 标准的部署描述文件; 与容器无关的信息; 业务接口,bean名字等等;
4)sun-ejb-jar.xml(可选), 厂商独有的部署文件;
用来配置依赖于容器的一些资源, 比如EJB的引用, Resource引用等等;
一起打jar包,部署在发布的目录下;
部署;写text类:
PricerInjection pi=(PricerInjection)ctx.lookup("#"+PricerInjection.class.getName());
PricerLookup pl=(PricerLookup)ctx.lookup("#"+PricerLookup.class.getName());
pi.getTaxInjection(1000, "sh");
pl.getTaxLookup(1000, "sh");
测试结果一样的话就对了;
例2: chapter07_2
LevelBean 本地接口和远程接口都实现;
LevelLocal
LevelRemote
{
public double getSarlary(int age){
return age*100;
}
}
本地接口和远程接口的方法可能不一样; 本地接口可能提供的方法多一点;
本地接口可以继承远程接口;
SalaryBean {//只实现远程接口;
@EJB
private LevelLocal levelRef; //因为实现了本地接口,所以不需要再配置文件;
double countSalary(double baseSarlary, double posotionSarlary, int age){
return (baseSarlary+posotionSarlary)*levelRef.getSarlary(age);
}
}
Test客户端测试;
改进 : IE -- > web容器(显示逻辑,接收请求, 流程控制) -- > EJB容器(业务逻辑) --> DB
servlet 调用 EJB ; 是远程调用; 两个容器, 跨进程调用;
新建一个web客户端应用; 在库中: 把EJB的jar包导进来;
countPrice.jsp
<font color="red" size="6">计算产品最终价格</font>
<form action="Constroller"><!-- 配置文件的url路径, 不加"/"表示是相对路径 -->
<table>
<tr>
<td>产品价格:</td> <td><input type="text" name="price"></td>
</tr>
<tr>
<td>省份:</td> <td><input type="text" name="province"></td>
</tr>
<tr>
<td colspan="2"> <td><input type="submit" name="确认"></td>
</tr>
</table>
</form>
在源包中建一个servlet ; Constroller
@EJB
private PricerInjection pi;
processRequest{
String province = request.getParameter("province");
String priceStr=request.getParameter("price");
double price=Double.parseDouble(priceStr);
double rst=pi.getTaxInjection(price,province);
request.setAttribute("rst",rst);
request.getRequestDispatcher("/rst.jsp").forward(request,response);
}
另一个页面: rst.jsp
最终价格: ${rst}
部署web项目;
在ie浏览器上运行: 端口号查, http-service; http-listener: 8080
http://localhost:8080/chapter07_client/countPrice.jsp
注:
将chapter07的 PricerBean 改为:
@Remote(PricerInjection.class)//只实现一个接口,怕带#号找不到;