EJB学习笔记01,了解企业级开发!

来源:互联网 发布:淘宝预售如何合并付款 编辑:程序博客网 时间:2024/05/23 00:02


 

有状态/无状态 SessionBean 和消息驱动Bean

    EJB主要的使用场合就是在数据分布的情况下,并且对事务的支持也要考虑多数据源,也就是跨容器的自动全局性事务,在EJB3中这种事务类型是CMT(容器管理事务)。还有另外一种事务类型,即BMT(Bean管理事务),也就是程序员用代码的方式来管理事务,相比CMT事务来讲,BMT的功能有限。

   下面以实例方式来介绍EJB3主要的核心组件:

      1. 会话Bean (Session Bean)

      2. 消息驱动Bean (Message Driven Bean)

   先来看看学习EJB3需要掌握的一些基本知识:

   1.EJB3 大量使用注解,这是在JDK5.0 中的技术,当然也可以使用XML文件来进行EJB3组件的配置,关于注解和XML 的选择可谓是仁者见仁,智者见智,并没有一个准确的答案,官方着力推进的方法还是使用注解。 

   2.EJB3 JTA (Java Transactoin API) 来规范事务的模型,这样就可以在跨数据源时达到全局性事务的处理。

   3.使用EJB3可以在任何实现JavaEE 技术的容器中进行部署,因为EJB3是一个标准和规范。

   4.EJB3也有类似Spring 框架的AOP 和 IOC 技术,如果有 struts + hibernate + spring 技术的使用经验,那么理解EJB3将会变得非常简单。    

   5.EJB3,实体Bean 带有注解,以匹配类中的属性和表中字段进行ORM映射。

 14.1.1 Java EE体系结构

   Java EE 应用框架 由不同的组件组成,映射到实际的开发中,也就是由不同的技术来组成JavaEE的体系结构(典型的javaEE体系结构客户端+业务层+数据库),所以JavaEE 体系是1个集大成者,不管是开源的技术还是商业的框架都能很好的在符合 Java EE 标准的容器中运行。

 14.1.2容器的概念   

  如果开发过JSP/Servlet类型的项目,那么大多数使用的服务器肯定是Tomcat,Tomcat就是1Web类型的容器,俗称:Web容器,Web容器主要负责request请求和response响应对象处理,并且将这些处理进行分发,通过解析无状态的http 协议来达到浏览器客户端与服务器之间的交互。那么在EJB3技术中,还有1种容器,叫做JavaEE容器。

  javaEE容器模糊点说就是在网上经常看到的软件,像Weblogic,JBoss,Websphere,GlasshFish等,其实JavaEE容器真正的意义是实现Java EE标准接口,提供EJB运行,开发,部署,调试等功能的环境,由于实现JavaEE 标准接口的厂商不同,所以会出现类似像Weblogic,JBoss,Websphere,GlasshFish 等这样的软件。

   Java EE 容器中的EJB 容器通过对Enterprise JavaBean 进行处理,来达到对服务器端商业组件功能的封装实现,EJB 技术发布了基于分布式的标准框架,使各个厂商有自己的跨容器,远程或本地功能的实现。

JavaEE 容器主要包含3种结构:

(1) Web容器 (2)EJB容器 (3)持久化容器

使用不同的技术也是在不同的容器中运行,像servlet运行在web容器,无状态/有状态 Enterprise JavaEean 运行在EJB 容器中,而与ORM映射有关的实体类运行在持久化容器中。

14.2有状态 SessionBean 和无状态 SessionBean

回话Bean EJB3的核心组件,也是使用EJB3必须要用到的技术,EJB3已经将会话Bean的使用复杂度降到了很低,可以说,用非常简单的代码,就可以实现使用会话Bean来完成分布式业务服务的功能。

14.2.1 SessionBean 有什么作用

   会话Bean(Session Bean)就有处理复杂业务逻辑的功能,相当于MVC模式的M层。大多数对事务的处理,以及持久化的功能都是在会话Bean中完成的,它是将软件的功能进行逻辑上的集成,在使用EJB3的过程中,可以使用会话Bean来将业务功能的接口进行暴漏,以便通过远程或本地服务的方式被调用。  

