EJB3学习笔记_EJB纵览和webService

<ul>
<li>1、EJB是为了构建企业级的、分层的、分布式的应用标准,降低开发的复杂性。(包含以下一些问题)</li>
<li>Remote Method Invocations(远程方法调用)</li>
<li>Load Balancing(负载平衡)</li>
<li>Transparent Fail-over(错误感知、容错性,将一台有问题主机的服务或用户会话状态迁移到另一台)</li>
<li>Back-end Integration(后端系统集成,如数据库)</li>
<li>Transactions(事务)</li>
<li>Clustering(集群)</li>
<li>Dynamic Redeployment(动态部署)</li>
<li>Clean Shutdown(平稳关机,在最后一个用户退出后关机,保持当前用户用完退出,新用户不再进入)</li>
<li>Logging and Auditing</li>
<li>Systems Management</li>
<li>Threading</li>
<li>Message-oriented and Middleware</li>
<li>Component Life Cycle</li>
<li>Resource pooling</li>
<li>Security </li>
<li>Caching</li>
<li>...</li>
</ul>
<p>2、远程方法调用实现方式</p>
<ul>
<li>定义公共接口</li>
<li>本地方法从命名服务器中获得存根对象(命名服务器初始化时需要:a、命名服务器的驱动. b、网络信息)</li>
<li>存根对象调用方法,远程拦截器通过代理在方法前后插入中间件服务(事务安全等),再调用远程方法。(拦截器也实现了接口)</li>
<li>在同一个JVM中的调用为本地调用,在不同JVM中的未远程调用(用物理主机是否分隔无关)。</li>
</ul>
<p>3、中间件服务分显示和隐式两中</p>
<ul>
<li>显示的,比如自己声明事务边界,自己open,commit。</li>
<li>隐式的,同步部署描述符或标注,定制服务。</li>
</ul>
<p>4、SOA与EJB</p>
<ul>
<li>SOA抽象服务,功能的对外接口,一些列组件提供,抽象为数据交互,做到一般适用化。</li>
<li>SOA不关心是用什么语言实现,不关心用了多少组件,适用公共接口和互操作协议,达到异构平台的互操作。</li>
<li>EJB通过Web service来实现SOA。(corba也是一种SOA实现,但比较复杂)</li>
</ul>
<p>5、Web Service的主要技术</p>
<ul>
<li>SOAP:Simple Object Access Protocol.互操作协议。(必须)</li>
<li>WSDL:Web Service Description Language.类似于适用说明。(非必须)</li>
<li>都是通过XML文件来描述</li>
</ul>
<p>6、常用Java EE技术列表</p>
<ul>
<li>Enterprise JavaBeans(EJB)</li>
<li>Java API for Web Services(JAX-WS)提供Web服务的简单支持</li>
<li>The Web Services Metadata for the Java Platform</li>
<li>Java Remote Method Invocation(RMI) (远程方法调用)and RMI-IIOP(远程方法调用的互操作协议,EJB用这个,WebService用SOAP)</li>
<li>Java Naming and Directory Interface(JNDI)(适用命名协议的统一API)</li>
<li>Java Database Connectivity(JDBC)</li>
<li>Java Transaction API(JTA) and Java Transaction Service(JTS)(事务支持的服务)</li>
<li>Java Messaging Service(JMS)(异步应用,参考手机短信,由消息服务器提供,用户通过统一API调用)</li>
<li>Java Servlets</li>
<li>Java Server Pages(JSP)</li>
<li>Java Server Faces(JSF)</li>
<li>Java EE Connector Architecture(JCA)(与后端系统集成,规定后端系统需要实现的接口)</li>
<li>Java API for XML Parsing(JAXP)</li>
<li>Java Architecture for XML Binding(JAXB) </li>
<li>Java Authentication and Authorization(JAAS)(Java认证和授权服务)</li>
</ul>
<p>7、开发EJB的环境</p>
<ul>
<li>Java SE (basic libraries)</li>
<li>Java EE (Add-on libraries to support JSP/Servlets and EJB, Deploy tool ,Java EE serever)</li>
</ul>
<p>8、列子</p>
<p><textarea cols="92" rows="15" name="code" class="java:collapse">package first;
import javax.ejb.Remote;
@Remote
public interface HelloRemote{
  String sayHello(String user);
}

package first;
import javax.ejb.Stateliess;
//@Remote(HelloRemote.class) 可选的标注,如果写了这个标注,那实现接口可以不写
@Stateless
public class Hello implements HelloRemote{
  public String sayHello(String user){
    return "hello , " + user;
  }
}
//以上文件打包时需要jboss_ejb3x.jar,用来支持2个标注
//打包后拷贝到 jboss的deploy中.启动JBOSS

