EJB 3.0快速入门与实践教程

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:EJB 3.0是Java EE的核心组件,简化了API和开发流程,易于学习。本教程介绍了注解驱动开发、实体Bean简化、状态管理、消息驱动Bean、依赖注入等核心特性,并通过设计模型、创建Bean、部署和测试等步骤,提供了深入学习和实践EJB 3.0的完整流程。学习资源包括《EJB 3.0实例教程.pdf》,适合初学者快速掌握EJB 3.0开发。

1. EJB 3.0核心概念介绍

EJB(Enterprise JavaBeans)3.0是Java EE平台中用于简化企业级应用开发的标准组件架构。它允许开发者通过定义业务逻辑的组件来构建可扩展、安全且可移植的服务器端应用程序。

1.1 EJB技术的演变

EJB技术自1.0版本发布以来,经过多次迭代,特别是在3.0版本中引入了注解,极大简化了配置的复杂度。开发者现在能够用注解来声明事务管理、安全性等,让代码更加清晰易懂。

1.2 EJB 3.0的关键特性

EJB 3.0的关键特性包括注解驱动的声明式事务管理、依赖注入以及对POJO(Plain Old Java Object)的支持,这意味着开发者可以使用普通的Java对象来编写业务逻辑,无需继承特定的EJB类或实现特定的接口。

1.3 EJB组件类型

EJB组件主要分为三种类型:实体Bean(Entity Beans)、会话Bean(Session Beans)和消息驱动Bean(Message-driven Beans)。实体Bean用于表示持久化数据,会话Bean提供业务逻辑处理,消息驱动Bean则用于处理异步消息。

代码示例

以下是一个简单的EJB 3.0会话Bean的代码示例:

import javax.ejb.Stateless;
import javax.ejb.Remote;

@Stateless
@Remote(MyBusinessInterface.class)
public class MySessionBean implements MyBusinessInterface {
    public String sayHello(String name) {
        return "Hello, " + name + "!";
    }
}

在本例中, @Stateless 注解声明了一个无状态会话Bean, @Remote 注解指定了远程接口,而 sayHello 方法提供了一个简单的业务逻辑实现。

通过本章的介绍,读者可以对EJB 3.0有一个基本的认识,为深入学习其各个组件和特性打下坚实的基础。

2. 注解驱动开发方法

在现代的软件开发中,注解已经成为了简化配置、增强代码可读性的一个重要工具。EJB 3.0 引入了基于注解的开发模式,极大地简化了 EJB 组件的开发流程。本章节将深入探讨 EJB 3.0 中注解的使用,包括其与传统的 XML 配置对比、常用注解详解以及在不同类型 Bean 中的应用。

2.1 注解的基本使用

2.1.1 注解与XML配置的对比

在 EJB 的早期版本中,依赖注入、事务管理等企业级服务需要通过 XML 文件进行声明和配置。这种模式虽然灵活,但也有明显的缺点,例如配置文件冗长且难以维护。

EJB 3.0 引入注解后,开发者可以在源代码中直接声明这些企业级服务,无需额外的 XML 文件。这种方式不仅减少了配置的工作量,同时也提高了代码的可读性和维护性。例如,使用 @Stateless 注解声明无状态会话 Bean,比在 XML 中配置要简单得多。

2.1.2 常用EJB注解详解

@Stateless

无状态会话 Bean 的基本注解,用于创建一个无状态会话 Bean 实例。无需在 XML 文件中声明任何信息。

示例代码:

@Stateless
public class MySessionBean {
    // 业务方法
}
@Stateful

有状态会话 Bean 的基本注解,和 @Stateless 类似,但用于创建有状态的会话 Bean。

示例代码:

@Stateful
public class MyStatefulSessionBean {
    // 业务方法和状态管理
}
@Inject

依赖注入的注解,用于将一个服务或组件注入到另一个组件中。 @Inject 注解可以与 @Named @PersistenceContext 等其他注解结合使用。

示例代码:

public class MyService {
    @Inject
    private MyDao myDao;

    // ...
}
@PersistenceContext

