简介:本书《Mastering EJB 3.0》深入讲解了企业级JavaBeans(EJB)3.0技术,这一核心组件用于构建企业级应用。EJB 3.0简化了编程模型,采用注解和Java Persistence API(JPA),提升了开发效率和代码可读性。书中从基础概念到新特性,包括注解、持久化、实体管理、会话Bean、容器管理的事务、服务组件API、异步处理和容器服务,详细阐述了EJB 3.0的各个方面。实际案例研究展示了如何将理论应用于项目实践。配合书中示例代码,读者能够掌握EJB 3.0的核心技术和最佳实践。
1. EJB 3.0基础概念与架构
在当今的Java企业级应用开发中,EJB(Enterprise JavaBeans)扮演着重要的角色。EJB 3.0作为该规范的较新版本,它在简化开发的同时提供了强大的企业服务。本章将从基础概念开始,逐步深入到EJB的架构层面,为读者打下坚实的基础。
1.1 EJB的基本概念
EJB是一种为开发分布式、事务性、和可伸缩的服务器端应用程序而设计的Java编程模型。它抽象了业务逻辑,以便开发者可以专注于业务需求而无需担心底层的服务和管理细节。EJB组件可以被分成三大类:Session Beans、Message-Driven Beans和Entity Beans。Session Beans分为无状态(Stateless)和有状态(Stateful)两种,而Entity Beans则代表数据模型的业务对象。
1.2 EJB架构的核心组件
EJB架构由几个核心组件构成,包括EJB容器、EJB对象、客户端以及各种服务接口和对象。容器负责生命周期管理、依赖注入、事务处理等企业级服务。EJB对象则作为客户端和实际业务逻辑之间的桥梁,提供远程接口和本地接口供客户端调用。客户端可以是Web应用、另一个EJB或者任何Java客户端程序。
// 示例代码,展示一个简单的无状态Session Bean
import javax.ejb.Stateless;
@Stateless
public class MySessionBean {
public String sayHello() {
return "Hello, EJB!";
}
}
通过上述示例可以看出,EJB的开发相当简洁,无需编写大量的配置代码,这要归功于EJB 3.0引入的注解驱动开发模式。在下一章中,我们将深入探讨如何使用注解来进一步简化EJB的开发流程。
2. 注解驱动开发实践
在当今的软件开发中,注解已成为一种强大的工具,它为代码提供了元数据,而无需在外部配置文件中定义这些信息。本章节深入探讨EJB 3.0中的注解驱动开发实践,包括在EJB中的注解应用、自定义注解的使用、与XML配置的对比分析,以及如何通过注解简化开发流程。
2.1 注解在EJB中的应用
2.1.1 依赖注入与生命周期管理
EJB 3.0引入了注解来简化企业级应用开发,其中包括了依赖注入(Dependency Injection, DI)和生命周期管理。通过使用 @Inject
注解,我们可以轻松地在组件之间进行依赖注入。这个过程不仅减少了需要编写的样板代码,而且还能通过容器提供的内置服务来管理对象的生命周期。
举个例子,当我们在一个无状态会话Bean中注入一个资源时,EJB容器会负责创建资源实例,并在需要的时候将其注入到Bean中。
@Stateless
public class MyService {
@EJB
private MyResource resource;
}
在上面的代码段中, @EJB
注解告诉容器, MyService
需要一个 MyResource
类型资源的引用。容器会处理好创建、配置和依赖注入的工作。
2.1.2 自定义注解与元注解的使用
除了EJB提供的标准注解之外,开发者还可以创建自定义注解。这些注解可以用来封装特定于业务逻辑的元数据,并且可以在类、方法或字段上使用。通过使用 @Target
和 @Retention
等元注解,我们可以精确控制自定义注解的适用范围和生命周期。
例如,创建一个自定义的 @Loggable
注解,用于在方法执行前后记录日志:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
}
然后,在业务逻辑中使用该注解:
@Stateless
public class MyService {
@Loggable
public void processOrder(Order order) {
// 处理订单逻辑...
}
}
之后,在运行时,可以使用Java代理或反射来检测 @Loggable
注解并执行相应的日志记录。
2.2 注解与XML配置的对比分析
2.2.1 简化开发流程的优势
使用注解大大简化了EJB组件的开发流程。相比XML配置,注解直接内嵌在源代码中,这样做有几个显著优势:
- 代码可读性更强 :注解使得代码更加清晰,可以直观地看到组件的配置和依赖关系。
- 减少配置文件数量 :使用注解,可以减少或完全不使用XML配置文件,简化了项目结构。
- 开发效率提升 :开发者可以更快地实现功能,因为注解的语法更加直观和简洁。
下面是一个使用注解的无状态会话Bean示例,可以看出代码本身已足够说明其配置信息:
@Stateless
public class MySessionBean {
@Resource(name = "jdbc/MyDB")
private DataSource dataSource;
public void doSomething() {
// 使用dataSource操作数据库...
}
}
2.2.2 灵活性与兼容性考量
尽管注解提供了诸多便利,但在某些情况下,XML配置依然有其优势。特别是在需要高度灵活性和对遗留系统兼容性的场景下,XML配置可能更加合适。例如,可以在XML文件中以编程方式添加或修改配置,而不需要重新编译整个应用。
此外,对于某些特定的配置选项,XML可能提供比注解更精细的控制。例如,在EJB的XML配置中,可以对事务属性进行非常细致的控制,这是注解难以达到的。
总结
通过本章节的介绍,我们看到了注解在EJB中的广泛使用以及它所带来的开发便利。依赖注入和生命周期管理通过注解变得更加简洁,而自定义注解与元注解的使用进一步扩展了EJB的功能。同时,我们还分析了注解与XML配置之间的对比,理解了它们在不同场景下的优势与考量。在下一章节中,我们将深入探讨JPA对象关系映射的核心概念与映射技术,继续解锁EJB 3.0的更多高级特性。
3. JPA对象关系映射深入
3.1 JPA核心概念与映射技术
在Java持久化API(JPA)中,对象和关系数据库之间的映射是其核心内容,这使得对象的持久化变得透明和高效。理解JPA的基本映射规则是构建企业级应用的关键。
3.1.1 实体类与表映射的基本规则
一个典型的实体类通常会映射到一个数据库表。通过使用注解 @Entity
标识该类为实体类,然后使用 @Table
注解指定对应数据库表的名称。每个实体属性可以通过 @Column
注解与表的列进行映射。例如:
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
// 其他属性、getter和setter省略
}
在上面的例子中, @Id
注解表示该字段是主键, @GeneratedValue
注解定义主键生成策略。 @Column
注解中的 name
属性将 firstName
和 lastName
属性映射到数据库表中的 first_name
和 last_name
列。
实体类还可以映射到复杂的数据类型,例如一对多、多对一和一对一的关系。这些关系通过使用 @OneToMany
、 @ManyToOne
、 @OneToOne
和 @ManyToMany
注解来实现。
3.1.2 关联映射、继承映射的实现
关联映射是JPA中不可或缺的一部分,它允许实体类之间建立复杂的关系。
一对一关系
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(mappedBy = "employee")
private EmployeeDetails employeeDetails;
// 其他属性、getter和setter省略
}
@Entity
public class EmployeeDetails {
@Id
@OneToOne
@JoinColumn(name = "employee_id")
private Employee employee;
// 其他属性、getter和setter省略
}
在上述代码中, Employee
和 EmployeeDetails
之间建立了一对一的双向关联。 Employee
类使用 @OneToOne
注解,并且 mappedBy
属性指向 EmployeeDetails
中的关联属性名称。而 EmployeeDetails
类使用 @OneToOne
注解,并使用 @JoinColumn
来明确指定连接列。
多对一关系
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "department")
private List<Employee> employees;
// 其他属性、getter和setter省略
}
这里 Department
实体类通过 @OneToMany
注解与 Employee
实体类建立多对一的关系。 mappedBy
属性指向 Employee
中对应的关联属性名称。
继承映射允许我们把具有共通属性的实体类组织在一个继承体系中,JPA支持三种继承映射策略:单表策略、每类一张表和连接表策略。选择合适的策略可以优化查询性能和数据存储。
通过这些映射技术,JPA为开发人员提供了强大的工具来抽象和管理对象与数据库之间的复杂关系,使应用开发更加高效和具有可维护性。
3.2 EntityManager与EntityManagerFactory应用
EntityManager
和 EntityManagerFactory
是JPA中管理实体生命周期和执行数据库操作的核心接口。
3.2.1 创建和管理实体的生命周期
EntityManager
负责实体的CRUD操作,以及管理实体状态。它通过方法如 find()
, persist()
, merge()
, remove()
等来实现。
// 创建一个新的EntityManager实例
EntityManager entityManager = entityManagerFactory.createEntityManager();
try {
entityManager.getTransaction().begin();
// 创建一个新的实体实例并保存
Employee newEmployee = new Employee("John", "Doe");
entityManager.persist(newEmployee);
// 提交事务
entityManager.getTransaction().commit();
} finally {
// 关闭EntityManager
entityManager.close();
}
在上述代码片段中,首先创建了 EntityManager
实例,并通过 persist
方法将新创建的 Employee
实体持久化到数据库中。之后提交事务以保证更改被保存。
3.2.2 查询语言JPQL的使用
Java Persistence Query Language(JPQL)是一种与SQL相似的面向对象的查询语言,它允许用户编写独立于数据库表结构的查询语句。
TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.lastName = :lastName", Employee.class);
query.setParameter("lastName", "Doe");
List<Employee> employees = query.getResultList();
在这个例子中, createQuery
方法使用JPQL语句来查询姓氏为"Doe"的所有员工。 setParameter
方法用于设置查询语句中的参数。 getResultList
方法返回匹配的实体列表。
JPQL查询极大地简化了跨不同数据库的查询操作,让开发者可以专注于业务逻辑,而不是底层SQL语句的编写。
3.2.3 JPA查询接口的扩展
JPA查询接口不仅包括JPQL,还包括Criteria API和Native SQL查询等高级特性。这些API和查询方法提供了更多的灵活性,使得查询的构建和执行可以根据开发需求进行优化。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = cb.createQuery(Employee.class);
Root<Employee> root = criteriaQuery.from(Employee.class);
criteriaQuery.select(root).where(cb.equal(root.get("lastName"), "Doe"));
TypedQuery<Employee> query = entityManager.createQuery(criteriaQuery);
List<Employee> employees = query.getResultList();
在上述代码中,使用Criteria API来构建查询,这允许开发者使用一种类型安全的方式创建查询,并且使查询语句可以动态构建。
JPQL和Criteria API提供了一种在保持与具体数据库无关的同时,可以进行复杂查询的方法。JPA为持久化操作提供了清晰的接口和一致的方法,使得开发者可以更专注于业务逻辑,而不需要担心底层数据库的复杂性。通过EntityManagerFactory和EntityManager,JPA提供了对实体生命周期的全面控制,以及丰富的查询语言来获取所需的数据。
总结
JPA的核心概念和映射技术为对象和关系数据库之间提供了清晰的映射规则。通过合理使用 EntityManager
和 EntityManagerFactory
,开发人员可以高效地管理实体的生命周期以及执行复杂的数据库操作。JPQL作为面向对象的查询语言,极大地提升了跨数据库查询的能力。同时,Criteria API和Native SQL查询提供了更高级的查询构建方式,扩展了JPA的查询能力。掌握JPA的这些特性对于任何希望深入Java企业级开发的开发者来说,都是必不可少的。
4. EJB事务管理与状态管理
4.1 CRUD操作与事务管理机制
4.1.1 事务隔离级别与传播行为
在EJB技术中,事务管理是保证数据一致性与完整性的重要机制。事务隔离级别定义了事务之间相互隔离的程度。EJB容器支持的隔离级别有多个选项:
-
READ_UNCOMMITTED
:读未提交,这是最低的隔离级别,在此级别下,事务可以读取到其他事务未提交的数据。 -
READ_COMMITTED
:读已提交,允许事务读取已经被其他事务提交的数据,但不允许读取未提交的数据,这是大多数数据库的默认级别。 -
REPEATABLE_READ
:可重复读,保证在同一个事务中多次读取同一数据时,结果是相同的。 -
SERIALIZABLE
:可串行化,确保事务是串行执行的,这是最高的隔离级别。
事务传播行为定义了事务的边界和事务如何在方法调用中传播。EJB支持以下传播行为:
-
REQUIRED
:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。这是最常见的选择。 -
REQUIRES_NEW
:新建事务,如果当前存在事务,把当前事务挂起。 -
SUPPORTS
:支持当前事务,如果当前没有事务,就以非事务方式执行。 -
NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 -
MANDATORY
:使用当前的事务,如果当前没有事务,就抛出异常。 -
NEVER
:以非事务方式执行,如果当前存在事务,则抛出异常。
代码块:设置事务属性
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateless
public class ItemService {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void updateItemPrice(int itemId, double newPrice) {
// 更新商品价格的业务逻辑
}
}
在上述代码示例中, updateItemPrice
方法被标记为 REQUIRED
属性,这意味着如果调用此方法的方法已经在事务中,那么 updateItemPrice
将在这个事务中执行。如果调用的方法不在事务中, updateItemPrice
将启动一个新的事务。
4.1.2 事务回滚与资源管理策略
事务的回滚是处理异常和错误情况的标准机制,它确保了一旦事务中的任何操作失败,所有的更改都会被撤销,从而维护了数据的完整性。在EJB中,开发者可以使用 @TransactionAttribute
注解来声明事务行为,或者在代码中明确地调用事务回滚:
import javax.ejb.EJBException;
import javax.ejb.SessionContext;
import javax.transaction.Transactional;
@Stateless
public class OrderService {
@Inject
private SessionContext context;
@Transactional(rollbackOn = Exception.class)
public void processOrder(Order order) throws Exception {
try {
// 正常处理订单的业务逻辑
// 假设出现异常,将自动回滚事务
} catch (Exception e) {
throw new EJBException("Transaction rolled back due to exception", e);
}
}
}
在上述代码中, @Transactional(rollbackOn = Exception.class)
注解指明了在发生任何异常时事务应当被回滚。这是资源管理策略的一部分,通过声明式的方式控制事务的行为。
资源管理策略还需要考虑与持久化上下文的关系。为了保持数据的一致性,开发者需要管理与实体Bean相关的持久化上下文。这涉及到对 EntityManager
的正确使用,以及在必要时对上下文的刷新和清除。正确的资源管理策略可以减少锁争用,提高并发访问性能。
4.2 无状态与有状态会话Bean管理
4.2.1 会话Bean的生命周期与作用域
会话Bean分为有状态(Stateful)和无状态(Stateless)两种。它们在EJB容器中拥有不同的生命周期和作用域。
无状态会话Bean
无状态会话Bean不保留任何与客户端相关的状态信息,因此它们可以被容器自由地重用。这使得无状态会话Bean非常适用于那些不需要记住特定客户端操作历史的场景。无状态会话Bean的生命周期通常与容器的生命周期一致,但具体实例可以在不同的方法调用之间共享,直到显式销毁或超时。
@Stateless
public class CalculatorBean {
public int add(int a, int b) {
return a + b;
}
}
上述的 CalculatorBean
是一个无状态会话Bean的例子,它提供了加法方法。由于它不依赖任何状态,所以每个客户调用 add
方法时,都会直接执行。
有状态会话Bean
有状态会话Bean会为每个客户端维护一个特定的状态,这使得它们能够记住客户端之前的交互信息。因此,有状态会话Bean的生命周期通常从创建时开始,到客户端调用完成(通常是 remove
方法)结束。每个客户端拥有自己的有状态会话Bean实例,不会被其他客户端共享。
@Stateful
public class ShoppingCartBean {
private List<Item> items = new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public List<Item> getItems() {
return items;
}
public void remove() {
items.clear();
// 此时,该会话Bean可能会被容器钝化或移除。
}
}
ShoppingCartBean
是一个有状态会话Bean的例子,它保存了一个购物车的状态。当一个客户端往购物车中添加商品时,这些商品将被添加到 items
列表中。这个状态对于其他客户端是不可见的,因为每个客户端都有自己的 ShoppingCartBean
实例。
4.2.2 状态保持技术与性能考量
在Web应用中,状态保持是一项挑战。为了在无状态环境中保持用户状态,开发者通常使用会话跟踪技术,如HTTP会话、URL重写、Cookies或隐藏表单字段等。然而,在EJB环境中,有状态会话Bean提供了一种自然的机制来维护状态,允许开发者创建状态相关的业务逻辑。
状态保持技术
在EJB中,状态可以通过以下方式在有状态会话Bean中保持:
- 实例变量:在有状态会话Bean中声明的变量。
- 事务上下文:保持事务性的业务逻辑操作中的状态。
- 调用上下文:EJB容器管理的状态信息,如用户身份、安全上下文等。
性能考量
有状态会话Bean可能会带来性能上的考量,因为每个客户端都需要自己的实例。这可能增加内存使用量,并且在高并发场景下可能会成为瓶颈。开发者需要在设计时就考虑好如何有效地管理这些实例:
- 池化机制 :EJB容器通常提供实例池化,以减少实例创建的开销,提高性能。
- 钝化与激活 :容器可以根据需要,将有状态Bean实例从内存中移除(钝化),并在需要时重新激活它们。
- 合理的生命周期管理 :确保有状态Bean的生命周期与业务需求相匹配,防止不必要的实例保持在内存中。
有状态与无状态会话Bean的选择应当基于实际的业务需求、性能考量以及可维护性。在某些场景下,选择错误的会话Bean类型可能会导致性能下降或资源浪费。因此,开发者需要仔细分析应用的特定需求,选择最合适的会话Bean类型。
请注意,由于篇幅限制,第四章的全部内容无法在这里完全展示,以上只包含了部分章节的样例内容。完整章节内容应包含更多细节和代码实例,以满足指定的字数和结构要求。
5. EJB3.0高级特性和服务
5.1 容器管理的事务(CMT)原理与应用
容器管理的事务(CMT)是EJB3.0中的一个重要特性,它允许开发者通过声明方式来管理事务,从而简化代码并增强可维护性。
5.1.1 CMT的工作机制与优势
在EJB3.0中,CMT工作机制允许开发者在业务方法上通过注解 @TransactionAttribute
来声明事务行为。容器负责根据这些声明来自动管理事务的边界和提交或回滚事务。例如:
@Stateless
public class MyService {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void performAction() {
// 业务逻辑
}
}
在上面的例子中, performAction
方法被标记为 REQUIRED
,意味着它将被加入到现有事务中,如果没有现有事务,则创建一个新的事务。
CMT的优势在于: - 代码简化 :开发者不需要编写代码来显式控制事务的开始和结束。 - 事务策略集中管理 :事务管理策略可以集中配置在部署描述符或注解中。 - 可维护性提高 :由于事务管理的代码被抽象化,业务逻辑更加清晰。
5.1.2 声明式事务管理的实现
声明式事务管理通过注解来实现,允许开发者仅通过在方法上添加注解来控制事务的行为。例如:
@Stateless
public class MyService {
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateData() {
// 更新操作
}
}
在上述代码中, updateData
方法上的 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
注解表示每次调用该方法都会启动一个新的事务,即使当前有事务在运行。
5.2 容器提供的安全性、集群、调度和监控服务
EJB3.0容器提供了许多高级特性,如安全性、集群支持、定时任务和监控服务,这使得开发者能够更加专注于业务逻辑的实现,同时容器提供稳定和可靠的基础设施。
5.2.1 安全性实现机制与最佳实践
EJB容器可以通过声明方式或编程方式实现安全性机制。开发者可以使用 @RolesAllowed
注解来限制哪些角色可以调用特定方法。例如:
@Stateless
public class MyService {
@RolesAllowed("admin")
public void updateConfiguration() {
// 更新配置的代码
}
}
安全性实现的最佳实践包括: - 最小权限原则 :仅授予完成工作所必需的权限。 - 角色分离 :不同的角色执行不同的任务。 - 安全审计 :定期审计安全日志和配置。
5.2.2 集群配置与会话复制策略
EJB支持集群环境中的状态管理,通过状态复制来保证在集群中的多个节点间状态的同步。开发者可以通过注解如 @Stateful
和 @Stateless
来声明会话Bean的类型,并选择合适的会话复制策略。例如:
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private List<Product> products;
@Remove
public void checkout() {
// 结算操作
}
}
在集群环境中,开发者可以配置会话复制策略来决定如何同步状态,例如使用单写入或多写入模式。
5.3 案例研究与实践应用
5.3.1 案例分析:构建一个企业级应用
在构建企业级应用时,通过利用EJB3.0的高级特性,可以大大简化开发流程并增强系统的稳定性和可维护性。例如,可以将业务逻辑分离到多个EJB中,并利用CMT和安全性注解来管理事务和访问权限。
5.3.2 从理论到实践:综合应用EJB3.0特性
综合应用EJB3.0特性的过程中,开发者应该: - 设计模式 :应用如Session Façade模式来简化客户端代码。 - 性能优化 :合理使用无状态和有状态会话Bean来优化性能。 - 可扩展性 :使用消息驱动Bean(MDB)来构建可扩展的异步处理机制。
结合这些理论和实践,开发者可以高效地构建复杂的企业级应用,并保证其在高负载下的可靠运行。
简介:本书《Mastering EJB 3.0》深入讲解了企业级JavaBeans(EJB)3.0技术,这一核心组件用于构建企业级应用。EJB 3.0简化了编程模型,采用注解和Java Persistence API(JPA),提升了开发效率和代码可读性。书中从基础概念到新特性,包括注解、持久化、实体管理、会话Bean、容器管理的事务、服务组件API、异步处理和容器服务,详细阐述了EJB 3.0的各个方面。实际案例研究展示了如何将理论应用于项目实践。配合书中示例代码,读者能够掌握EJB 3.0的核心技术和最佳实践。