import javax.naming.*;
import first.HelloRemote;
public class HelloTest{
  public static void main(String[] args){
    System.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory")//这个驱动是jboss的.jar包是jbossall-client.jar
    System.setProperty(Context.PROVIDER_URL,"jnp://localhost");
    //如果主机名有问题,最方便的办法是将主机名改为IP地址 ,lunix下得命令为 hostname 192.168.0.21
    //可以在类路径下写一个jndi.properties,以key-value的方式生命参数,省去以上几步
    Context ctx = new InitialContext();
    /*
    Context ctx2= (Context)ctx.lookup("Hello");Hello是一个上下文
     HelloRemote hello =(HelloRemote)ctx2.lookup("remote");
     */
    HelloRemote hello=(HelloRemote)ctx.lookup("Hello/remote");
    String result = hello.sayHello("clat");
    System.out.println(result);
  }
}</textarea></p>
<p></p>
<p>9、查看Jboss上的EJB服务</p>
<ul>
<li>
<a href="http://localhost:8080/">http://localhost:8080/</a> -&gt; JMS Console -&gt; jboss-service=JNDIView -&gt; java.lang.String list() - invoke -&gt; 查找全局JNDI名字(Global JNDI Namespace)</li>
<li>一些JNDI是本地的,只供JBOSS内部访问</li>
</ul>
<p>10、EJB的类型</p>
<p></p>
<p>1)、Session bean : model business process,</p>
<ul>
<li>Stateful Session Bean</li>
</ul>
<p> Maintains state whici is encapsulated within the bean instance</p>
<p> Across multiple client requests</p>
<ul>
<li>Stateless Session Bean</li>
</ul>
<p></p>
<p>2)、Message-driven bean :similar to session bean, asynchronoous programming model.</p>
<p></p>
<p></p>
<p>3)、Entity bean: model business data.(已经用JPA代替)</p>
<ul>
<li>Has not been enhanced in EJB3.0</li>
<li>Will not be included in course</li>
<li>Uses Entity API instead</li>
</ul>
<p></p>
<p>11、Session Bean Subtypes</p>
<p></p>
<p>Stateless Session Beans</p>
<ul>
<li>Represent single request conversation</li>
<li>Need not to keep states across method invocations</li>
<li>Can be shared by multiple clients</li>
<li>单线程,共享的,容器会维护一个bean池。</li>
</ul>
<p>Stateful Session Beans</p>
<ul>
<li>Represent business process drawn-out conversations over several request</li>
<li>Designated to service business processes that span multip method request or transactions</li>
<li>Retain state on behalf of an individual client</li>
</ul>
<p>12、Stateless Session Bean声明周期</p>
<p>创建:</p>
<ul>
<li>newInstance()</li>
<li>dependency injection 依赖注入</li>
<li>调用@PostConstruct,类似初始化方法</li>
</ul>
<p>销毁</p>
<ul>
<li>@PreDestroy 销毁前的回调方法</li>
</ul>
<p>13、Stateful Session Bean 交换策略和生命周期</p>
<p></p>
<p>交换策略:当心的请求来临,当前stateful session bean已达到服务器的最大限制,就将不活动的bean钝化,序列化到磁盘上。</p>
<p> 当刚才不活动的用户活动时,再从容器中将刚才钝化的信息拿回来重新去找个不活动的bean相应请求。</p>
<p> (就是拆东墙补西墙)。</p>
<p></p>
<p>@PerPassivate:钝化前的回调方法。</p>
<p>@PostActivate: 反钝化后的回调方法。</p>
<p></p>
<p>钝化时序列化对象:(以下对象容器维护)</p>
<ul>
<li>非transient的原始类型</li>
<li>非transient的java对象</li>
<li>对其他bean的引用</li>
<li>SessionContext(EJB上下文),The UserTransaction(事务),EntityManager or EntityManagerFactory,or a Timer object(容器维护)</li>
<li>JNDI naming contexts</li>
</ul>
<p>不被序列化的对象:比如JDBC的连接connector等等,需要自己处理。</p>
<p></p>
<p>生命周期:</p>
<p>创建:</p>
<ul>
<li>newInstanse()</li>
<li>Dependency injection</li>
<li>@PostConstruct</li>
</ul>
<p>钝化和反钝化</p>
<ul>
<li>
<div>@PrePassivate</div>
</li>
<li>
<div>@PostActivate</div>
</li>
</ul>
<p>销毁</p>
<ul>
<li>
<div>@PreDestroy</div>
</li>
</ul>
<p>14、使用@Interceptors({xxx.class}) 定义生命周期回调的监听器</p>
<ul>
<li>定义4个回调方法</li>
<li>执行顺序:从外到内(优先实现类本身的),从左到右(定义的监听器)</li>
</ul>
<p>15、使用部署描述符 XML</p>
<p><textarea cols="81" rows="15" name="code" class="xhtml:collapse">&lt;enterprise-beans&gt;
  &lt;session&gt;
    &lt;ejb-name&gt;Counter&lt;/ejb-name&gt;
    &lt;business-remote&gt;chapter3.CounterRemote&lt;/business-remote&gt;
    &lt;ejb-class&gt;chapter3.Counter&lt;/ejb-class&gt;
    &lt;session-type&gt;Stateful&lt;/session-type&gt;
  &lt;/session&gt;
&lt;/enterprise-beans&gt;