用于注入实体管理器,使得开发者能够操作数据库。

示例代码:

@PersistenceContext
private EntityManager entityManager;

2.2 业务逻辑的注解实现

2.2.1 实体类的注解使用

@Entity

标识一个类为一个实体类,这是 JPA(Java Persistence API)的一部分,用于将 Java 类映射到数据库表。

示例代码:

@Entity
public class User {
    @Id
    private Long id;

    private String name;
    // 其他字段和方法
}
@Table

用于指定实体类映射到的数据库表名。

示例代码:

@Table(name = "users")
@Entity
public class User {
    // ...
}

2.2.2 会话Bean的注解实现

@TransactionAttribute

用于定义方法的事务属性,指定方法在执行过程中需要事务管理的行为。

示例代码:

@Stateless
public class MyService {
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void someBusinessMethod() {
        // ...
    }
}
@RolesAllowed

用于指定哪些角色可以调用该方法,实现访问控制。

示例代码:

@Stateless
public class MyService {
    @RolesAllowed("admin")
    public void someAdminMethod() {
        // ...
    }
}

2.3 注解在消息驱动Bean中的应用

2.3.1 消息监听器的注解定义

@MessageDriven

用于定义一个消息驱动 Bean,它处理消息队列中的消息。

示例代码:

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class MyMessageBean implements MessageListener {
    // ...
}

2.3.2 消息处理方法的注解标记

@Timeout

用于定时消息的处理,指定在特定时间间隔后执行的方法。

示例代码:

@Timeout
public void handleTimeout(Message message) {
    // 处理超时消息
}

通过本章节的介绍,我们了解了 EJB 3.0 注解的基本使用、业务逻辑中实体类和会话 Bean 的注解实现,以及消息驱动 Bean 中的应用。在下一章,我们将深入探讨实体 Bean 的生命周期、关系映射、查询和事务处理的细节。

3. 实体Bean简化与操作

3.1 实体Bean的生命周期

3.1.1 创建和持久化实体Bean

实体Bean(Entity Bean)是Java EE规范中用于实现数据持久化的一种组件,它代表了数据库中的数据和逻辑。在EJB 3.0之前,实体Bean的开发相当复杂,需要实现多种接口,并编写大量的样板代码。EJB 3.0引入注解和POJO(Plain Old Java Object)实体Bean,大幅简化了实体的开发。

创建一个简单的实体Bean,开发者只需要在Java类中添加@Entity注解即可。在创建实体时,必须使用EJB容器提供的Context来获取EntityManager,它负责管理实体Bean的生命周期和数据库持久化操作。

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private String email;

    // getters and setters
}

@Entity 注解标记该类为实体Bean, @Id @GeneratedValue 用于定义主键和主键的生成策略。 EntityManager 通过 persist() 方法可以将实体保存到数据库中。

3.1.2 管理实体Bean状态转换

实体Bean的状态管理是通过EntityManager来完成的,它提供了多种方法来控制实体Bean的状态,例如: persist() merge() remove() refresh() 等。

  • persist() : 将新创建的实体标记为持久化状态,EJB容器会保证在适当的时候将其保存到数据库。
  • merge() : 用于合并临时状态的实体到持久化上下文中,比如,从会话Bean中获取了一个实体实例,修改后需要通过merge()方法将其变更同步到数据库。
  • remove() : 将持久化状态的实体标记为删除状态,EJB容器会在适当的时候将其从数据库中删除。
  • refresh() : 从数据库中重新加载实体的状态,覆盖实体的当前状态。
public void manageEntityStates(EntityManager entityManager) {
    User user = new User();
    user.setName("John Doe");
    user.setEmail("john.***");
    // Persist user
    entityManager.persist(user);

    // Merge user
    user.setName("Jane Doe");
    entityManager.merge(user);

    // Remove user
    entityManager.remove(user);

    // Refresh user
    User sameUser = entityManager.find(User.class, user.getId());
    entityManager.refresh(sameUser);
}

3.2 实体关系映射详解

3.2.1 单表映射与关联映射

