Spring IoC&DI
一、Spring、Spring boot、Spring MVC之间的区别
1. Spring 是什么
Spring 是包含了众多工具方法的 IoC 容器
(1)容器
容器是用来容纳某种物品的基本装置,比如List/Map就是数据存储容器,Tomcat就是Web容器
(2)loC
1. 概述
loC:Inversion if Control(控制反转),也就是说Spring 是一个“控制反转”的容器,是 Spring 的核心思想
eg. 在类上添加@RestController 和 @Controller 注解,就是把这个对象交给 Spring管理,Spring 框架启动时就会加载该类,即实现了把对象交给Spring管理
这部分代码就是loC容器做的事
IoC容器的优点:
资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
- 资源集中管理: IoC容器会帮我们管理一些资源(对象等),我们需要使用时, 只需要从IoC容器中去取就可以了
- 我们在创建实例的时候不需要了解其中的细节, 降低了使用资源双方的依赖程度, 也就是耦合度
代码方面理解:把材料外包出去,不自己制造
2. 使用
【1】Bean的存储
Spring 是一个loC容器,而作为容器,那【存】和【取】的功能就是最基本的。
Spring 容器 管理的主要是对象,这些对象, 我们称之为"Bean"。我们把这些对象交由Spring管理, 由Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出对象
对于 Spring 框架而言,共有两类注解可以将某个对象交给loC容器管理
- 类注解:@Controller、@Service、@Repository、@Component、@Configuration
- 方法注解:@Bean
Bean 的 名称:Spring bean 是Spring框架在运行时管理的对象,Spring 会给管理的对象起一个名字,而根据这个名称(BeanId)就可以获取到对应的对象
Bean的命名约定:程序开发人员不需要为bean指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该bean生成唯?的名称
命名约定使用Java标准约定作为实例字段名. 也就是说,bean名称以小写字母开头,然后使用驼峰式大小写
- 类名: UserController, Bean的名称为:userController
- 类名: AccountManager, Bean的名称为:accountManager
也有?些特殊情况, 当有多个字符并且第?个和第?个字符都是大写时, 将保留原始的大小写
- 类名: UController, Bean的名称为:UController
- 类名: AManager, Bean的名称为:AManager
@Controller(控制器存储)
@Controller
public class UserController {
public void sayHi(){
System.out.println("这是UserController");
}
}
@SpringBootApplication
public class demo {
public static void main(String[] args) {
//获取Spring上下文对象
ApplicationContext context = SpringApplication.run(demo.class, args);
//从上下文中获取对象,下面是三种不同的获取方式
//根据类的类型获取
UserController userController1 = context.getBean(UserController.class);
//根据名称获取,需要强转
UserController userController2 = (UserController) context.getBean("userController");
//根据名称和类型获取,不需要强转
UserController userController3 = context.getBean("userController", UserController.class);
System.out.println(userController1);
System.out.println(userController2);
System.out.println(userController3);
}
}
获取bean对象, 是父类BeanFactory提供的功能
- ApplicationContext VS BeanFactory(常见面试题)
- 继承关系和功能方面来说:Spring 容器有两个顶级的接口:BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能力,而ApplicationContext 属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
- 从性能方面来说:ApplicationContext 是?次性加载并初始化所有的 Bean 对象,而
BeanFactory 是需要那个才去加载那个,因此更加轻量。(空间换时间)
@Service(服务存储)
@Service
public class UserService {
public void sayHi(){
System.out.println("这是UserService");
}
}
@SpringBootApplication
public class demo {
public static void main(String[] args) {
//获取Spring上下文对象
ApplicationContext context = SpringApplication.run(demo.class, args);
UserService service = context.getBean(UserService.class);
service.sayHi();
}
}
@Repository(仓库存储)、@Configuration(配置存储)、@Component(组件存储)的操作与上述都类似,只需要更改注解
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下?对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//从Spring上下?中获取对象
UserConfiguration userConfiguration = context.getBean(UserConfiguration.cl
//使?对象
userConfiguration.sayHi();
}
}
为什么需要这么多的注解???
让程序员看到类注解之后,就能直接了解当前类的用途
- @Controller:控制层, 接收请求, 对请求进行处理, 并进行响应
- @Servie:业务逻辑层, 处理具体的业务逻辑
- @Repository:数据访问层,也称为持久层. 负责数据访问操作
- @Configuration:配置层. 处理项目中的?些配置信息
应用分层的调用逻辑
方法注解 @Bean
类注解是添加到某个类上的, 但是存在两个问题:
- 使用外部包里的类, 没办法添加类注解
- ?个类, 需要多个对象,比如多个数据源
这种场景, 我们就需要使用方法注解 @Bean,@Bean 注解的bean, bean的名称就是它的方法名
使用时的注意点:
- 在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中
- bean想要生效,还需要被Spring扫描
- 通过 @ComponentScan 来配置扫描路径
- 有时候 @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication 中了。默认扫描的范围是SpringBoot启动类所在包及其子包
@Configuration
public class BeanConfig {
@Bean
public UserInfo userInfo(){
UserInfo user = new UserInfo();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
定义多个对象
@Configuration
public class BeanConfig {
@Bean
public UserInfo userInfo1(){
UserInfo user = new UserInfo();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public UserInfo userInfo2(){
UserInfo user = new UserInfo();
user.setName("lisi");
user.setAge(22);
return user;
}
}
@SpringBootApplication
public class St20231205Application {
public static void main(String[] args) {
//根据名称获取Bean对象
UserInfo userInfo1 = (UserInfo) context.getBean("userInfo1");
UserInfo userInfo2 = (UserInfo) context.getBean("userInfo2");
System.out.println(userInfo1);
System.out.println(userInfo2);
}
}
重命名Bean
@Bean(name = {"u1","user1"})
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下?对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//从Spring上下?中获取对象
User u1 = (User) context.getBean("u1");
//使?对象
System.out.println(u1);
}
}
name={} 可以省略,如下代码所示,如:
@Bean({“u1”,“user1”})
public User user1(){
????????? User user = new User();
????????? user.setName(“zhangsan”);
????????? user.setAge(18);
????????? return user;
}
只有?个名称时, {}也可以省略, 如:
@Bean(“u1”)
public User user1(){
????????? User user = new User();
????????? user.setName(“zhangsan”);
????????? user.setAge(18);
????????? return user;
}
(3)DI
1. 概述
DI: Dependency Injection(依赖注入),即容器在运行期间, 动态的为应用程序提供运行时所依赖的资源,如果程序运行时需要某个资源(对象),此时容器就为其提供这个资源。
所以,DI 和 loC是从不同的角度去描述同一件事情,即都是通过引入loC容器,利用依赖关系注入的方式,实现对象之间的解耦。loC是一种思想,而DI是loC的一种具体实现
依赖注入是?个过程,是指IoC容器在创建Bean时, 去提供运行时所依赖的资源,而资源指的就是对象
2. 使用
关于依赖注入,Spring也给我们提供了三种方式:
- 属性注入(Field Injection)
- 构造方法注入(Constructor Injection)
- Setter 注入(Setter Injection)
(1)属性注入
属性注入是使用 @Autowired 实现的,将 Service 类注入到 Controller 类中
@Controller
public class UserController {
@Autowired
private UserService userService;
public void sayHi() {
System.out.println("Hi,UserController");
userService.sayHi();
}
}
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
@SpringBootApplication
public class demo {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(demo.class, args);
UserController userController = (UserController)context.getBean("userController");
userController.sayHi();
}
}
(2)构造方法注入
@Controller
public class UserController2 {
private UserService userService;
@Autowired
public UserController2(UserService userService){
this.userService = userService;
}
public void sayHi() {
System.out.println("Hi,UserController2");
userService.sayHi();
}
}
(3)Setter注入
@Controller
public class UserController3 {
//注??法3: Setter?法注?
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHi(){
System.out.println("hi,UserController3...");
userService.sayHi();
}
}
(4)三种注入优缺点分析
- 属性注入:
- 优点: 简洁,使用方便
- 缺点:
- 只能用于 IoC 容器,如果是非 IoC 容器不可用,并且只有在使用的时候才会出现 NPE(空指针异常)
- 不能注入?个Final修饰的属性
- 构造函数注?(Spring 4.X推荐)
- 优点:
- 可以注入final修饰的属性
- 注入的对象不会被修改
- 依赖对象在使用前?定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法
- 通用性好, 构造方法是JDK支持的, 所以更换任何框架,他都是适用的
- 缺点:
- 注入多个对象时, 代码会比较繁琐
- 优点:
- Setter注入(Spring 3.X推荐)
- 优点: 方便在类实例之后, 重新对该对象进行配置或者注入
- 缺点:
- 不能注入?个Final修饰的属性
- 注入对象可能会被改变, 因为setter方法可能会被多次调用, 就有被修改的风险
(4)@Autowired存在问题
当同?类型存在多个bean时,使用@Autowired会存在问题。
解决方法
- @Primary:确定默认的实现
@Component
public class BeanConfig {
@Primary //指定该bean为默认bean的实现
@Bean("u1")
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
- @Qualifier:指定当前要注入的bean对象。@Qualifier注解不能单独使用,必须配合@Autowired使用
```java
@Controller
public class UserController {
@Qualifier("user2") //指定bean名称
@Autowired
private User user;
public void sayHi(){
System.out.println("hi,UserController...");
System.out.println(user);
}
}
- @Resource:按照bean的名称进行注入。通过name属性指定要注?的bean的名称
@Controller
public class UserController {
@Resource(name = "user2")
private User user;
public void sayHi(){
System.out.println("hi,UserController...");
System.out.println(user);
}
}
@Autowird 与 @Resource的区别
- @Autowired 是spring框架提供的注解,?@Resource是JDK提供的注解
- @Autowired 默认是按照类型注入,而@Resource是按照名称注?. 相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean
2. 区别概述
Spring:简单来说,Spring 是?个开发应用框架,什么样的框架呢,有这么几个标签:轻量级、?站式、模块化,其目的是用于简化企业级应用程序开发
Spring的主要功能: 管理对象,以及对象之间的依赖关系, ?向切?编程, 数据库事务管理, 数据访问,web框架支持等
但是Spring具备高度可开放性, 并不强制依赖Spring, 开发者可以自由选择Spring的部分或者全
部,Spring可以无缝继承第三方框架,比如数据访问框架(Hibernate 、JPA),web框架(如Struts、JSF)
Spring MVC:Spring MVC是Spring的?个子框架, Spring诞生之后,?家觉得很好用,于是按照MVC模式设计了?个 MVC框架(一些用Spring 解耦的组件), 主要用于开发WEB应用和网络接口,所以,Spring MVC 是?个Web框架
Spring MVC基于Spring进行开发的, 天生的与Spring框架集成. 可以让我们更简洁的进行Web层开发, 支持灵活的 URL 到页面控制器的映射, 提供了强大的约定大于配置的契约式编程支持, 非常容易与其他视图框架集成,如 Velocity、FreeMarker等
Spring Boot:Spring Boot是对Spring的?个封装, 为了简化Spring应用的开发而出现的,中小型企业,没有成本研究自己的框架, 使用Spring Boot 可以更加快速的搭建框架, 降级开发成本, 让开发人员更加专注于Spring应用的开发,而无需过多关注XML的配置和?些底层的实现
Spring Boot 是个脚?架, 插拔式搭建项目, 可以快速的集成其他框架进来
Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的?个MVC 框架,?Spring Boot 是基于Spring的?套快速开发整合包
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!