【Java】JavaBean、POJO 和 EJB

Posted by 西维蜀黍 on 2018-02-23, Last Modified on 2021-09-21

1 JavaBeans

JavaBeans 在 1996 年被 Sun 公司提出,并定义为 A JavaBean is reusable, platform independent component that can be manipulated visually in a builder tool.

JavaBeans 是一类符合一定编写规范(满足某些约定)的可被作为重用组件的 Java 类。

JavaBeans 是可重用组件,通过将不同的类(Object)封装到一个类(single Object)中,这个类被称为一个 Bean。

对于一个其方法命名、构造及行为必须符合以下约定的 Java 类,称为一个 bean

  • 所有属性为 private
  • 这个类必须有一个公共的缺省构造函数(即无参数的构造函数)
  • 这个类的属性(property)可能使用 set 方法 和 get 方法来访问(或 is 方法,用于访问布尔型属性)
  • 这个类的属性可具有只读、只写或可读可写的状态
  • 这个类是可序列化的(实现了 serializable 接口)
  • 这个类可以将很多类封装到自己内部

例子

GUI 组件(Component) 均是理想的 JavaBeans,即所有的 SwingAWT 类均是 JavaBeans

在 GUI 组件中:

  • 属性(Properties):JavaBeans 的属性是一组被命名的字段,可以包括颜色(color)、标签(label)、字体(font)、字体大小(font size)、显示模式(display size),可用于描述 GUI 组件的外观、行为和状态
  • 方法(Methods):JavaBeans 的方法与一般 Java 方法相同。所有的属性都通过方法来读取和修改
  • 事件(Event):JavaBeans 的事件与 SWING/AWT 中的事件处理(event handling)相同
  • 持久化(persistence):实现了 Serializable 接口使得每个 JavaBeans 都可以完成持久化存储

当然,我们也可以自己编写 JavaBeans

PersonBean.java

public class PersonBean implements java.io.Serializable {

    /**
     * name 属性(注意大小写)
     */
    private String name = null;

    private boolean deceased = false;

    /** 无参构造器(没有参数) */
    public PersonBean() {
    }

    /**
     * name 属性的Getter方法
     */
    public String getName() {
        return name;
    }

    /**
     * name 属性的Setter方法
     * @param value
     */
    public void setName(final String value) {
        name = value;
    }

    /**
     * deceased 属性的Getter方法
     * 布尔型属性的Getter方法的不同形式(这里使用了is而非get)
     */
    public boolean isDeceased() {
        return deceased;
    }

    /**
     * deceased 属性的Setter方法
     * @param value
     */
    public void setDeceased(final boolean value) {
        deceased = value;
    }
}

TestPersonBean.java

import player.PersonBean;

/**
 * <code>TestPersonBean</code>类
 */
public class TestPersonBean {
    /**
     * PersonBean 类测试方法的main函数
     * @param ARGS
     */
    public static void main(String[] args) {
        PersonBean person = new PersonBean();

        person.setName("张三");
        person.setDeceased(false);

        // 输出: "张三[活着]"
        System.out.print(person.getName());
        System.out.println(person.isDeceased() ? " [已故]" : " [活着]");
    }
}

JSP 中访问 JavaBeans

JavaBeans 可以被使用在 JSP 中,即在 Servlet(相当于 Controller)中根据用户通过 HTTP 请求传递过来的参数构造一个 Beans 实例(通过调用 Beans 实例的各种 setter 方法),并存储到 HttpSession 中的。

在 JSP 页面中,可将这个 Beans 实例取出(从 HttpSession 中),并将其属性显示在 HTML 页面中。

一个视频例子:Youtube - Java Beans simplified with the dynamic web programming example. using servlets, xml, jsp, html


<jsp:useBean> 标签可以在 JSP 中声明一个 Beanjsp:useBean 中的 id 属性用于指定这个 Bean 实例的名称(id 值可任意设置,只要不和同一 JSP 文件中其他 Bean 实例名字相同即可),而 class 属性指定这个 Bean 的类类型。

jsp:useBean 标签主体中使用 <jsp:getProperty/> 标签来调用 getter 方法,使用 <jsp:setProperty/> 标签来调用 setter 方法:

<jsp:useBean id="Bean实例的名称" class="Bean的类类型" scope="Bean作用域">
   <jsp:setProperty name="Bean实例的名称" property="Bean实例的名称中的某属性名"  
                    value="value"/>
   <jsp:getProperty name="Bean实例的名称" property="Bean实例的名称中的某属性名"/>
   ...........
</jsp:useBean>

testPersonBean.jsp

<% // 在JSP中使用PersonBean类 %>
<jsp:useBean id="person" class="player.PersonBean" scope="page"/>
<jsp:setProperty name="person" property="*"/>

<html>
    <body>
        姓名:<jsp:getProperty name="person" property="name"/><br/>
        已故与否?<jsp:getProperty name="person" property="deceased"/><br/>
        <br/>
        <form name="beanTest" method="POST" action="testPersonBean.jsp">
            输入姓名:<input type="text" name="name" size="50"><br/>
            选择选项:
            <select name="deceased">
                <option value="false">活着</option>
                <option value="true">已故</option>
            </select>
            <input type="submit" value="测试这个JavaBean">
        </form>
    </body>