实体关系映射(Entity Relationship Mapping,简称ORM)是将关系数据库中的表及其关系映射到对象模型的过程。在EJB 3.0中,这主要是通过Java Persistence API(JPA)注解来实现的。

单表映射是实体与数据库表直接映射的最简单情况。使用@Entity注解标记实体类,并用@Table指定对应的数据库表名。

import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {
    // ... fields, getters and setters ...
}

关联映射涉及到两个实体之间的关系。常见的关联类型有:

  • @OneToOne: 一对一关系。
  • @OneToMany: 一对多关系。
  • @ManyToOne: 多对一关系。
  • @ManyToMany: 多对多关系。

对于一对多关系,例如一个用户可以有多个地址,可以在User类上使用@OneToMany注解,并在Address类上使用@ManyToOne注解。

@Entity
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String street;
    private String city;
    // getters and setters
}

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    @OneToMany
    private List<Address> addresses;

    // getters and setters
}

3.2.2 嵌入式字段和继承映射

嵌入式字段映射(@Embeddable和@Embedded)允许将一组属性看作单一对象,而不需要创建一个单独的数据库表。这个单一对象可以在多个实体中被复用。

@Embeddable
public class ContactDetails {
    private String phone;
    private String email;
    // getters and setters
}

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @Embedded
    private ContactDetails contactDetails;

    // getters and setters
}

继承映射允许不同的实体类继承一个共同的基类。通过使用@Inheritance注解,开发者可以选择如何在数据库中存储继承层次结构。

  • SINGLE_TABLE: 所有实体类的字段存储在单个表中。
  • TABLE_PER_CLASS: 每个类对应一个表。
  • JOINED: 每个类对应一个表,基类的属性存储在基类表中,子类属性存储在各自表中。
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
public abstract class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // getters and setters
}

@Entity
public class Employee extends Person {
    private String department;

    // getters and setters
}

3.3 实体Bean的查询与事务处理

3.3.1 JPQL查询语言的应用

Java Persistence Query Language(JPQL)是一种面向对象的查询语言,用于在实体层面上进行查询。JPQL与SQL语法类似,但操作的是实体类和属性名,而不是数据库表名和列名。

例如,要查询所有用户的名字和电子邮件地址,可以编写如下JPQL查询语句:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;

public class QueryExample {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example");
        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin();
        String jpql = "SELECT u.name, u.email FROM User u";
        Query query = entityManager.createQuery(jpql);
        List<Object[]> resultList = query.getResultList();
        for (Object[] result : resultList) {
            System.out.println("Name: " + result[0] + ", Email: " + result[1]);
        }

        entityManager.getTransaction().commit();
        entityManager.close();
    }
}

3.3.2 事务管理与传播行为

在EJB中,事务管理确保业务逻辑处理的原子性,即一系列操作要么全部成功,要么全部失败。EJB容器使用声明式事务管理来控制事务,通过@Transactional注解来定义事务的边界和属性。

事务传播行为定义了事务应该如何在方法调用之间传播。EJB支持的传播类型包括:

  • REQUIRED: 如果当前没有事务,就新建一个事务。
  • SUPPORTS: 支持当前事务,如果当前没有事务,就以非事务方式执行。
  • MANDATORY: 使用当前的事务,如果当前没有事务,就抛出异常。
  • REQUIRES_NEW: 新建事务,如果当前存在事务,把当前事务挂起。
  • NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • NEVER: 以非事务方式执行,如果当前存在事务,抛出异常。
  • NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。
