浙江网站建设制作流程,抖音推广,电子商务平台排名,什么是百度搜索推广文章目录 一、IoC DI 基本知识1.1 IoC 的基本概念#xff1a;1.2 IoC 的优势#xff1a;1.3 DI 介绍#xff1a; 二、IoC 详解2.1 Spring 容器#xff1a;2.2 被存储 Bean 的命名约定#xff1a;2.3 Bean 的存储方式#xff1a;2.3.1 五大类注解#xff1a;2.3.1.… 文章目录 一、IoC DI 基本知识1.1 IoC 的基本概念1.2 IoC 的优势1.3 DI 介绍 二、IoC 详解2.1 Spring 容器2.2 被存储 Bean 的命名约定2.3 Bean 的存储方式2.3.1 五大类注解2.3.1.1 Controller控制器存储2.3.1.2 Service服务存储2.3.1.3 Repository仓库存储2.3.1.4 Configuration配置存储2.3.1.5 Component组件存储2.3.1.6 类注解之间的关系 2.3.2 方法注解Bean 2.4 Bean 重命名2.4.1 五大类注解重命名2.4.2 方法注解重命名 三、DI 详解Autowired3.1 属性注入3.2 Setter 注入3.3 构造方法注入3.4 三种注入优缺点3.5 处理一个类多个对象的注入情况3.5.1 Primary3.5.2 Qualifier3.5.3 Resource 一、IoC DI 基本知识
使用一句话概括 Spring
Spring 是包含了众多工具方法的 IoC 容器。
1.1 IoC 的基本概念
其实 IoC 我们在前面已经使用了我们在前面讲到在类上面添加 RestController 和 Controller 注解就是把这个对象交给 Spring 管理Spring 框架启动时就会加载该类。把对象交给 Spring 管理就是 IoC 思想。
IoCInversion of Control (控制反转)也就是说 Spring 是一个控制反转的容器。
控制反转的概念
控制反转更准确的说是控制权反转。当需要某个对象时传统开发模式中需要自己通过 new 创建对象现在不需要再进行创建把创建对象的任务交给容器程序中只需要依赖注入(Dependency Injection,DI)就可以。
1.2 IoC 的优势
资源不由使用资源的双方管理而由不使用资源的第三方管理这可以带来很多好处。 资源集中管理实现资源的可配置和易管理。 降低了使用资源双方的依赖程度也就是我们说的解耦合。
Spring 就是一种 IoC 容器帮助我们来做了这些资源管理。
1.3 DI 介绍
DIDependency Injection依赖注入。
容器在运行期间动态的为应用程序提供运行时所依赖的资源称之为依赖注入。
IoC 是一种思想也是目标而思想只是一种指导原则最终还是要有可行的落地方案而 DI 就属于具体的实现。所以也可以说DI 是 IoC 的一种实现。
二、IoC 详解
在 Spring 框架中Bean 和对象是等价的 。也就是说下面我们提到的 Bean 其实就是指对象。
2.1 Spring 容器
这里我们来学习一下如何从 Spring 容器中获取对象。
假设 UserController 对象已经被存储在 Spring 容器中。
我们通过下面的代码即可获取到 UserController 对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserController userController context.getBean(UserController.class);//使用对象userController.sayHi();}
}ApplicationContext 翻译过来就是Spring 上下文。
因为对象都交给 Spring 管理了所以获取对象要从 Spring 中获取那么就得先得到 Spring 的上下文。
关于 getBean 要传递的参数下面有详细解释。
getBean 的详解
上述代码是根据类型来查找对象。
如果 Spring 容器中同一个类型存在多个 bean 的话怎么来获取呢
ApplicationContext 也提供了其他获取 bean 的方式ApplicationContext 获取 bean 对象的功能是父类 BeanFactory 提供的功能。
public interface BeanFactory {//以上省略... // 1. 根据bean名称获取bean Object getBean(String var1) throws BeansException;// 2. 根据bean名称和类型获取bean T T getBean(String var1, ClassT var2) throws BeansException;// 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean Object getBean(String var1, Object... var2) throws BeansException;// 4. 根据类型获取bean T T getBean(ClassT var1) throws BeansException;// 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的
beanT T getBean(ClassT var1, Object... var2) throws BeansException;//以下省略...
}
常用的是上述124种这三种方式获取到的 bean 是一样的。
其中 12 种都涉及到根据名称来获取对象。
bean 的名称是什么呢
2.2 被存储 Bean 的命名约定
我们看下官方文档的说明https://docs.spring.io/spring-framework/reference/core/beans/definition.html#beans-beanname 程序开发人员不需要为 bean 指定名称如果没有显式的提供名称Spring 容器将为该 bean 生成唯一的名称。
Bean 默认名称的具体生成规则如下
五大类注解
**普通类名的小驼峰表示法。**例如类名UserControllerBean 的名称为userController。
**如果前两位为大写类名。**例如类名UControllerBean 的名称为UController。
方法注解Bean
**Bean 的名称为方法名。**例如方法名getUserInfoBean 的名称为getUserInfo。
上面都是 spring 自动帮助我们生成的如果觉得不合适程序员可以自己指定只要不重复就行。
2.3 Bean 的存储方式
共有两类注解类型可以实现
类注解Controller、Service、Repository、Configuration、Component。方法注解Bean。
2.3.1 五大类注解
2.3.1.1 Controller控制器存储
使用 Controller 存储 bean 的代码如下所示
import org.springframework.stereotype.Controller;Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(){System.out.println(hi,UserController...);}
}从 Spring 容器中获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserController userController context.getBean(UserController.class);//使用对象userController.sayHi();}
}效果如下 2.3.1.2 Service服务存储
使用 Service 存储 bean 的代码如下所示
Service
public class UserService {public void sayHi(){System.out.println(hello Service~);}
}从 Spring 容器中获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserService userService context.getBean(UserService.class);//使用对象userService.sayHi();}
}效果如下 2.3.1.3 Repository仓库存储
使用 Repository 存储 bean 的代码如下所示
Repository
public class UserRepository {public void sayHi(){System.out.println(Hi,Repository~);}
}从 Spring 容器中获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserRepository userRepository context.getBean(UserRepository.class);//使用对象userRepository.sayHi();}
}效果如下 2.3.1.4 Configuration配置存储
使用 Configuration 存储 bean 的代码如下所示
Configuration
public class UserConfiguration {public void sayHi(){System.out.println(hi,UserConfiguration...);}
}从 Spring 容器中获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserConfiguration userConfiguration context.getBean(UserConfiguration.class);//使用对象userConfiguration.sayHi();}
}效果如下 2.3.1.5 Component组件存储
使用 Component 存储 bean 的代码如下所示
Component
public class UserComponent {public void sayHi(){System.out.println(hi,UserComponent...);}
}从 Spring 容器中获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//从 Spring 上下文中获取对象UserComponent userComponent context.getBean(UserComponent.class);//使用对象userComponent.sayHi();}
}效果如下 为什么要这么多类注解
这个也是和我们前面讲的应用分层是呼应的。让程序员看到类注解之后就能直接了解当前类的用途。
Controller控制层。接收请求对请求进行处理并进行响应。Servie业务逻辑层。处理具体的业务逻辑。Repository数据层也称为持久层。负责数据访问操作。Configuration配置层。处理项目中的一些配置信息。Component组件层。实际开发中如果实在分不清是什么层的就用 Component除了控制层Controller 有特殊的含义。
程序的应用分层调用流程如下 2.3.1.6 类注解之间的关系
查看 Controller / Service / Repository / Configuration 等注解的源码发现 其实这些注解里面都有一个注解 Component 说明它们本身就是属于 Component 的子类。
Component 是一个元注解也就是说可以注解其他类注解如 ControllerService Repository 等。这些注解被称为 Component 的衍生注解。
ControllerService 和 Repository 用于更具体的用例分别在表现层业务逻辑层数据层)在开发过程中如果你要在业务逻辑层使用 Component 或 Service显然 Service 是更好的选择。比如杯子有喝水杯刷牙杯等但是我们更倾向于在日常喝水时使用水杯洗漱时使用刷牙杯。
2.3.2 方法注解Bean
类注解是添加到某个类上的但是存在两个问题
使用外部包里的类没办法添加类注解。一个类需要多个对象比如多个数据源。
这种场景我们就需要使用方法注解 Bean。
注意方法注解要配合类注解使用。
在 Spring 框架的设计中方法注解 Bean 要配合类注解才能将对象正常的存储到 Spring 容器中。
如下代码所示
Configuration
public class UserConfig {Beanpublic UserInfo getUserInfo1(){return new UserInfo(1,zhangsan);}
}通过上面这段代码的写法我们就能获取到外部包里的类。无需在外部包里面加上类注解。
同一个类定义多个对象
Configuration
public class UserConfig {Beanpublic UserInfo getUserInfo1(){return new UserInfo(1,zhangsan);}Beanpublic UserInfo getUserInfo2(){return new UserInfo(2,lisi);}
}通过 Spring 容器获取对象。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);//获取对应的对象UserInfo getUserInfo1 (UserInfo)context.getBean(getUserInfo1);UserInfo getUserInfo2 (UserInfo) context.getBean(getUserInfo2);//进行打印System.out.println(getUserInfo1);System.out.println(getUserInfo2);}
}效果如下 可以看到Bean 可以针对同一个类定义多个对象。
这时如果通过类型来获取 Bean 就会报错显示这个类没有唯一的 Bean。 2.4 Bean 重命名
2.4.1 五大类注解重命名
直接在注解里面加上名字即可或者加上 value 名字。
Repository(u1)
public class UserRepository {public void sayHi(){System.out.println(Hi,Repository~);}
}获取 Bean。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);UserRepository userRepository context.getBean(u1, UserRepository.class);userRepository.sayHi();}
}效果如下 2.4.2 方法注解重命名
可以通过设置 name 属性给 Bean 对象进行重命名操作如下代码所示
Configuration
public class UserConfig {Bean(name {h1,h2})public UserInfo getUserInfo1(){return new UserInfo(1,zhangsan);}
}其中 name 可以省略只有一个参数的情况如果只有一个名称时{}也可以省略。
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);UserInfo userInfo context.getBean(h1, UserInfo.class);System.out.println(userInfo);}
}三、DI 详解Autowired
依赖注入是一个过程是指 IoC 容器在创建 Bean 时去提供运行时所依赖的资源而资源指的就是对象。、
关于依赖注入Spring 也给我们提供了三种方式 属性注入Field Injection Setter 注入Setter Injection 构造方法注入Constructor Injection
后续的注入演示代码将采用 Service 类注入到 Controller 类中。为了帮助大家理解下面先给出 Service 类。
Service
public class UserService {public void sayHi(){System.out.println(hello Service~);}
}3.1 属性注入
属性注入是使用 Autowired 实现的。
Controller 类的实现代码如下
Controller // 将对象存储到 Spring 中
public class UserController {Autowiredprivate UserService userService;public void sayHi(){System.out.println(hi,UserController...);userService.sayHi();}
}调用 Controller 中的 sayHi 方法
SpringBootApplication
public class Spring20240928iocApplication {public static void main(String[] args) {//获取 Spring 上下文对象ApplicationContext context SpringApplication.run(Spring20240928iocApplication.class, args);UserController userController context.getBean(UserController.class);userController.sayHi();}
}效果如下 3.2 Setter 注入
Setter 注入和属性的 Setter 方法实现类似只不过在设置 set 方法的时候需要加上 Autowired 注解如下代码所示
Controller // 将对象存储到 Spring 中
public class UserController {private UserService userService;Autowiredpublic void setUserService(UserService userService){this.userService userService;}public void sayHi(){System.out.println(hi,UserController...);userService.sayHi();}
}由于获取 Bean 的方式和效果是一样的所以 Setter 注入和构造方法注入就不再赘述。
3.3 构造方法注入
构造方法注入是在类的构造方法中实现注入如下代码所示
Controller // 将对象存储到 Spring 中
public class UserController {private UserService userService;Autowiredpublic UserController(UserService userService){this.userService userService;}public void sayHi(){System.out.println(hi,UserController...);userService.sayHi();}
}注意如果类只有一个构造方法那么 Autowired 注解可以省略如果类中有多个构造方法 那么需要添加上 Autowired 来明确指定到底使用哪个构造方法。
3.4 三种注入优缺点
属性注入
优点简洁使用方便。
缺点 只能用于 IoC 容器如果是非 IoC 容器不可用。 不能注入一个 Final 修饰的属性。
Setter注入Spring 3.X推荐
优点方便在类实例之后重新对该对象进行配置或者注入。
缺点不能注入一个 Final 修饰的属性。
构造函数注入Spring 4.X推荐
优点
可以注入 final 修饰的属性。通用性好构造方法是 JDK 支持的所以更换任何框架它都是适用的。
缺点注入多个对象时构造方法会写很长。
3.5 处理一个类多个对象的注入情况
当同一类型存在多个 bean 时实用 Autowired 会存在问题。
Configuration
public class UserConfig {Beanpublic UserInfo getUserInfo1(){return new UserInfo(1,zhangsan);}Beanpublic UserInfo getUserInfo2(){return new UserInfo(2,lisi);}
}报错如下 报错的原因是非唯一的 Bean 对象。
如何解决上述问题呢Spring提供了以下几种解决方案 Primary Qualifier Resource
3.5.1 Primary
使用 Primary 注解当存在多个相同类型的 Bean 注入时加上 Primary 注解来确定默认的实现。
Configuration
public class UserConfig {PrimaryBeanpublic UserInfo getUserInfo1(){return new UserInfo(1,zhangsan);}Beanpublic UserInfo getUserInfo2(){return new UserInfo(2,lisi);}
}3.5.2 Qualifier
使用 Qualifier 注解指定当前要注入的 bean 。在 Qualifier 的 value 属性中指定注入 bean 的名称。
注意Qualifier 注解不能单独使用必须配合 Autowired 使用。
Controller // 将对象存储到 Spring 中
public class UserController {Qualifier(getUserInfo2)Autowiredprivate UserInfo userInfo;public void printUserInfo(){System.out.println(userInfo);}
}3.5.3 Resource
使用 Resource 注解是按照 bean 的名称进行注入。通过 name 属性指定要注入的 bean 的名称。
Controller // 将对象存储到 Spring 中
public class UserController {Resource(name getUserInfo1)private UserInfo userInfo;public void printUserInfo(){System.out.println(userInfo);}
}常见面试题Autowird 与 Resource 的区别
Autowired 是 spring 框架提供的注解而 Resource 是 JDK 提供的注解。Autowired 默认是按照类型注入而 Resource 是按照名称注入。相比于 Autowired 来说Resource 支持更多的参数设置。
使用习惯
如果一个类的 Bean 只有一个的话使用 Autowired。
如果一个类的 Bean 有多个的话使用 Resource。
结语 其实写博客不仅仅是为了教大家同时这也有利于我巩固知识点和做一个学习的总结由于作者水平有限对文章有任何问题还请指出非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注这可以激励我写出更加优秀的文章。