和依赖注入(DI))
控制反转IoC原理控制反转是Spring框架的核心思想之一它将对象的创建和管理权从应用程序代码转移到Spring容器。传统编程中对象直接通过new关键字实例化依赖对象而IoC模式下对象的创建和依赖关系由外部容器如ApplicationContext统一管理。IoC通过以下机制实现BeanFactorySpring的基础容器接口负责管理Bean的生命周期。ApplicationContextBeanFactory的扩展提供更多企业级功能如事件发布、国际化等。Bean定义通过XML、注解或Java配置声明Bean的元数据容器根据这些定义创建对象。示例代码片段// 传统方式紧耦合classServiceA{privateServiceBserviceBnewServiceB();}// IoC方式松耦合ComponentclassServiceA{AutowiredprivateServiceBserviceB;}控制反转解决的问题控制反转Inversion of Control, IoC是一种设计原则旨在解耦组件之间的依赖关系。传统编程中调用者直接控制被调用者的生命周期和流程导致代码紧耦合。IoC通过将控制权交给外部容器或框架解决以下问题紧耦合组件直接依赖具体实现难以替换或修改。可测试性差依赖硬编码导致单元测试困难。灵活性低变更需求时需要大量修改代码。使用以下注解可将控制权交给容器管理Component用于标记一个类为Spring容器的组件被标记的类会被Spring自动扫描并创建实例。这是最通用的注解适用于任何层级的组件。Controller专用于标记Web层的控制器类通常与RequestMapping配合使用处理HTTP请求。继承自Component具备相同的组件扫描功能。Service标记业务逻辑层的服务类表明该类包含业务规则和逻辑处理。同样继承自Component用于区分服务层组件。Repository标记数据访问层的DAO类用于数据库操作。继承自Component同时具备将数据访问异常转换为Spring统一异常体系的功能。Component 注解的扫描机制Component及其衍生注解如Service、Repository、Controller标记的类需要被 Spring 的组件扫描机制发现并注册到容器中。以下是关键点启用组件扫描在 Spring 配置类或 XML 配置中明确指定扫描路径否则注解不会生效Java 配置方式使用ComponentScan注解。ConfigurationComponentScan(com.example.package)// 指定扫描的包路径publicclassAppConfig{}XML 配置方式通过context:component-scan标签。context:component-scanbase-packagecom.example.package/扫描的默认行为包路径限制默认扫描配置类所在包及其子包。若类不在扫描范围内即使有Component也不会被加载。过滤器可通过ComponentScan的includeFilters或excludeFilters自定义扫描规则。未被扫描的常见原因包路径错误配置的base-package未覆盖目标类所在包。缺少注解配置类未标注Configuration或 XML 中未启用context:component-scan。类未在扫描路径中例如类位于com.other.package但扫描路径仅配置为com.example。验证组件是否被加载通过ApplicationContext检查 Bean 是否存在ApplicationContextcontext...// 获取上下文booleanexistscontext.containsBean(beanName);// 默认类名首字母小写为 Bean 名称手动注册替代方案若需绕过扫描可直接通过Bean方法或 XML 的bean标签手动注册ConfigurationpublicclassAppConfig{BeanpublicMyComponentmyComponent(){returnnewMyComponent();}}依赖注入原理依赖注入Dependency InjectionDI是一种设计模式用于实现控制反转Inversion of ControlIoC通过外部提供依赖对象的方式解耦组件间的依赖关系。其核心思想是将对象的依赖关系从内部创建转为外部注入从而提高代码的可测试性、可维护性和灵活性。核心概念依赖一个对象需要另一个对象才能完成其功能时称为依赖。例如类A中使用了类B的实例类A依赖于类B。注入依赖对象不是由当前类内部创建而是通过构造函数、属性或方法参数从外部传入。实现方式构造函数注入通过构造函数传递依赖对象是最常用的方式。确保对象在创建时即具备所有依赖。publicclassService{privatefinalRepositoryrepository;publicService(Repositoryrepository){this.repositoryrepository;}}属性注入通过公开属性或Setter方法设置依赖对象。灵活性高但可能导致依赖不完整。publicclassService{privateRepositoryrepository;publicvoidsetRepository(Repositoryrepository){this.repositoryrepository;}}方法注入依赖对象通过方法参数传递适用于单次操作的依赖。publicclassService{publicvoidprocess(Repositoryrepository){// 使用repository}}优势解耦减少类与类之间的直接依赖依赖关系由外部容器管理。可测试性依赖可替换为Mock对象便于单元测试。可维护性修改依赖实现时无需改动依赖方代码。典型框架SpringJava通过Autowired或XML配置实现依赖注入。示例代码SpringServicepublicclassUserService{privatefinalUserRepositoryuserRepository;AutowiredpublicUserService(UserRepositoryuserRepository){this.userRepositoryuserRepository;}}通过依赖注入UserService无需关心UserRepository的具体实现由Spring容器自动装配。Autowired 注解的基本概念Autowired是 Spring 框架提供的注解用于实现依赖注入Dependency Injection。它能够自动将 Spring 容器中管理的 Bean 注入到目标字段、方法或构造函数中无需显式编写配置代码。使用场景字段注入直接在字段上添加AutowiredSpring 会自动装配匹配的 BeanAutowiredprivateUserServiceuserService;构造函数注入推荐用于强制依赖通过构造函数参数注入privatefinalUserServiceuserService;AutowiredpublicUserController(UserServiceuserService){this.userServiceuserService;}Setter 方法注入通过 Setter 方法注入可选依赖privateUserServiceuserService;AutowiredpublicvoidsetUserService(UserServiceuserService){this.userServiceuserService;}Autowired注解的 required 属性Autowired(required false)表示依赖是非必须的。若容器中没有匹配的 BeanSpring 不会抛出异常而是将字段设为null。处理多个同类型 Bean当存在多个相同类型的 Bean 时需配合Qualifier指定 Bean 的名称AutowiredQualifier(userServiceImplA)privateUserServiceuserService;自动装配的优先级Spring 按以下顺序尝试注入优先按类型匹配byType。若找到多个同类型 Bean再按名称匹配byName。若仍无法确定需通过Qualifier明确指定。替代方案ResourceJSR-250 标准注解默认按名称匹配byName。InjectJSR-330 标准注解功能类似Autowired需额外依赖javax.inject。常见问题循环依赖若两个 Bean 互相依赖可能导致循环引用。解决方法使用构造函数注入并配合Lazy延迟加载。重构代码避免设计上的循环依赖。注入失败检查是否已通过Component或其他注解将类标记为 Spring Bean并确保包扫描路径正确。测试场景在单元测试中可通过MockBean或手动创建 Mock 对象替代真实依赖。最佳实践推荐使用构造函数注入便于维护和测试。避免滥用字段注入以减少隐藏的依赖关系。对可选依赖显式设置required false。