@Stateless
public class MyServiceBean {
    @Resource
    private SessionContext ctx;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void doWork() {
        // This method is executed within a transaction.
        // If there is no transaction, a new one will be created.
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void doNonTransactionalWork() {
        // This method is executed without a transaction.
        // If there is a transaction, it will be suspended.
    }
}

通过合理配置事务传播行为,开发者可以灵活控制事务如何在业务逻辑的不同部分传播,保证数据的一致性和完整性。

4. 无状态与有状态会话Bean

4.1 会话Bean的类型与特性

4.1.1 无状态会话Bean的原理与优势

无状态会话Bean(Stateless Session Bean)是一种不保存客户会话状态信息的业务组件。由于不维持状态,它能够有效地在多个用户间共享和重用,从而提供高性能和可伸缩性。

无状态会话Bean原理

每个无状态会话Bean的实例在处理方法调用之间不保存任何状态信息。当一个无状态会话Bean的实例完成一个方法调用后,它就可以被容器回收,重新分配给其他客户端使用。因此,无状态会话Bean通常适用于实现那些不依赖于客户端特定状态的服务,比如查询和更新操作。

@Stateless
public class MyStatelessBean {
    public String sayHello(String name) {
        return "Hello " + name;
    }
}

在上述代码中, MyStatelessBean 是一个无状态会话Bean,它不存储任何与调用者相关的信息,每次 sayHello 方法被调用时,都基于提供的 name 参数返回新的结果。

无状态会话Bean优势
  • 可伸缩性 :由于实例可以被任意重用,会话Bean能够支持大量的并发访问。
  • 性能提升 :实例能够被容器有效地管理,减少了内存消耗和管理开销。
  • 易于维护 :没有状态信息的保持,简化了业务逻辑的实现。
  • 负载均衡 :能够更简单地在多个服务器之间进行负载均衡。

4.1.2 有状态会话Bean的会话持久性

有状态会话Bean(Stateful Session Bean)能够保持一个会话期间客户端的状态。这意味着,当客户端调用同一个有状态会话Bean的不同方法时,这个Bean能够记住之前的操作状态和数据。

有状态会话Bean原理

有状态会话Bean为每个客户端维护一个独立的状态。容器负责管理这个状态,并在调用之间保持它。在Java EE中,你可以通过声明 @Stateful 注解来创建一个有状态会话Bean。

@Stateful
public class MyStatefulBean {
    private String customerInfo;

    public void setCustomerInfo(String info) {
        this.customerInfo = info;
    }

    public String getCustomerInfo() {
        return customerInfo;
    }
}

在上述代码中, MyStatefulBean 维护了一个 customerInfo 变量来跟踪客户状态。

会话持久性优势
  • 个性化服务 :有状态会话Bean能够根据会话的历史信息提供个性化处理。
  • 简化编程模型 :相比于无状态会话Bean,有状态会话Bean更适合于那些需要跟踪客户会话状态的场景。
  • 数据保持 :能够存储客户端会话期间的数据,对于复杂的交互过程非常有用。

4.2 会话Bean的方法实现

4.2.1 无状态会话Bean的业务逻辑处理

无状态会话Bean的业务逻辑实现应保持简单和无状态,以便于提高效率和实现负载均衡。

实现策略
  • 依赖注入 :使用依赖注入来获取对其他组件或服务的引用。
  • 事务管理 :在方法中使用声明式事务,确保业务操作的原子性。
@Stateless
public class MyStatelessBean {
    @EJB
    private SomeService service;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void processBusinessLogic() {
        // 业务逻辑实现,调用service组件
    }
}

在上面的代码中, processBusinessLogic 方法通过声明式事务和依赖注入利用了外部的服务组件。

性能优化
  • 合理事务 :合理使用事务确保数据的一致性,同时避免过大的事务范围影响性能。
  • 异步处理 :对于耗时的操作,可以考虑使用异步处理提高响应性。

4.2.2 有状态会话Bean的会话跟踪

有状态会话Bean需要跟踪客户端状态,因此需要使用会话上下文来保存状态信息。

实现策略
  • 会话上下文 :利用会话上下文来存储和检索与特定客户端关联的状态信息。
  • 视图类 :对于Web应用,可以通过视图类来管理客户端的状态信息。
@Stateful
public class MyStatefulBean {
    private String sessionData;

    public void setSessionData(String data) {
        this.sessionData = data;
    }

