EJB3.0(一)

EJB3.0

基本概念:

1.ejb的背景(什么是分布式的应用程序?分布式面临的问题?)

2.什么是javaee?

3.什么是ejb?有什么用?

4.ejb为什么用java来写?

5.什么是服务?

 

ejb的背景(什么是分布式的应用程序?分布式面临的问题?):

JAVAEE服务器和容器:

分布式多层应用图:

我们说的企业级应用就是分布式应用,什么是分布式应用?

client1   client2  client3

     |        |        |

  server         server

        /          /

           data

多个客户端访问多个服务器,多个服务器访问公共数据库,应用程序分布在多台服务器上,他们共同完成一个目标,以往用的是Host/Terminal,所有的程序在一个服务器上,这样做的问题是服务器端的压力过大,Client/Server方式解决了这个问题,它将程序的一部分写在了客户端但是,问题是升级维护比较麻烦,采用分布式的B/S架构解决了这个问题,它可以设置多个服务器,然后由程序将用户的请求分流给各个服务器,各个服务器之间互相访问,并且各个服务器的系统可能是异构的系统,这样一是减轻了服务器的压力,也解决了维护不便的问题

 

分布式面临的问题:

1.远程方法调用

2.群集系统:考虑给各个服务器分配请求平衡的问题

3.事务问题:如何控制事务,事务传输问题,分布式事务问题

4.动态的重新部署:系统升级不影响已在使用中的客户

5.超市下班问题:超市下班对进入关闭,但是正在购物的客户还可以选购

6.组件生命周期管理...等等

这些问题说明了分布式程序的复杂性

 

什么是javaee:

企业应用中需要的各个服务组件的集合:web组件,业务组件,邮件服务,命名服务等

 

什么是ejb?有什么用?

我们知道企业级应用=分布式应用,分布式应用有很多要考虑的问题,这些问题比较复杂,所以将不变的做成中间件服务器(),也就是ejb容器(sun公司的产品)将变的做成业务组件(),通过一系列配置,完成业务逻辑,EJB定义了业务组件和中间件的标准(规范,开发流程),组件框架,主要做业务开发,一些分布式程序产生的问题不需要考虑,开发人员只需要根据ejb规范开发业务逻辑就可以了,这些问题由ejb容器负责

作用:统一的标准(ejb容器),快速应用开发

 

ejb为什么用java来写?

java本身的特性呼应:接口实现分离,安全

 

什么是服务?

服务:数据的交换,例如:请求资源数据到服务器,服务器中的服务接收并返回数据

 

第一个ejb:

1.开发步骤

1.手工方式

2.使用IDE工具方式

 

开发步骤:

1.安装javaee jdk

2.安装服务器(我们使用的是sun服务器)

3.创建domain()

4.设置classpath,配置jarappserv-rt and javaee.jar 这两个包在服务器中

5.启动服务器

6.创建ejb模块

7.一个远程接口,一个包含远程方法的bean

8.编译,打包 将这个ejb模块打包

9.部署到域中的autodeploy目录下

10.写客户端调用这个远程方法

 

手工方式:

创建域:

假定你的宿主目录是/home/soft01/ , 新建domain domain2  x:/home/soft01/自己定义一个域的目录

$ /opt/SUNWappserver/bin/asadmin  create-domain --domaindir /home/soft01/sundomains --adminport

4848 domain2

asadmin  create-domain --domaindir f:/ejb --adminport 4848 domain

输入管理员用户名>admin

输入管理员密码>adminadmin

再次输入管理员密码>adminadmin

输入主密码>adminadmin

 

创建ejb模块:

1 准备CLASSPATH

     $export CLASSPATH=.:/opt/SUNWappserver/lib/appserv-rt.jar:/opt/SUNWappserver/lib/javaee.jar