14.2.2 SessionBean的种类

 在EJB3中,会话Bean主要分为2

 1.无状态会话:不保存客户端应用程序的会话状态,有点类似于Web技术中http协议,其实它真正的实现是在Java EE容器中有一个无状态会话Bean实例池pool,在这个pool池中存放无状态会话Bean,池中的所有无状态会话Bean都是为客户端所共享,有些类似于JDBC中的Connection pool 的含义,所以使用完就放回池中,那么无状态会话Bean也有点"http协议时无状态"的味道了。

 2.有状态会话:而有状态会话则是像web技术中的session对象,可以在服务器端保存客户端的会话状态。

   14.2.3 MyEclipse中无状态SessionBean的创建

14.2.7 调用远程Remote类型的 StatelessBean实验

    前面的章节创建的是Local本地类型的无状态的SessionBean,现在要做一个跨JVM容器的调用Remote远程无状态SessionBean的实例。

    1.首先创建企业级项目,添加EJB模块支持(注意,不添加JPA标准支持,将checkbox勾去掉)

2.新建远程类型的无状态SessionBean(注意要将 Create Interface 类型选择为Remote)

业务方法,在这里需要注意的是,要在@Stateless 加入mappedName 属性,mappedName 属性值代表在 weblogic中注册JNDI节点的名称。

package publicInterface;

 

import javax.ejb.Remote;

 

@Remote

public interface UserinfoServiceRemote {

 

public void xyz();

}

package publicInterface;

 

import javax.ejb.Stateless;

 

@Stateless(mappedName = "zzzzzzzzzzzzzzzzzzz")

public class UserinfoService implements UserinfoServiceRemote {

 

public void xyz() {

System.out.println("run xyz method !");

}

}

 

将企业级项目部署到weblogic, 并且以ear 文件格式进行发布。

下一步就要再单独调的创建一个web项目去调用这个远程的无状态的SessionBean

项目示例如下:

package controller;

public class tt extends HttpServlet {

 

Public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

try {

Properties props = new Properties();

props.setProperty(Context.INITIAL_CONTEXT_FACTORY,

"weblogic.jndi.WLInitialContextFactory");

props.setProperty(Context.PROVIDER_URL, "t3://localhost:7001");

props.setProperty(Context.SECURITY_PRINCIPAL, "weblogic");

props.setProperty(Context.SECURITY_CREDENTIALS, "12345678");

Context context = new InitialContext(props);

UserinfoServiceRemote remote = (UserinfoServiceRemote) context

.lookup("zzzzzzzzzzzzzzzzzzz#publicInterface.UserinfoServiceRemote");

remote.xyz();

context.close();

} catch (NamingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

14.2.8无状态SessionBean 的回调函数和生命周期

无状态SessionBean 的回调函数有2种:

@PostConstruct  +  @PreDestroy

说起无状态SessionBean 的回调函数就要一同介绍一下与它息息相关的生命周期,无状态SessionBean的生命周期只有2个状态:

  1.不存在(does not exist)状态代表实例在内存中还没有创建

  2.无状态SessionBean中的方法在池中准备被调用(method-ready pool)状态实例已经被创建,并且放入实例池中等待被调用,

    根据Java EE 容器的不同,有些Java EE容器在启动时就创建一些无状态SessionBean ,并且放入实例池,

    这和容器的实现有很大的区别。

    其中从does not exist 状态转换到 method-ready pool 状态需要执行大体3个步骤:

    1.容器会调用Class类的newInstance()方法来构造一个无状态SessionBean的实例,所以可以有一个无参的构造函数,如果没有无参的构造函数,

      则使用系统默认的构造函数。

    2.容器将其它的资源注入进这个无状态SessionBean中。

    3.容器自动执行带有@PostConstruct 注解无参,不抛出异常,无返回值的任何名称的方法,每个类只允许定义1@PostContruct方法,并且这个方法只被调用1次。

     经过上面的3个步骤无状态SessionBean 就进入了method-ready pool 状态,准备供外部进行调用了,无状态SessionBean是线程安全的,所以访问量非常大时也能保证

     每个无状态SessionBean的线程安全,直到执行完本请求的业务方法后,再被其它的请求所调用,或者由于SessionBean数量不够,由容器再创建一些无状态的SessionBean.

     被调用结束后,无状态SessionBean 转为method-ready pool 状态。

    4.当容器中空闲无状态SessionBean 的数目过多,或大量的无状态SessionBean 占用太多的系统资源,则Java EE 容器自动调用带有@PreDestroy注解的无参,

      不抛出异常,无返回值的任何名称的方法,每1个类只允许定义1@PreDestroy方法,并且这个方法只被调用1次,它是在由method-ready pool 到 does not exist

      状态时被调用,调用后被垃圾回收器所回收,释放内存资源。

      下面一起来做一个实验:创建时添加EJB 和 WEB 模块,但不需要添加JPA 支持,然后在EJB 模块中创建无状态SessionBean。。

 

ejb1testEJB     

TestRemote.java

import java.io.IOException;

 

import javax.ejb.EJB;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import com.syz.testLocal;

 

public class test extends HttpServlet {

@EJB

testLocal tl;

 

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

tl.sayHello();

}

TestLocal.java

package com.syz;

 

import javax.ejb.Local;

 

@Local

public interface testLocal {

public void sayHello();

}

}

Test.java

package com.syz;

 

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.ejb.Stateless;

 

@Stateless

public class test implements testLocal, testRemote {

 

public test() {

 

System.out.println("你好我是构造!!");

}

 

public void sayHello() {

try {

System.out.println("Begin 你好我是EJB");

Thread.sleep(10000);

System.out.println("End 你好我是EJB");

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

 

@PostConstruct

public void postConstruct() {

System.out.println("postConstruct");

}

 

@PreDestroy

public void preDestroy() {

System.out.println("preDestroy");

}

}

ejb1testWeb

import java.io.IOException;

 

import javax.ejb.EJB;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import com.syz.testLocal;

 

public class test extends HttpServlet {

@EJB

testLocal tl;

 

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

tl.sayHello();

}

 

}

14.2.9 无状态SessionBean 实例变量值保留的问题与无状态SessionBean实例池