    public String getSessionData() {
        return this.sessionData;
    }
}

在上述代码中, MyStatefulBean 使用 sessionData 来维护会话状态。

会话跟踪优势
  • 状态保持 :能够在客户端和服务器端保持状态信息。
  • 交互增强 :能够提供更流畅的用户交互体验,比如购物车功能。

4.3 实例池与性能优化

4.3.1 实例池机制的工作原理

实例池机制可以有效地管理无状态会话Bean的实例,提高资源利用率和响应速度。

工作原理
  • 实例的创建与销毁 :容器创建一定数量的实例并将它们存储在池中。
  • 实例的分配与回收 :当客户端请求服务时,容器从池中分配一个可用实例;方法执行完毕后,实例被回收到池中以供下次使用。
实例池优势
  • 快速响应 :实例池允许容器快速响应请求,因为它可以复用已有的实例。
  • 资源优化 :实例池减少了实例创建和销毁的开销,优化了资源使用。

4.3.2 优化会话Bean性能的策略

性能优化的目的是减少资源消耗和提升系统响应能力。

性能优化策略
  • 负载均衡 :合理分配负载可以防止某些实例过载,而其他实例空闲。
  • 资源预热 :在系统启动时,预热实例池以提高初始响应速度。
  • 生命周期管理 :合理配置实例的生命周期,避免过长的实例生命周期。
@Stateless
@Startup
@ApplicationScoped
public class BeanPoolManager {
    @PostConstruct
    public void initializePool() {
        // 初始化实例池代码
    }
}

在上述代码中, BeanPoolManager 类通过 @Startup @ApplicationScoped 注解确保实例在应用启动时初始化,并且作为一个单例存在。

总结以上内容,无状态与有状态会话Bean的类型与特性各有优势,会话Bean的方法实现和实例池机制提供了性能优化和负载管理的多种策略。在EJB开发中,针对不同的应用场景选择合适的会话Bean类型,并且合理应用性能优化策略是至关重要的。

5. 消息驱动Bean应用

5.1 消息驱动Bean的基本概念

5.1.1 JMS与消息驱动Bean的关系

Java消息服务(JMS)为Java平台提供了一种标准的API来创建、发送、接收和读取异步消息。消息驱动Bean(Message-Driven Bean,MDB)是JMS与企业Java Beans(EJB)技术结合的产物,它是一个容器管理的、无状态的、异步的消息监听器,能够接收并处理来自消息服务的消息。

MDB为开发者提供了处理异步消息的简化模型。与传统的同步请求/响应模式相比,MDB允许应用解耦,消息的生产者和消费者可以独立运行。MDB的生命周期由容器管理,这包括消息的接收和处理。它不需要客户端维持连接,提高了资源利用率和系统的可伸缩性。

5.1.2 消息驱动Bean的生命周期管理

MDB的生命周期管理包括实例的创建、消息的接收和处理、以及实例的销毁。当一个消息到达目的地时,容器决定是否创建一个新的MDB实例或者使用现有的实例来处理该消息。

容器会在MDB实例化之前进行依赖注入,并在销毁实例之前处理好资源的释放。MDB的生命周期是由EJB容器管理的,开发者无需手动管理MDB的生命周期,这也使得开发关注于业务逻辑而非资源管理。

示例代码
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class MyMessageBean implements MessageListener {
    @Override
    public void onMessage(Message message) {
        try {
            TextMessage textMessage = (TextMessage) message;
            String text = textMessage.getText();
            // 处理消息
            System.out.println("Received message: " + text);
        } catch (JMSException ex) {
            // 异常处理逻辑
            ex.printStackTrace();
        }
    }
}

在上述代码中, @MessageDriven 注解标记了一个消息驱动Bean,指明了消息目的地类型为队列(Queue)。 onMessage 方法定义了消息到达时的处理逻辑。通过容器管理的实例生命周期,开发者无需编写额外的代码来管理实例的创建和销毁。

5.2 消息处理与异步通信

5.2.1 消息监听器的配置与使用

消息监听器是MDB的入口点,它实现了一个消息监听接口,如 javax.jms.MessageListener 。当容器接收到消息时,它会自动调用该监听器的 onMessage 方法。容器负责将消息适配到对应的参数类型,如 Message TextMessage ObjectMessage 等。

为了配置MDB以接收消息,开发者需要在 @MessageDriven 注解中指定消息目的地和类型。此外,还可以通过激活配置属性来自定义消息监听器的特定行为,例如配置消息选择器(message selectors)以过滤消息。

5.2.2 异步消息处理机制

MDB提供的异步处理机制是其核心特点之一。开发者可以定义MDB来响应不同的消息类型,这些消息可能来自于不同的客户端或服务,通过异步处理,系统能够并行地处理多个消息,提升系统的性能和吞吐量。

异步处理的另一个好处是提高了系统的响应性。因为消息处理是异步的,消费者不需要等待消息处理完成即可发送下一条消息。这使得系统能够有效地处理大量的并发请求,同时减轻了客户端等待响应的压力。

5.3 消息驱动Bean与事务管理

5.3.1 事务性消息的发送与接收

事务性消息确保了消息的一致性和可靠性。在EJB中,消息的发送和接收可以被整合进一个事务中,这样当事务提交时,消息才会被实际发送,反之,如果事务回滚,消息则不会被发送。这确保了消息的发送和业务操作具有相同的一致性保证。

要实现事务性消息处理,开发者可以在会话Bean中发送消息,并将消息发送操作整合进业务事务中。MDB则可以在接收到消息时,自动成为事务的一部分,即如果消息接收成功,且事务提交,那么消息接收被认为是成功的,否则消息接收将被回滚。

5.3.2 消息驱动Bean的事务回滚策略

当消息驱动Bean处理消息时,可能会遇到业务逻辑上的异常或错误。在这些情况下,可能需要回滚事务以保证数据的一致性。MDB提供了事务回滚的策略,这允许在消息处理过程中进行更细粒度的控制。

开发者可以通过声明事务的边界来控制何时事务应当被提交或回滚。例如,可以在MDB方法中抛出一个运行时异常来指示事务的回滚,或者使用 Session.setRollbackOnly() 来明确指定事务应当被回滚。容器在调用 MDB 处理方法时,会根据这些指示来管理事务的提交和回滚。

通过理解这些概念和策略,开发者可以设计出鲁棒的、事务性的异步消息处理系统。

6. 依赖注入实现机制

依赖注入(Dependency Injection,简称DI)是EJB中实现解耦合和简化代码的重要概念。该技术允许容器自动管理对象之间的依赖关系,而不是由对象自己在运行时创建或寻找依赖对象。这种机制有助于代码更加灵活,易于测试,提高开发效率。

6.1 依赖注入的基本原理

6.1.1 依赖注入的概念与优势

依赖注入是控制反转(Inversion of Control,IoC)的一个重要方面,它将依赖对象的创建和绑定推迟到容器执行阶段。这意味着开发者无需关心依赖对象的创建逻辑,容器会在运行时自动注入。其核心优势包括:

  • 解耦合 :业务逻辑类不需要了解依赖类的具体实现,提高了类与类之间的解耦合性。
  • 代码简洁 :开发人员不需要编写样板式的代码来创建和管理对象。
  • 提高可测试性 :可以更容易地对依赖的组件进行单元测试。
  • 灵活的配置 :依赖关系的改变不会影响业务逻辑代码,提高了应用的灵活性。

6.1.2 注入类型与注入点

在EJB中,注入类型主要有三种:

  • 构造器注入(Constructor Injection) :通过在类的构造器中声明依赖的参数来实现依赖注入。
  • 字段注入(Field Injection) :通过注解标记类的成员变量,容器将自动注入这些变量。
  • setter注入(Setter Injection) :通过定义setter方法来注入依赖。

注入点通常是类中的依赖属性,这些属性通过构造器参数、字段或者setter方法来标识。

6.2 注入技术的实践应用

6.2.1 字段注入、构造器注入与setter注入

以下是一个示例来比较不同注入类型的应用场景:

假设有一个服务类需要依赖一个日志组件:

public class Service {
    private Logger logger;
    // 构造器注入
    public Service(Logger logger) {
        this.logger = logger;
    }
    // 字段注入
    @Inject
    private Logger loggerField;
    // setter注入
    private Logger loggerSetter;
    @Inject
    public void setLogger(Logger loggerSetter) {
        this.loggerSetter = loggerSetter;
    }
}
  • 构造器注入 是推荐的方式,因为它强制依赖项的注入,使得类实例化时就处于可用状态。
  • 字段注入 使得代码更加简洁,但缺点在于无法显式地看到依赖项。
  • setter注入 提供了更多的灵活性,可以注入可选依赖,或者在类实例化后修改依赖项。

6.2.2 依赖注入在会话Bean中的应用

会话Bean经常使用依赖注入来管理业务逻辑和资源的依赖关系。例如,一个无状态会话Bean使用依赖注入来注入持久化单元:

@Stateless
public class OrderServiceBean implements OrderService {

