EJB的相互调用

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)//只实现一个接口,怕带#号找不到;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值