首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

Servlet 環境下基於 CDI + JPA 開發企業級應用實戰教程

     編輯:關於JSP

前言:為什麼選擇 CDI + JPA + Servlet?

JSR-299 (CDI) 核心目標是整合 JSF 與 EJB,但其**依賴注入容器**能力遠超於此。本教程在**純 Servlet 環境**示範 CDI 整合 JPA,避開 JSF 深層封裝與 EJB 重型容器,保留:

  • 聲明式事務管理(@Transactional)
  • Session 作用域共享 Persistence Context(長會話模式)
  • CDI 事件總線(解耦業務邏輯)
  • 類型安全注入(編譯期檢查)

適合具備 Servlet、JPA、Maven、Spring IoC 基礎的開發者。

技術棧版本鎖定

  • Servlet 容器:Tomcat 7.0.28+(需 Servlet 3.0+)
  • CDI 實現:Weld 1.1.8.Final (CDI 1.0)
  • JPA 提供者:Hibernate 4.1.4.Final
  • 建構工具:Maven 3.0.4+
  • IDE:Eclipse Indigo SR2 (Java EE 版)

Maven 關鍵依賴

<repositories>
  <repository>
    <id>jboss-public-repository-group</id>
    <url>https://repository.jboss.org/nexus/content/groups/public/</url>
  </repository>
</repositories>

<dependencies>
  <!-- Weld Servlet 整合 -->
  <dependency>
    <groupId>org.jboss.weld.servlet</groupId>
    <artifactId>weld-servlet-core</artifactId>
    <version>1.1.8.Final</version>
  </dependency>
  <dependency>
    <groupId>org.jboss.weld</groupId>
    <artifactId>weld-core</artifactId>
    <version>1.1.8.Final</version>
  </dependency>
  <!-- Hibernate EntityManager -->
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.1.4.Final</version>
  </dependency>
  <!-- Servlet API (provided) -->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

初次建構:mvn dependency:resolve 下載依賴。

核心架構設計

1. 啟動 CDI 容器

在 web.xml 註冊 Weld Listener:

<listener>
  <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

並在 META-INF/beans.xml(可空)啟用 Bean 發現模式。

2. 實體與 Repository

@Entity
public class Employee {
    @Id @GeneratedValue Long id;
    String name; String department; BigDecimal salary;
    // getters/setters
}

@ApplicationScoped
public class EmployeeRepository {
    @PersistenceContext EntityManager em;

    public Employee findById(Long id) { return em.find(Employee.class, id); }
    public List findAll() { return em.createQuery("SELECT e FROM Employee e", Employee.class).getResultList(); }
    public Employee save(Employee e) { return em.merge(e); }
    public void delete(Long id) { em.remove(em.getReference(Employee.class, id)); }
}

3. 聲明式事務攔截器

@Interceptor @Transactional
public class TransactionInterceptor {
    @Inject UserTransaction utx;
    @AroundInvoke
    public Object manageTransaction(InvocationContext ctx) throws Exception {
        boolean started = false;
        try {
            if (utx.getStatus() == Status.STATUS_NO_TRANSACTION) {
                utx.begin(); started = true;
            }
            return ctx.proceed();
        } catch (Exception e) {
            if (started) utx.rollback();
            throw e;
        } finally {
            if (started && utx.getStatus() == Status.STATUS_ACTIVE) utx.commit();
        }
    }
}

在 beans.xml 啟用:<interceptors><class>...TransactionInterceptor</class></interceptors>。

4. Session 作用域共享 EntityManager(長會話)

@SessionScoped
public class ExtendedPersistenceContext implements Serializable {
    @Produces @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    public void flush() { em.flush(); }
    public void clear() { em.clear(); }
}

控制器注入 EntityManager em 即自動獲得同一 Session 內共享的延伸持久化上下文,實現「Open Session in View」無需 Filter 手工管理。

5. CDI 事件解耦

// 事件物件
public class EmployeeChangedEvent {
    private final Employee employee;
    private final EventType type; // CREATED, UPDATED, DELETED
    // constructor, getters
}

// 發送
@Inject @Any Event employeeEvent;
employeeEvent.fire(new EmployeeChangedEvent(emp, EventType.UPDATED));

// 觀察
public void onEmployeeChanged(@Observes EmployeeChangedEvent evt) {
    // 發送通知、更新快取、記錄審計日誌...
}

專案結構建議

src/main/java
├── com.example.domain      // JPA 實體
├── com.example.repository  // Repository (CDI Bean)
├── com.example.service     // 業務邏輯 @Transactional
├── com.example.web         // Servlet 控制器
├── com.example.cdi         // Interceptor, Producer, Qualifier
└── com.example.event       // 事件物件與觀察器

常見坑點與對策

現象原因對策
LazyInitializationExceptionSession 關閉後存取關聯使用 EXTENDED PersistenceContext 或 DTO 投影
事務不生效Interceptor 未啟用或 Bean 非 CDI 管理檢查 beans.xml、@Transactional 註解、非 final 方法
Weld 啟動慢掃描類路徑過大beans.xml 設定 bean-discovery-mode="annotated"
Tomcat 類載入衝突Hibernate/JPA API 版本不一排除傳遞依賴,統一版本鎖定

現代化演進建議(2024+)

  • 升級至 **CDI 4.0 (Jakarta EE 10)** + **Hibernate 6.2+** + **Tomcat 10.1+ (Jakarta EE 10 Web Profile)**。
  • 引入 **MicroProfile Config / Health / Metrics** 實現雲原生可觀測性。
  • 考慮 **Quarkus** 或 **Micronaut** 原生支援 CDI、GraalVM 原生映像、啟動極速,適合容器化部署。
  • 若團隊熟悉 Spring,**Spring Boot 3.x** 仍是生產力最高選擇;CDI 適合「標準化、輕量、無 Spring 依賴」場景。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved