Java安全
Java 基础知识
01概述
02变量
03运算符
04程序控制语句
05数组
06面向对象编程
07代码练习
08重载
09作用域
10构造方法&构造器
11this
12包
13修饰符
14封装
15继承
16super
17覆盖&重写
18多态
19零钱通项目
20类变量&类方法
21抽象类
22接口
23内部类
24枚举
25泛型
26常用API
27lambda表达式
28正则表达式
29异常
30File&IO流
31日志技术
32多线程
33网络编程
01反射
02反序列化
03JVM
04JDBC
05RMI
06JRMP
07JNDI
08CDI
09JPA
10Servlet
11Filter
12MVC模型
13MVC框架
14类的加载机制
15Maven
16注解
17ORM
18CC链
19JNDI注入
Log4j2
-
+
首页
08CDI
CDI(Contexts and Dependency Injection,上下文与依赖注入)是 Jakarta EE(原 Java EE)中用于组件管理和依赖解耦的核心规范,旨在通过 “依赖注入(DI)” 和 “上下文生命周期管理” 简化企业级应用开发,是现代 Java 企业级开发的重要基础。 ## 概述 CDI 的全称是 Contexts and Dependency Injection。 它是一套规范:定义了如何将组件(如 Bean)的生命周期和它们之间的依赖关系,交给容器来统一管理。 它的使命:实现解耦。开发者不需要自己使用 new 关键字来创建对象,也不需要手动处理对象之间的依赖关系。容器(如 Jakarta EE 服务器或 Spring 框架)会自动帮你“注入”所需的依赖。 两大核心功能: 1. 依赖注入:自动将依赖对象“注入”到需要它的组件中。 2. 上下文生命周期管理:管理组件(Bean)的创建、状态和销毁,并可以为其绑定一个明确的作用域(如请求范围、会话范围、应用范围)。 > 比喻 CDI 就像一个智能的自动化物流中心。当一个工厂(你的代码)需要零件(依赖项)时,它不需要知道零件来自哪个仓库、如何运输。它只需要发布一个需求清单(如使用 @Inject 注解),物流中心(CDI 容器)就会自动找到正确的零件,并在正确的时间送到工厂的流水线上。 ## 核心概念 ### Bean 组件 指由 CDI 容器管理和生命周期的 Java 组件,几乎任何普通的 Java 对象都可以成为 Bean(如 POJO、EJB 等)。 > **标记 Bean 的方式**: 类上添加作用域注解(如@RequestScoped); 类上添加@Named(暴露给视图层,如 JSF); 实现特定接口(如 EJB 的@Stateless本质上也是 CDI Bean)。 ### 依赖注入 通过在字段、构造函数或设置方法上使用 @Inject 注解,容器会在运行时查找并注入符合条件的 Bean,无需手动创建。 ```java public class UserService { // 字段注入:容器会自动找一个PasswordHasher的实现注入到这里 @Inject private PasswordHasher passwordHasher; // 构造函数注入(更推荐,易于测试) @Inject public UserService(PasswordHasher passwordHasher) { this.passwordHasher = passwordHasher; } public void registerUser(String username, String password) { String hashedPassword = passwordHasher.hash(password); // ... 保存用户 } } ``` ### 限定符 当存在多个同类型的 Bean 时(如PaymentService有WechatPayment和AlipayPayment两个实现),用限定符区分注入的具体 Bean。 > 使用步骤 1、定义自定义限定符注解(需标注@Qualifier)。 ```java @Qualifier @Retention(RUNTIME) @Target({TYPE, FIELD, PARAMETER}) public @interface Wechat {} ``` 2、用限定符标记具体的Bean。 ```java @Wechat // 标记为微信支付实现 public class WechatPayment implements PaymentService { ... } ``` 3、注入时指定限定符。 ```java public class OrderService { @Inject @Wechat // 注入微信支付实现 private PaymentService paymentService; } ``` ### 上下文与作用域 上下文定义了 Bean 的生命周期范围,作用域定义了 Bean 的生命周期和可见性。CDI 内置多种标准作用域,适配不同场景: | 作用域注解 | 生命周期描述 | 典型场景 | | ------------------- | ------------------------------------------------------------ | ---------------------------------- | | @RequestScoped | 与 HTTP 请求绑定:请求开始时创建,请求结束时销毁。 | 处理单次 HTTP 请求的组件 | | @SessionScoped | 与用户会话绑定:会话创建时创建,会话失效(如超时、 logout)时销毁。 | 存储用户登录状态的组件 | | @ApplicationScoped | 与应用绑定:应用启动时创建,应用停止时销毁(全局单例)。 | 全局配置、缓存组件 | | @Dependent | 依赖于其他 Bean 的生命周期:被注入到哪个 Bean,就跟随其生命周期(默认作用域)。 | 临时工具类、依赖其他组件的 Bean | | @ConversationScoped | 长对话范围:手动控制生命周期(如多步骤表单提交),需配合Conversation API。 | 跨多个请求的业务流程(如订单创建) | ### 生成者与消费者 当需要注入的对象无法直接被 CDI 管理(如第三方库对象、配置参数)时,通过`@Produces`定义 “生产者” 提供对象。 > 示例:注入数据库连接(`Connection`) ```java public class DatabaseProducer { // 生产者方法:提供Connection对象 @Produces public Connection createConnection() throws SQLException { return DriverManager.getConnection("jdbc:mysql://localhost:3306/test"); } // 销毁方法:关闭连接(配合@Disposes) public void closeConnection(@Disposes Connection conn) throws SQLException { conn.close(); } } // 消费者:注入生产者提供的Connection public class UserDao { @Inject private Connection conn; // 容器通过DatabaseProducer获取连接 } ``` ### 拦截器 基于 AOP(面向切面编程)思想,通过拦截器抽取通用逻辑(如日志、事务、权限校验),并应用到目标 Bean。 > 示例:日志拦截器 1、定义拦截器注解: ```java @InterceptorBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Log {} ``` 2、实现拦截器逻辑: ```java @Interceptor @Log // 关联拦截器注解 public class LogInterceptor { @AroundInvoke // 环绕通知:在目标方法前后执行 public Object logMethod(InvocationContext ctx) throws Exception { System.out.println("方法" + ctx.getMethod().getName() + "开始执行"); Object result = ctx.proceed(); // 执行目标方法 System.out.println("方法" + ctx.getMethod().getName() + "执行结束"); return result; } } ``` 3、在目标Bean上应用拦截器: ```java public class UserService { @Log // 对该方法应用日志拦截器 public void addUser(String username) { ... } } ```
毛林
2025年10月27日 20:56
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码