    @PersistenceContext(unitName="OrderPU")
    private EntityManager em;
    // 其他业务方法...
}

在上面的例子中, @PersistenceContext 注解用于注入一个持久化上下文,该上下文是由容器自动管理的。

6.3 注入的高级配置与管理

6.3.1 注入资源的限定符与命名

在复杂的依赖注入场景中,可能需要区分相同类型的多个依赖。这时可以使用限定符来指定注入点。

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, METHOD, PARAMETER, FIELD })
public @interface CustomQualifier {
    String value();
}

@Stateless
public class CustomService {
    @Inject
    @CustomQualifier("primaryLogger")
    private Logger primaryLogger;

    @Inject
    @CustomQualifier("secondaryLogger")
    private Logger secondaryLogger;
    // ...
}

在上面的代码中, @CustomQualifier 注解用于区分两个不同类型的 Logger 依赖。

6.3.2 注入生命周期的管理

依赖注入不仅可以管理普通对象,还可以管理对象的生命周期。例如,使用 @PostConstruct @PreDestroy 注解来指定初始化和销毁方法:

@Stateless
public class ResourceBean {
    @Inject
    private SomeDependency dependency;

    @PostConstruct
    private void initialize() {
        dependency.initialize();
    }
    @PreDestroy
    private void cleanup() {
        dependency.cleanup();
    }
    // ...
}

以上代码展示了如何在EJB中通过注解来管理依赖对象的生命周期。

通过本章节的介绍,我们可以看到依赖注入在EJB应用中的核心作用。了解和掌握依赖注入的原理及其在实际应用中的配置方式,对于提高EJB应用的开发效率和代码质量有着重要的影响。接下来的章节将介绍EJB开发流程的详细步骤,这包括了环境搭建、项目结构规划和代码组织,以及测试与部署等关键环节。

7. 开发流程详细步骤

开发流程的详细步骤是实现任何项目的基础,尤其是对于EJB这种复杂的中间件应用来说,合理的开发流程可以确保项目的高效性和可靠性。本章将详细介绍EJB项目的开发流程,包括环境搭建、项目结构规划、代码组织、测试以及部署步骤。

7.1 开发环境的搭建

7.1.1 选择合适的EJB容器与服务器

选择合适的EJB容器与服务器是EJB项目开发的首要步骤。常见的EJB容器包括JBoss, GlassFish, WebLogic和WebSphere等。选择时需要考虑以下因素:

  • 支持的EJB版本 :确保选择的容器支持EJB 3.0及以上版本。
  • 开发与生产环境一致性 :尽可能选择在生产环境中也会使用的服务器。
  • 社区支持与文档 :一个活跃的社区和详尽的文档可以帮助开发者快速解决问题。
  • 性能与稳定性 :评估服务器的性能指标,确保其可以满足项目的负载要求。

示例代码:

# 下载并安装JBoss AS
wget ***

7.1.2 配置开发工具与调试环境

Eclipse、IntelliJ IDEA和NetBeans等IDE都支持EJB开发。配置IDE的步骤大致包括:

  • 安装EJB插件 :根据IDE的不同,安装相应的EJB开发插件。
  • 配置JDK :确认IDE使用的Java开发工具包(JDK)版本符合EJB 3.0或更高版本的要求。
  • 配置服务器连接 :在IDE中配置服务器连接,以便可以部署和调试应用程序。
  • 设置项目 :创建一个EJB项目,并配置其属性以符合EJB标准。