&lt;interceptors&gt;
  &lt;interceptor&gt;
    &lt;interceptor-class&gt;chapter3.CounterCallback&lt;/interceptor-class&gt;
    &lt;post-construct&gt;
       &lt;lifecycle-callback-method&gt;postConstruct&lt;/lifecycle-callback-method&gt;
    &lt;/post-construct&gt;   
  &lt;/interceptor&gt;
  &lt;assembly-descriptor&gt;
    &lt;interceptor-binding&gt;
      &lt;ejb-name&gt;Counter&lt;/ejb-name&gt;
      &lt;interceptor-class&gt;chapter3.CounterCallback&lt;/interceptor-class&gt;
    &lt;/interceptor-binding&gt;
  &lt;/assembly-descriptor&gt;

&lt;/interceptors&gt;</textarea></p>
<p></p>
<p>部署描述符 可以覆盖 标注。(便于修改,而不用重新编译源代码)</p>
<p></p>
<p>16、 @Remove标注</p>
<p> 标注业务方法,客户自己调用,告诉容器,已经完成调用,可以移除此bean,而不是等会话超时。</p>
<p></p>
<p>17、通过System.setProterty()设置系统环境变量, 可以完成进程间通讯</p>
<p>或也可以再JVM启动时使用 -D设置环境变量。</p>
<p></p>
<p>18、编写Web Service 的两种方式</p>
<ol>
<li>先写java类,用容器生成wsdl</li>
<li>写wsdl,通过工具生成java类</li>
</ol>
<p>例子:</p>
<ul>
<li>编写一个java类,使用@WebService标注类</li>
</ul>
<p><textarea cols="64" rows="15" name="code" class="java">package ws;
import javax.jwx.WebService;

@WebService
public class Converter{
  @WebMethod/*添加了这个的方法才暴露为web服务,如果没有在任何方法上有此标注,则所有方法都暴露为web服务*/
  public double remToDollar(double rmb){
    return rmb*0.125;
  }
}

/*@WebService(targetNamespace="http://clat/ws",portName="ConverterPort",serviceName="ConverterService")
targetNamespace:命名空间
portName:端口名称,接口功能的实现(wsdl中有portType类似接口,影响存根对象的名字。)
serviceName:决定服务名 , port的工厂。

*/</textarea></p>
<ul>
<li>在web.xml中作为servlet 标注映射关系, 部署在容器中(如jboss)</li>
</ul>
<p><textarea cols="50" rows="15" name="code" class="xhtml:collapse">&lt;servlet&gt;
  &lt;servlet-name&gt;Converter&lt;/servlet-name&gt;
  &lt;servlet-class&gt;ws.Converter&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
  &lt;servlet-name&gt;Converter&lt;/servlet-name&gt;
  &lt;url-pattern&gt;/Converter/&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</textarea></p>
<ul>
<li>使用工具生成JAVA类。在JBOSS中<a href="http://localhost:8080/jbossws/">http://localhost:8080/jbossws/</a>-&gt; View a list of deployed services -&gt; 找到服务端点地址(<a href="http://tarena-teacher:8080/sd10702-web/Converter?wsdl">http://tarena-teacher:8080/sd10702-web/Converter?wsdl</a>)</li>
</ul>
<p> jboss/bin/wsconsume.bat <a href="http://tarena-teacher:8080/sd10702-web/Converter?wsdl">http://tarena-teacher:8080/sd10702-web/Converter?wsdl</a>-o F:/</p>
<p>-o : 指明生成文件存放位置</p>
<p> -k : 同时保存JAVA文件</p>
<ul>
<li>编写客户类,运行时需要包含Jboss相关jar包.</li>
</ul>
<p><textarea cols="63" rows="15" name="code" class="java:collapse">import ws.*;

public class ConverWsTest{
  public static void main(String[] args){
    ConverterService service = new ConverterService();
    Converter converter = service.getConverterPort();
    doublic doolar = converter.rmbToDollar(10);
    System.out.println(dollar);
  }
}</textarea></p>
<p></p>
<p></p>
<p>19、EJB2.1之后 Stateless Session Bean也能发布为webService</p>
<p>扩展了用户接口:这样用户可以通过RMII-IIOP类型的客户端,也可以用webService的类型访问。</p>
<p><textarea cols="64" rows="15" name="code" class="java:collapse">@Remote
public interface CalculatorRemote{
  double add(double a,double b)
  double subtract(double a,double b)
}

@Stateless
@WebService
/*soap消息绑定类型有RPC和Document两种方式绑定,默认是Document*/
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class Calculator implements CalculatorRemote{
  public double add(double a,double b){
    return a+b;
  }
  public subtract(double a,double b){
    return a-b;
  }
}</textarea></p>
<p></p>
<p>20、以上调用WebService都是静态的方式,就是指服务端都是固定的,如果服务端的IP变更之类,就会调用失败。</p>
<p></p>
<p>可以通过查看源码,找到对应的URL和server定位变量,通过参数的形式输入URL等信息,来显示得定义服务地址,完成动态调用。</p>
<p></p>

你可能感兴趣的:(webservice)