</html>

2 EJB

当初,Java 为了响应满足所谓 “企业级应用” 的开发,具有可伸缩的性能和事务、安全机制,推出了一个叫 Java Platform, Enterprise Edition (J2EE) 的框架。

针对该企业级开发对应的 JavaBeans,变成了 Enterprise Java Bean (EJB)。而且 EJB 本身比 JavaBeans 更复杂。

设计 EJB 的初衷,是希望开发者能够把精力只放在业务上,而事务管理、安全管理和线程管理等统统都交给容器(Web Server)来处理。

  • 使用 ** 会话 Bean(Session Bean)** 来专注于处理业务
  • 使用 ** 实体 Bean(Entity Bean)** 来和数据库中的元组(tuple)形成映射,使用开发者和数据库打交道,甚至连 SQL 可能都不需要写
  • 使用 ** 消息驱动 Bean(Message Driven Bean)** 来与消息队列进行连接,以处理消息

很快,大家发现 EJB 极其笨重(在定义一个 EJB 时,需要增加一大堆与业务逻辑完全没有关系的代码,被迫实现一些与业务逻辑没有任何关系的接口),比如:

public class HelloWorldBean implements SessionBean{
    public  void setSessionContext(SessionContext context){
    }
    
    public void ejbCreate() throws CreateException{
    }
    
    public void ejbActivate() throws CreateException{
    }
    
    public void ejbPassivate() throws CreateException{
    }
    
    public void ejbRemove() throws CreateException{
    }
    
    // 只有这个方法包含业务逻辑,而上面实现的方法都仅仅是为了通过编译
    public String hello(){
        return "hello world";
    }
}

于是,在 2000 年,程序员们发起了一场叫 Plain Old Java Object (POJO)的运动(POJO 这个词被 Martin Fowler 提出),他们希望上面这个类变成这样:

public class HelloworldBean{
    public String hello(){
        return "hello world"
    }
}

因此,提出 POJO 的初衷,是希望这些描述实体的 Java 对象能够更简单(区别于复杂的 JavaBeansEJB),即不需要满足任何框架中的约束。


2002 年,Rod Johnson 写了一本叫 **《Expert One-on-One J2EE Design and Development》** 的书,书中分析了 Java EE 的开发效率和实际性能等方面的问题,从实践和架构的角度探讨了简化开发的原则和方法(初衷是为了替代 EJB,并使得 Java EE 开发更加简单灵活)。并以此作为方法论,实现了一个名为 interface21 的轻量级开发框架,interface21 则为 Spring 框架的前身。

2014 年,Spring 发布 1.0 版本,Rod Jahnson 同时推出了另一部影响深远的经典著作 **《Expert one on one J2EE development withoutEJB**》。

Spring 顺应了 POJO 的潮流,提供了一个叫 Spring 的容器来管理这些 POJO

对于一个 JavaBean 来说,如果它依赖于其他的 Bean,只需要声明即可。Spring 容器会负责把依赖的 Bean “注入进去”,这就是控制反转(IoC)

Martin flower 给这种方式起了个更好的名字,叫 “依赖注入(Dependency Injections)”。

如果一个 Bean 需要一些像事务、日志、安全等这样的通用的服务, 也是只需要声明即可。 Spring 容器在运行时能够动态的 “植入” 这些服务, 这就是依赖注入

3 Plain Old Java Object (POJO)

Plain Old Java Object (POJO)即简单的 Java 对象,实际上就是那些没有遵循特定框架约束,不具有任何特殊角色的 Java 普通对象。以将 POJOJavaBeansEnterprise JavaBean (特别是 EBJ3 之前的 EJB,因为 EJB3 从代码的表达性层面而言,大大减小了 Enterprise JavaBean 的使用复杂性)、EntityBean 等区别开来。

POJO 特点

  • 只有一些 private 属性(property),且每一个属性都包含其对应的 getset 方法用于获取或修改属性值
  • getset 方法中不包含任何业务逻辑
  • 没有继承任何类,也没有实现任何接口(区别于 JavaBeans,即 POJO 不需要实现 serializable 接口)
  • 更没有被其他框架侵入(不需要遵循任何框架的约定)

POJO 对象有时也被称为 Data 对象,大量应用于表现现实中的对象。如果项目中使用了 Hibernate 框架,有一个关联的 XML 文件,使对象与数据库中的表对应,对象的属性与表中的字段相对应(在这个语境中,我们可以将 POJO 理解为简单的实体类)。

public class Student {
    private String name;
    private Integer id;

    public String getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

JavaBeans 与 POJO 的区别

POJO 其实是比 JavaBeans 更纯净的 Java 简单类,POJO 严格遵循简单对象的概念,而 JavaBeans 中可能会封装一些简单的逻辑。

POJO 主要用于数据的传递,即它只能装载数据(作为存储数据的载体),但其本身不具备任何业务逻辑处理能力。

Reference