2 启动server(假定你的domain domain2 ,domain 目录是/home/soft01/sundomains/)

     $ /opt/SUNWappserver/bin/asadmin start-domain --domaindir /home/soft01/sundomains domain2

     输入主密码>adminadmin

asadmin start-domain --domaindir F:/ejb domain

3 创建一个ejb模块目录:

     $mkdir ~/myejbs

4 myejbs目录中创建包first

     $cd myejbs

     $mkdir first

5 first 目录中创建两个java 文件

     $cd first

     $touch HelloBean.java  HelloRemote.java:暴露bean中的远程方法,要想调用一个远程方法,必须有一个暴露接口去暴露这个方法

     _________________________________________

     package yuchen.first;

     /*

      * @Remote:说明这个接口是远程接口

      * 如果想调用远程类中的远程方法,必须提供一个远程的接口

      * 而且要写抽象的远程方法

     */

     import javax.ejb.*;

 

     @Remote

     public interface HelloRemote {

         String sayHello(String user);

     }

     __________________________________________

     package yuchen.first;

     /*

 @Stateless:说明这个bean类是远程的beanBean类,Bean类即可以实现商业接口,也可以不实现,但是其中的方法签名要和接口中相同,不过最好还是实现商业接口避免书写错误

      */

     import javax.ejb.*;

 

     @Stateless

     public class HelloBean implements HelloRemote {

         public String sayHello(String user) {

              return "hello , " + user;

         }

     }

     __________________________________________

6 编译,打包 将这个ejb模块打包

     $cd ..  (确保pwd/home/soft01/myejbs)

     $javac first/*.java

     $jar cvf HelloEJB.jar .

     jar cvf HelloEJB.jar .

7 部署

     cp HelloEJB.jar /home/soft01/sundomains/domain2/autodeploy/

    

     :包含javaee服务配置的集合

 

8 写一个客户端测试ejb:调用远程方法

 

     Test.java

     ------------------------------------------

     /*

      * 程序目标:调用远程方法,输出一些字符串

      */

     package yuchen.first;

     import javax.naming.*;

     import yuchen.first.*;

 

     public class Test {

         public static void main(String[] args) throws Exception {

              Context context = new InitialContext();

              HelloRemote hello = (HelloRemote) context.lookup(HelloRemote.class

                   .getName());

              System.out.println(hello.sayHello("yuchen"));

         }

     }

 

     ------------------------------------------

9 编译,运行

 

使用IDE工具方式:

1.打开NetBeans,创建ejb容器:Runtime->Servers->”add”,域设置(4个选项)

注意端口: ORB listener Port (3700) Https Port (8181)

2.创建ejb模块,写接口and实现类

3.倒入包到ejb模块中

4.打包,Deploy Projects

5.创建客户端工程,写测试类,需要倒入ejb模块的jar

6.运行客户端文件

 

ejb分布式远程方法调用的原理?

面向对象的远程方法调用都是通过代理模式实现的

什么是代理模式?有什么用?

客户端定义的接口和远程接口的一样,那么它的作用是什么呢?

接口的实现对象哪来的?

是通过jndi查询从远程服务器上获得的,用客户端接口引用它

这个对象是不是就是远程bean类的对象呢?

不是,而是bean的远程代理

什么是bean的远程代理?有什么用?

bean一样,都实现了接口,当客户端调用远程代理对象的实现方法的时候,它去做网络连接,传递参数和返回值,做序列化和反序列化

客户端—Jndi查询到服务器的bean,容器创建的远程代理对象(存根)----服务端代理对象(骨架)—service服务对象(请求拦截器)—服务端的bean :代理对象的一系列操作流程是不变的,这些是由应用服务器实现,业务组件,也就是bean是变化的,由程序员来开发

服务对象拦截客户端装载一系列服务,如事务,安全等,这些都是不可见的,是应用服务器实现,那么服务器如何知道哪个方法需要哪些服务呢?标注,部署描述符加载服务

存根是服务对象的代理,服务对象是bean的代理

 

