Spring 两大核心思想(一):IoC

Spring 两大核心思想(一):IoC Spring 两大核心思想一IoC1. 什么是 IoC2. Bean 的存储和获取2.1 类注解2.2 方法注解 Bean2.3 Bean 的命名规则2.4 获取 Bean3. DI 依赖注入3.1 三种注入方法3.2 同一类型有多个 Bean 时怎么注入4. IoC 的好处IoC 是 Spring 的两大核心思想之一而 DI 是 IoC 的具体落地实现二者是 Spring 所有功能的基石也是 Java 后端面试的高频核心考点。本文从概念本质出发详细梳理 IoC 相关知识点讲解详细欢迎收藏1. 什么是 IoCIoCInversion of Control控制反转IoC 是一种思想将对象的控制权交给 IoC 容器由 IoC 容器来创建对象而不是自己去 new 一个对象。使用时将依赖注入DI进来即可这里的依赖其实就是对象。简单来说对象的控制权从程序员代码交给了 IoC 容器就是控制权实现了反转。Spring 框架实现了 IoC 思想所以Spring 是一个包含了众多方法的 IoC 容器。2. Bean 的存储和获取被 Spring IoC 管理的对象叫作 Bean。要想让对象被 Spring 管理我们要把它们存储到 IoC 容器中。可以通过以下注解实现。2.1 类注解我们可以通过五大注解实现对象的存储这五大注解是类注解加在类上Controller控制层Service业务逻辑层Repository数据访问层Component其他Configuration配置层这五大注解与程序的应用分层是相呼应的让程序员看到注解后就能直接了解当前类的用途。根据类所在的层在类上加上对应的注解就可以实现 Bean 的存储。Controller、Service、Repository、Configuration 中都实现了 Component它们可以理解为是 Component 的“子类”所以在一些分层比较模糊的场景我们不用纠结到底使用哪个注解它们也可以通用。2.2 方法注解 Bean还有一个方法注解Bean。Bean 可以解决两种情况当想要使用的类在外部的包第三方依赖中时我们没法对该类添加注注解当一个类中需要创建多个对象时此时在对应方法上Bean 即可。【注意】Bean 必须搭配五大注解一起使用。Bean 的命名规则被 Bean 修饰的方法名就是当前 Bean 的默认名称。2.3 Bean 的命名规则开发人员不需要为 Bean 指定名称Spring 容器会自动为 Bean 生成唯一的名称如果类的名称是大驼峰形式Bean 的名称是将类名第一个字母小写即变为小驼峰。UserCroller -- userController如果类的名称前两个字母都是大写类名即为 Bean 的名称。UController -- UController如果是 Bean 存储的对象Bean 修饰的方法名即为 Bean 的名称也可通过 Bean(“name”) 自定义名称。2.4 获取 Bean有三种方式根据名称获取、根据类型获取、根据名称 类型获取首先从需要调用ApplicationContext 提供的 getBean 方法从 Spring 上下文中获取对象。假设我们要获取的对象类型为 UserController代码如下SpringBootApplicationpublicclassSpringApplication{publicstaticvoidmain(String[]args){// 获取 Spring 上下文ApplicationContextcontextSpringApplication.run(SpringIocDemoApplication.class,args);// 从 Spring 上下文中获取对象// 1. 根据名称获取UserControlleruserController1(UserController)context.getBean(userController);// 2. 根据类型获取UserControlleruserController2(UserController)context.getBean(UserController.class);// 3. 根据名称 类型处理UserControlleruserController3(UserController)context.getBean(userController,UserController.class);}}在上面的代码中我们用不同方式三次获取了 Bean打印他们的地址可以发现它们是同一个对象。也就是说Spring 创建的对象是单例的。因为 Spring 默认使用单例池只创建一个对象全局复用。此外ApplicationContext 获取 Bean 对象的功能是其父类 BeanFactory 提供的功能。ApplicationContext 和 BeanFactory 的主要区别有继承关系方面ApplicationContext 继承自 BeanFactoryBeanFactory 提供了基础的访问容器的功能而 ApplicationContext 除了继承了 BeanFactory 的所有功能之外还添加了对国际化支持、资源访问支持以及事件传播等方面的支持。性能方面ApplicationContext 是一次性加载并初始化所有 Bean 对象BeanFactory 是用到了才去加载因此 BeanFactory 更加轻量。3. DI 依赖注入DI (Dependency Injection) 依赖注入是 IoC 的具体实现方式。DI 是一个过程是指 IoC 容器在创建 Bean 时动态地去提供运行时所依赖的资源这里的资源就是对象。简单来说就是容器自动把依赖的 Bean 取出放到某个类的属性中的过程。3.1 三种注入方法关于依赖注入Spring 给我们提供了 3 种方法属性注入将 Autowired 方法加在属性上代码示例将 userService 注入到 UserController 中ControllerclassUserController{AutowiredprivateUserServiceuserService;...}优点代码简单使用方便。缺点不能注入 final 修饰的对象只能用于 IoC 容器非 IoC 容器不可用。构造方法注入在类的构造方法上加上Autowired代码示例将 userService 注入到 UserController 中ControllerclassUserController{privateUserServiceuserService;AutowiredpublicUserController(UserServiceuserService){this.userServiceuserService;}...}如果构造方法唯一可以不加 Autowired会自动注入如果有多个构造方法必须在一个上加上 Autowired指定需要使用哪个构造方法。【注意】使用构造函数必须把无参构造函数显示地添加不管用不用否则报错。优点可以修饰 final 修饰的对象注入对象不会被修改依赖对象在使用前一定会被初始化避免了空指针异常因为是在构造方法中注入的而构造方法在类加载阶段就执行了通用性好此方法是 JDK 支持的其他框架也适用。缺点注入多个对象时代码繁琐。Setter 方法注入在需要注入属性的 Setter 方法上加上 Autowired代码示例将 userService 注入到 UserController 中ControllerclassUserController{privateUserServiceuserService;AutowiredpublicvoidsetUserService(UserServiceuserService){this.userServiceuserService;}...}优点方便在类实例化后重新对该对象进行配置或修改。缺点不能注入 final 修饰的属性注入的对象可能会被改变因为 setter 方法可能会被多次调用。3.2 同一类型有多个 Bean 时怎么注入当我们使用 Bean 注解一个类中将多个 Bean 交给 IoC 容器这时同一类型的 Bean 就会有多个。这种情况下 Autowired 就会报错原因是非唯一的 Bean。Spring 提供了以下几种解决方案Primary设置默认优先的 Bean在其中一个对象上加上 Primary表示是默认要注入的 Bean。ComponentpublicUserInfo{PrimaryBean(user1)//对对象进行重命名publicUseruser1(){...}Bean(user2)publicUseruser2(){...}}Qualifier指定 Bean 的名称在 Qualifier 的属性 value 中指定要注入的 Bean 的名称。【注】Qualifier 不能单独使用必须搭配 Autowired 一起使用。publicclassUserController{Qualifier(valueuserService1)AutowiredprivateUserServiceuserService;...}Resourse默认按名称注入默认根据名称匹配 Bean在 Resourse 的 name 属性中指定要注入的 Bean 的名称。publicclassUserController{Resourse(nameuserService2)privateUserServiceuserService;...}Autowired 和 Resourse 的区别Autowired 是 Spring 提供的注解而 Resourse 是 JDK 提供的注解。Autowired 支持按类型注入而 Resourse 默认按名称注入。相比于 AutowiredResourse 支持更多属性设置如 name 属性根据名称获取 Bean。4. IoC 的好处最后总结一下 IoC 的好处资源集中管理Ioc 容器会帮我们管理一些资源对象等我们使用时只需从 Ioc 容器中去取就可以。我们在创建实例的时候不再需要了解其中的细节无需手动 new 对象降低了使用资源双方的依赖程度耦合度。支持单例复用Spring 默认单例减少了对象的创建开销提升性能。