示例步骤:

  1. 打开IntelliJ IDEA,选择 File -> Project Structure -> Project
  2. 设置Project SDK为Java 8或更高版本。
  3. 添加EJB库,选择 File -> Project Structure -> Libraries ,点击加号添加EJB API库。
  4. 配置服务器连接,在 Run -> Edit Configurations -> + -> Application Server ,选择对应的服务器类型并配置。

7.2 项目结构与代码组织

7.2.1 项目目录结构的规划

一个清晰的项目目录结构对于代码管理至关重要,推荐的目录结构可能如下:

  • src/main/java :存放EJB实现类和相关的Java类。
  • src/main/resources :存放资源配置文件,如 persistence.xml
  • src/main/webapp :如果EJB是Web应用的一部分,这里存放Web相关的资源文件。
  • src/test/java :存放测试用的Java代码。

示例目录结构:

ProjectDirectory/
|-- src/
|   |-- main/
|   |   |-- java/
|   |   |   |-- com/
|   |   |   |   |-- mycompany/
|   |   |   |       |-- myapp/
|   |   |   |           |-- entity/
|   |   |   |           |-- session/
|   |   |   |           |-- message/
|   |   |   |-- resources/
|   |   |   |-- webapp/
|   |   |-- resources/
|   |-- test/
|       |-- java/
|-- pom.xml

7.2.2 模块划分与代码分割策略

代码分割和模块化可以提高代码的可维护性和复用性。在EJB项目中,可以按照以下策略进行模块划分:

  • 按功能划分模块 :将业务逻辑、数据访问、服务接口等不同功能分离到不同的模块中。
  • 按层划分模块 :将表示层、业务逻辑层、数据访问层等分离。
  • 按实体划分模块 :将与特定实体相关的代码分到同一模块。

示例代码分割:

// 一个简单的会话Bean示例
@Stateless
public class UserSessionBean {
    @PersistenceContext(unitName = "myapp")
    private EntityManager entityManager;

    public User findUserById(Long id) {
        return entityManager.find(User.class, id);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void updateUser(User user) {
        entityManager.merge(user);
    }
}

7.3 测试与部署

7.3.* 单元测试的编写与执行

编写单元测试对于确保代码质量非常关键。单元测试应覆盖所有业务逻辑的分支。EJB项目的单元测试通常使用JUnit和Mockito进行。

示例代码单元测试:

import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;

public class UserSessionBeanTest {
    private UserSessionBean userSessionBean;
    private EntityManager entityManager;

    @Before
    public void setUp() {
        entityManager = mock(EntityManager.class);
        userSessionBean = new UserSessionBean();
        Field field = UserSessionBean.class.getDeclaredField("entityManager");
        field.setAccessible(true);
        field.set(userSessionBean, entityManager);
    }

    @Test
    public void testFindUserById() {
        User user = new User();
        when(entityManager.find(User.class, 1L)).thenReturn(user);
        User result = userSessionBean.findUserById(1L);
        assertEquals(user, result);
    }
}

7.3.2 应用程序的打包与部署过程

打包和部署是开发流程的最后一步。打包通常使用Maven或Gradle这样的构建工具来完成。

示例部署命令:

mvn clean package

部署完成后,确保在服务器上运行以下命令启动应用程序:

# JBoss / WildFly
${JBOSS_HOME}/bin/standalone.sh -c standalone.xml

# GlassFish
asadmin start-domain

本章介绍了EJB项目的开发流程,从开发环境的搭建,到项目结构与代码组织,再到单元测试与应用部署,每一步都是EJB项目成功的关键。掌握这些步骤能够帮助开发者更高效地构建和管理EJB应用程序。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:EJB 3.0是Java EE的核心组件,简化了API和开发流程,易于学习。本教程介绍了注解驱动开发、实体Bean简化、状态管理、消息驱动Bean、依赖注入等核心特性,并通过设计模型、创建Bean、部署和测试等步骤,提供了深入学习和实践EJB 3.0的完整流程。学习资源包括《EJB 3.0实例教程.pdf》,适合初学者快速掌握EJB 3.0开发。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值