使用web调用一个ejb:

1.MVC方式:

2.MVC方式:

MVC方式:

程序目标:在浏览器端输入盘符,服务端将该盘符中的内容显示给用户

web:index.jsp

<%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>

<%@ page import="javax.naming.*,session.*" %>

 

 

<!DOCTYPE HTML PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN"

   "http://www.w3.org/TR/html4/loose.dtd">

 

<html>

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

        <title>JSP Page</title>

    </head>

    <body>

    <%!

        ListRemote lr;

        public void jspInit(){

            try{

            Context context=new InitialContext();

                lr=(ListRemote)context.lookup(ListRemote.class.getName());

            }catch(Exception e){

                e.printStackTrace();

            }

           

        }

    %>

    <form method="get" action="index.jsp">

        <input type="text" name="path" /><br>

        <input type="submit" value="list"  />

    </form>

        <%

            String rst="";

            String path=request.getParameter("path");

            if(path!=null){

               rst=lr.list(path);

            }

           

        %>

       

        <%=path%>:<br><%=rst%>

    </body>

</html>

 

ejb remote:

package session;

 

import javax.ejb.Remote;

 

/**

 *

 * @author yuchen

 */

@Remote

public interface ListRemote {

    public String list(String path);

}

 

ejb bean:

package session;

 

import java.io.File;

import javax.ejb.Stateless;

 

/**

 *

 * @author yuchen

 */

@Stateless

public class ListBean implements session.ListRemote {

   

    /** Creates a new instance of ListBean */

    public ListBean() {

    }

 

    public String list(String path) {

        File file=new File(path);

        if(!file.isDirectory()){

            return "meiyou";

        }

        String[] f=file.list();

        String rst="";

        for(String s:f){

            rst+=s+"<br>";

        }

        return rst;

    }

   

}

 

MVC方式:

web index.jsp:

<%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>

 

 

<!DOCTYPE HTML PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN"

   "http://www.w3.org/TR/html4/loose.dtd">

 

<html>

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

        <title>JSP Page</title>

    </head>

    <body>

 

    <h1>JSP Page</h1>

        <form action="list.do" method="post">

            <input type="text" name="path" />

            <input type="submit" value="list" />

        </form>

    </body>

</html>

 

web view.jsp:

<%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>

 

<!DOCTYPE HTML PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN"

   "http://www.w3.org/TR/html4/loose.dtd">

 

<html>

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

        <title>JSP Page</title>

    </head>

    <body>

 

    <h1>JSP Page</h1>

    <%

        String view=(String)request.getAttribute("view");

    %>

    ${view}

    </body>

</html>

 

web servlet:

package controller;

 

import java.io.*;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

import javax.servlet.*;

import javax.servlet.http.*;

import session.ListRemote;

 

/**

 *

 * @author yuchen

 * @version

 */

public class NewServlet extends HttpServlet {

   

    /** Processes requests for both HTTP <code>GET</code> and

<code>POST</code> methods.

     * @param request servlet request

     * @param response servlet response

     */

    ListRemote lr;

    public void init(){

       

        try {

            Context context=new InitialContext();

            lr=(ListRemote)context.lookup(ListRemote.class.getName());

        } catch (NamingException ex) {

            ex.printStackTrace();

        }

    }

    protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

    throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        String path=request.getParameter("path");

        String rst=lr.list(path);

        request.setAttribute("view",rst);

        RequestDispatcher rd=request.getRequestDispatcher("view.jsp");