  无状态的SessionBean 在使用全局变量时有1个特性,比如1个无状态SessionBean,类名称为TestSessionBean,类TestSessionBean 中有1个全局变量是username,那么:

  1.用户1第一次使用这个TestSessionBean 时对username的值进行赋值了

  2.而用户2也使用这个TestSessionBean 时取到的还是用户1username变量赋的值

  为什么会有这种情况呢?其实这里面的机制是因为 Java EE 容器预先将一定数目的无状态SessionBean放入一个实例池中,每次执行无状态SessionBean 时从实例池取出一个实例,并不是重新new 创建出一个对象,一起来做一个实例,看看无状态SessionBean全局变量的特性。

 

   14.2.10 什么是有状态SessionBean

 

   有过web开发经验的盆友都会第一时间想到HttpSession,HttpSession会话对象可以在服务器端以sessionid为标识记录客户端的用户信息,这种在服务器端记录客户端用户信息的功能,就称为"有状态"功能 EJB3也能实现这种有状态的机制,称为"有状态SessionBean"

   使用有状态SessionBean的主要目的就是使每个用户有自己的有状态SessionBean,它和实例池中将无状态SessionBean 做共享的特性是相反,有状态SessionBean 不做共享,1个客户有1个自己的有状态SessionBean,比如购物车,每个人有自己的购物车。

   14.2.11 有状态SessionBean 的创建与状态特性

   注意:将Stateful 选中,意味着将要创建的是有状态的SessionBean,并且有状态SessionBean的类型是Local本地访问。

package com.syz;

 

import javax.ejb.Local;

 

@Local

public interface CartServiceLocal {

public void add();

public int getSize();

public void del();

}

package com.syz;

 

import java.util.ArrayList;

import java.util.List;

 

import javax.ejb.Stateful;

 

@Stateful

public class CartService implements CartServiceLocal {

private List list = new ArrayList();

 

public void add() {

list.add("= =");

}

 

public void del() {

list.remove(0);

}

 

public int getSize() {

return list.size();

}

 

}

test2Web

import java.io.IOException;

 

import javax.ejb.EJB;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import com.syz.CartServiceLocal;

 

public class test extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

Object o = request.getSession().getAttribute("CartService");

if (o == null) {

try {

System.out.println("第一次运行");

Context c = new InitialContext();

CartServiceLocal cs = (CartServiceLocal) c

.lookup("java:comp/env/CartService");

cs.add();

request.getSession().setAttribute("CartService", cs);

System.out.println(cs.getSize());

} catch (NamingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} else {

System.out.println("不是第一次运行");

CartServiceLocal cs = (CartServiceLocal) o;

cs.add();

System.out.println(cs.getSize());

request.getSession().setAttribute("CartService", cs);

}

}

}

0 0
原创粉丝点击