        rd.forward(request,response);

    }

   

    protected void doGet(HttpServletRequest request, HttpServletResponse

response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

   

 

    protected void doPost(HttpServletRequest request, HttpServletResponse

response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

   

 

    public String getServletInfo() {

        return "Short description";

    }

 

}

 

web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <servlet>

        <servlet-name>NewServlet</servlet-name>

        <servlet-class>controller.NewServlet</servlet-class>

    </servlet>

    <servlet-mapping>

        <servlet-name>NewServlet</servlet-name>

        <url-pattern>*.do</url-pattern>

    </servlet-mapping>

    <session-config>

        <session-timeout>

            30

        </session-timeout>

    </session-config>

    <welcome-file-list>

     <welcome-file>

            index.jsp

        </welcome-file>

    </welcome-file-list>

</web-app>

 

ejb:使用上面的ejb

 

SessionBean

1.什么是sessionBean?有状态?无状态?

2.sessionbean生命周期?

3.会话bean实例池

4.有状态会话bean的实例池

5.两种bean之间的区别

6.三种方法实现生命周期回调方法(将回调方法写到bean 单独写一个类 部署描述符)

 

什么是sessionbean:

Sessionbean和其他企业bean的区别在于生命周期,SessionBean分为有状态的sessionbean和无状态的sessionbean,sessionbean的作用就是处理客户请求做业务处理的,:订单登陆,数据库操作等

 

ejb中的sessionbean和普通的javabean的区别是什么?

Javabean不支持远程方法调用,所以用javabean做业务逻辑组件在分布式应用中是不行的,所以需要写支持分布式的sessionbean

 

会话bean实例池:

由于会话bean可能占用大量的资源,并且经常会使用,所以做个池来维护这些实例,作用就是提高效率,这个池相当于计算机的缓存一样,在计算机中cpu为了提高效率,往往会使用它,这比cpu访问内存和硬盘的速度快很多

 

sessionbean生命周期:

客户调用sessionbean的方法,ejb容器创建sessionbean实例,当客户不再使用了,容器

放回到会话池中,客户也可以显示调用@Remove方法销毁该实例,一般情况下,一个客户的持续期间为sessionbean的存活期,多用户不能同时使用一个sessionbean,sessionbean是服务完一个再去服务其他的客户

 

用户会话的持续期:

1.打开浏览器到关闭浏览器

2.java applet

3.一个java应用等等

这些期间为用户的会话的持续期

 

什么是无状态sessionbean:

如果客户端只有一个请求就能够完成业务需求,并且不需要保存各种信息,那么就使用

无状态bean,特点是不存在会话状态,注意,一个bean的实例可能会服务多个客户

所以实例池中的bean都可以重用,所以ejb容器不用考虑多请求之间需要保存的资源

 

什么是有状态sessionbean:

不能在客户间共享,与客户是一对一的

当在做购物车等功能的时候,在多个请求之间需要保存客户的资源,这个时候可以使用

有状态的sessionbean实现,他跟踪每个客户的状态

 

有状态的实例池:

客户端调用bean的方法容器实例化实例池并取得一个bean实例--如果此时另一个客户调用该bean,并且池中已经没有实例了,那么容器将最近最少使用的那个bean实例的会话状态挂起然后得到该实例为客户使用当第一个客户再次调用的时候,容器从二级存储源中读取该用户被挂起的状态,得到一个实例

当挂起的时候:将状态信息序列化到硬盘中,而挂起的那个bean实例还可以服务其他的

调用者

注意,当再次得到bean的时候,不一定是原来的那个对象,ejb容器将bean挂起的时候,

容器会把bean对象的状态保存到硬盘中,再次激活的时候,会得到这个状态

 

激活和挂起:

考虑一个问题:客户的数量无限,而内存有限,怎么办?也就是说有1000个客户访问,但是你的服务器只能存储100个实例,这样如何处理?

比如:有五个客户,但是实例池中只有4,那么容器会将最近最少使用的那个bean实例

挂起,就是说将bean实例的会话状态存储到二级存储源中,也就是硬盘上或者是数据库

中等,例如购物车,容器将购物车中的商品信息存到硬盘上,然后这个实例可以服务第五个

客户了,如果被挂起的那个客户又要使用自己的购物车了,那么再挂起其他的实例,然后激活自己的状态到内存中

例如:实例池中有两个bean实例,现在有三个客户访问,第一个和第二个得到实例并进行操作,然后第三个访问到来,发现池中没有实例了,这个时候将其中的一个实例的会话状态保存到二级存储源中,然后再为第三个用户使用,当那个失去实例的用户需要再次调用bean实例的时候,容器会激活,并读取以前保存的会话状态

挂起:当出现实例阻塞的时候发生,也就是我要使用bean,发现池中没有了

激活:当用户再次访问业务方法的时候,激活被挂起的状态

 

状态不能被挂起的情况:

1.bean中的成员变量为transient类型的对象(标注为transient的类型)

2.容器帮助维护状态的成员变量(也不能序列化):本地或远程引用,上下文,SessionContext,UserTransaction,EntityManager,EntityManagerFactory,Timer

 

激活和挂起的回调方法:

我们知道数据库连接不能被序列化,那么像这样的资源容器如何处理呢?

容器定义了回调方法,这些方法的作用就是用来释放和获得资源的

@PrePassivate:在挂起bean实例前调用,一般用来释放数据库连接等资源

@PostActivate:激活,当激活bean实例后调用它,可以获得数据库连接等资源

 

有状态的sessionbean和无状态的sessionbean的区别:

看业务要求需不需在要跨方法,跨请求时保存会话状态:

什么叫跨方法?指调用不同的方法,如果方法之间需要另一个方法的执行结果,那么需要保存这个结果数据,这时使用有状态的sessionbean

什么叫跨请求:指多次调用同一个方法,调用后如果需要保存一些数据,那么就使用有状态的会话bean,这些数据就是会话的状态

:业务需要当调用一个方法的时候输出一句话,没有数据要保存,使用无状态会话bean

购物车,当每次点添加商品的时候(跨请求),购物车对象的内容都不一样,这些内容在每次添加商品方法调用的时候都需要保存,所以使用有状态会话bean

有状态会话bean通过属性来保存会话状态

无状态的会话bean可以更有效率的被客户重用,因为不需要激活挂起会话状态信息

 

无状态实例:

 

接口:

 

package Stateless;

 

import javax.ejb.Remote;

 

 

/**

 * This is the business interface for StatefulSession enterprise bean.

 */

@Remote

public interface StatelessSessionRemote {

    public int count();

    public void setval(int val);

    public void remove();

}

 

sessionbean:

/*

 * StatefulSessionBean.java

 *

 * Created on 2007 5 14 , 上午10:44

 *

 * To change this template, choose Tools | Template Manager

 * and open the template in the editor.

 */

 

package Stateless;

 

import javax.ejb.Remote;

import javax.ejb.Remove;

import javax.ejb.Stateless;

import javax.interceptor.Interceptors;

 

/**

 *

 * @author yuchen

 */

@Stateless

@Interceptors(CountCallbacks.class)

public class StatelessSessionBean implements StatelessSessionRemote {

   

    /** Creates a new instance of StatefulSessionBean */

    private int val;

    public StatelessSessionBean() {

       

    }

 

    public int count() {

        System.out.println("count...");

        return ++val;

    }

 

    public void setval(int val) {

        this.val=val;

        System.out.println("setval...");

    }

   

    @Remove

    public void remove() {

       System.out.println("remove...");

    }

   

}

 

生命周期回调:

 

package Stateless;

 

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.ejb.PostActivate;

import javax.ejb.PrePassivate;

import javax.interceptor.InvocationContext;

 

/**

 *

 * @author yuchen

 */

public class CountCallbacks {

   

    /** Creates a new instance of CountCallbacks */

    public CountCallbacks() {

       

    }

   

    //创建ejb实例后调用

    @PostConstruct

    public void construct(InvocationContext ctx) throws Exception{

        System.out.println("创建ejb实例后调用");

        ctx.proceed();

    }

   

    //激活ejb实例后调用

    @PostActivate

    public void activate(InvocationContext ctx) throws Exception{

        System.out.println("激活ejb实例后调用");

        ctx.proceed();

    }

   

    //挂起前调用

    @PrePassivate

    public void passivate(InvocationContext ctx) throws Exception{

        System.out.println("挂起前调用");

        ctx.proceed();

    }

   

    //销毁前调用

    @PreDestroy

    public void destroy(InvocationContext ctx) throws Exception{

        System.out.println("销毁前调用");

        ctx.proceed();

    }

}

 

打包

 

测试端:

 

倒入ejb,需要使用包中的接口

package teststatelesssessionbean;

 

import Stateless.StatelessSessionRemote;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

 

 

/**

 *

 * @author yuchen

 */

public class Main {

   

    /** Creates a new instance of Main */

    public Main () {

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) throws NamingException,

InterruptedException {

        // TODO code application logic here

       Context context=new InitialContext();

       //创建一个stateless sessionbean的实例

       StatelessSessionRemote remote =(StatelessSessionRemote)

context.lookup(StatelessSessionRemote.class.getName());

       remote.setval(0);

       //将属性加一

       int var=remote.count();

       System.out.println(var);

       //再加一

       var=remote.count();

       System.out.println(var);

       remote.setval(0);

      

       System.out.println("创建三个实例");

       StatelessSessionRemote [] rem=new StatelessSessionRemote[2];

       for(int i=0;i<rem.length;i++){

            rem[i]=(StatelessSessionRemote) context.lookup

(StatelessSessionRemote.class.getName());

            System.out.println(rem[i].count());

            Thread.sleep(500);

       }

      

       for(int i=0;i<rem.length;i++){

           System.out.println(rem[i].count());

           Thread.sleep(100);

       }

    }

   

}

 

无状态实例二:

程序目标:测试无状态会话bean的生命周期,bean类中写回调方法

Remote接口:

package lifecycle;

 

import javax.ejb.Remote;

import javax.ejb.Remove;

 

 

/**

 * This is the business interface for Lifecycle enterprise bean.

 */

@Remote

public interface LifecycleRemote {

    public int add(int a,int b);

 

@Remove

void remove();

}

 

bean:

package lifecycle;

 

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.ejb.Remove;

import javax.ejb.Stateless;

 

/**

 *

 * @author yuchen

 */

@Stateless

public class LifecycleBean implements lifecycle.LifecycleRemote {

   

    /** Creates a new instance of LifecycleBean */

    public LifecycleBean() {

    }

 

    //回调方法,先调用bean的构造方法,然后是依赖注入,再调用此方法

    @PostConstruct

    public void postinit(){

        System.out.println("init");

    }

    //bean实例销毁前调用此方法

    @PreDestroy

    public void destroy(){

        System.out.println("destroy");

    }

    public int add(int a, int b) {

        return a+b;

    }

    @Remove

    public void remove(){

        System.out.println("delete...");

    }

}

 

client:

public class Main {

   

    /** Creates a new instance of Main */

    public Main () {

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) throws NamingException {

        // TODO code application logic here

        Context context=new InitialContext();

        LifecycleRemote remote= (LifecycleRemote) context.lookup

(LifecycleRemote.class.getName());

        int str=remote.add(15,20);

        System.out.println(str);

        remote.remove();

    }

   

}

 

调用结果:init delete...

为什么没有调用@PreDestroy标注的方法呢?

因为容器在客户调用完此方法的时候并没有销毁该对象,只是将这个实例放回到了实例

池中,供下次调用使用

 

无状态实例三:

程序目标:测试生命周期,使用单独得类写生命周期拦截类

Remote接口:

 

package session;

 

import javax.ejb.Remote;

 

 

/**

 * This is the business interface for statelessbean enterprise bean.

 */

@Remote

public interface statelessbeanRemote {

    public int add(int a,int b);

}

 

bean:

package session;

 

import javax.ejb.Stateless;

import javax.interceptor.Interceptors;

 

/**

 *

 * @author yuchen

 */

@Stateless

@Interceptors(lifecycle.class) 

public class statelessbeanBean implements session.statelessbeanRemote {

   

    /** Creates a new instance of statelessbeanBean */

    public statelessbeanBean() {

        System.out.println("构造方法");

    }

 

    public int add(int a, int b) {

        return a+b;

    }

   

}

 

回调方法类:

package session;

 

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.interceptor.InvocationContext;

 

/**

 *

 * @author yuchen

 */

public class lifecycle {

   

    /** Creates a new instance of lifecycle */

    public lifecycle() {

       

    }

   

        //创建ejb实例后调用

    @PostConstruct

    public void construct(InvocationContext ctx) throws Exception{

        System.out.println("创建ejb实例后调用");

        ctx.proceed();

    }

   

    @PreDestroy

    public void destroy(InvocationContext ctx) throws Exception{

        System.out.println("销毁前调用");

        ctx.proceed();

    }

}

 

client:

package testlifecycle2;

 

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import session.lifecycle;

import session.statelessbeanRemote;

 

/**

 *

 * @author yuchen

 */

public class Main {

   

    /** Creates a new instance of Main */

    public Main () {

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) throws NamingException {

        // TODO code application logic here

        Context context=new InitialContext();

        statelessbeanRemote sr=(statelessbeanRemote) context.lookup

(statelessbeanRemote.class.getName());

        System.out.println(sr.add(10,20));

    }

   

}

 

使用这个方式写回调方法有些区别:

1.在回调方法类中,回调方法需要有个参数,这个参数告诉这个类需要的bean对象的环境是什么

2.bean类中要用标注引用回调类

 

有状态实例:

 

接口:

 

package stateful;

 

import javax.ejb.Remote;

 

 

/**

 * This is the business interface for StatefulSession enterprise bean.

 */

@Remote

public interface StatefulSessionRemote {

    public int count();

    public void setval(int val);

    public void remove();

}

 

bean:

 

package stateful;

 

import javax.ejb.Remote;

import javax.ejb.Remove;

import javax.ejb.Stateful;

import javax.interceptor.Interceptors;

 

/**

 *

 * @author yuchen

 */

@Stateful

@Remote(StatefulSessionRemote.class)

@Interceptors(CountCallbacks.class)

public class StatefulSessionBean implements stateful.StatefulSessionRemote

{

   

    /** Creates a new instance of StatefulSessionBean */

    private int val;

    public StatefulSessionBean() {

       

    }

 

    public int count() {

        System.out.println("count...");

        return ++val;

    }

 

    public void setval(int val) {

        this.val=val;

        System.out.println("setval...");

    }

 

    @Remove

    public void remove() {

       System.out.println("remove...");

    }

   

}

 

回调:

 

package stateful;

 

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.ejb.PostActivate;

import javax.ejb.PrePassivate;

import javax.interceptor.InvocationContext;

 

/**

 *

 * @author yuchen

 */

public class CountCallbacks {

   

    /** Creates a new instance of CountCallbacks */

    public CountCallbacks() {

       

    }

   

    //创建ejb实例后调用

    @PostConstruct

    public void construct(InvocationContext ctx) throws Exception{

        System.out.println("创建ejb实例后调用");

        ctx.proceed();

    }

   

    //激活ejb实例后调用

    @PostActivate

    public void activate(InvocationContext ctx) throws Exception{

        System.out.println("激活ejb实例后调用");

        ctx.proceed();

    }

   

    //挂起前调用

    @PrePassivate

    public void passivate(InvocationContext ctx) throws Exception{

        System.out.println("挂起前调用");

        ctx.proceed();

    }

   

    //销毁前调用

    @PreDestroy

    public void destroy(InvocationContext ctx) throws Exception{

        System.out.println("销毁前调用");

        ctx.proceed();

    }

}

 

客户端类:

倒入ejb实例包

 

package testsessionful;

 

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import stateful.StatefulSessionRemote;

 

/**

 *

 * @author yuchen

 */

public class Main {

   

    /** Creates a new instance of Main */

    public Main () {

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) throws NamingException,

InterruptedException {

        // TODO code application logic here

        Context context=new InitialContext();

        //创建ejb实例,通过上下文得到ejb实例(这个实例是代理对象)

        //它去做网络连接,传递参数和返回值,做序列化和反序列化

        StatefulSessionRemote remote=(StatefulSessionRemote)

context.lookup(StatefulSessionRemote.class.getName());

        //调用代理对象的方法,网络连接到远程,并可能被拦截器加载一些服务

        remote.setval(0);

        int val=remote.count();

        //打印变量,val=1

        System.out.println(val);

       

        //再次调用:原来的val的值还保存着

        val=remote.count();

        //打印变量,val=2

        System.out.println(val);

        //再次设置为0

        remote.setval(0);

       

        System.out.println("创建三个实例,代表三个客户端,因为一个实例只服务

一个客户");

        StatefulSessionRemote[] rem=new StatefulSessionRemote[2];

        int var;

        for(int i=0;i<rem.length;i++){

            rem[i]=(StatefulSessionRemote) context.lookup

(StatefulSessionRemote.class.getName());

            var=rem[i].count();

            System.out.println(var);

            Thread.sleep(500);

        }

       

        System.out.println("证明");

        for(int i=0;i<rem.length;i++){

            var=rem[i].count();

            System.out.println(var);

            rem[i].remove();

            Thread.sleep(100);

           

        }

     

    }

   

}

 

 

基本概念()

1.ejb使用中间件服务的方式

2.什么是SOA?有什么用?

3.ejb的客户端类型

4.什么是web service?有什么用?

5.JavaEE技术多有哪些?

6.EJB的运行

 

ejb使用中间件服务的方式:

1.显式调用中间件服务:使用提供的服务API

2.隐式的调用中间件服务:使用标注和部署描述符

 

什么是SOA?有什么用?

系统A(应用:ERP 服务:C++)       系统B(应用:OA系统 服务:Java)

      

         SOA的目标就是将异构的系统集成,并实现互操作

 

这些系统就是服务,也就是将整个应用看成是服务,不是单个组件

什么是服务?服务就是数据的交换,比如:客户请求资源,服务器响应,给出数据,这是种服务,从程序的角度就是一些组件的集合,一个业务功能,一个完整的应用系统都可以看成是服务

那么,SOA的目标是将异构的服务集成并实现互操作

 

什么是web service?有什么用?

Web serviceSOA的实现,它真正实现了将异构的系统集成并互操作的想法,它采用的是xml语言定义的,所以能够实现各个语言开发的系统间的互操作

对整个服务如何集成呢?

两个问题:

1.需要对这个服务进行描述,也就是说这个服务提供了什么功能:公共接口WSDL(web服务描述语言)

2.如何调用这个服务:互操作协议

 

售货员(这是一个服务):

1.描述提供什么服务(公共接口):卖货的服务

2.如何使用这个服务(互操作协议):给钱

 

Ejb应用(服务):

1.描述该应用提供的服务:公共接口,就是远程接口,它暴露了bean的业务方法

2.如何使用这个服务:远程方法调用协议,基于internet的一个协议

 

ejb的客户端类型:

java应用 and web应用

 

JavaEE技术多有哪些?

Ejb

Jax-ws:javaweb服务定义的api

Rmi-iiop:远程对象访问协议

Jndi

Jdbc

Jta:java事务API,jts:java事务服务

JMS:java消息服务

Servlets

Jsp

Jsf

Jca

Jaxp

Jaxb:xml的邦定

Jaas:java认证和授权

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值