【JavaEE 进阶(三)】Spring IoC&DI

❣博主主页: 33的博客
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多进阶知识

在这里插入图片描述

1.前言

本篇文章将介绍Spring IOC的概念和Spring DI的概念,以及 IOC和 DI的实现。

2.Spring是什么?

通过前⾯的学习,我们知道了Spring是⼀个开源框架,他让我们的开发更加简单.他⽀持⼴泛的应⽤场景,有着活跃⽽庞⼤的社区,这也是Spring能够⻓久不衰的原因.但是这个概念相对来说,还是⽐较抽象.我们⽤⼀句更具体的话来概括Spring,那就是**:Spring是包含了众多⼯具⽅法的IoC容器**

3.IOC&DI入门

3.1IOC

那么IOC是什么呢?IOC是Spring的一种思想,其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加@RestController 和@Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交给Spring管理,就是IoC思想。IOC(Inversion of Control (控制反转))就是把控制权交给Spring管理。
例如当我们设计汽车的时候,但汽车需要车身:

 public class NewCarExample {
 public static void main(String[] args) {
 Car car = new Car();
 car.run();
 }
 }
// 汽车对象
 static class Car {
 private Framework framework;
 public Car() {
            framework = new Framework();
            System.out.println("Car init....");
        }
  public void run(){
         System.out.println("Car run...");
     }
  }
//车身对象
  static class Framework {
        private String color;
        public Tire(){
            this. color= "red";
            System.out.println("颜色:" +color );
        }
    }
 }

但这样设计,如果我想修改颜色或者是构造方法,那么整个程序都会改动。那么我们就把创建子类的方式改为注入传递。

 public static void main(String[] args) {
 Framework framework = new Framework("blue");
 Car car = new Car(framework);
 car.run();
 }
 static class Car {
 private Framework framework;
 public Car(Framework framework) {
 this.framework = framework;
 System.out.println("Car init....");
 }
 public void run() {
 System.out.println("Car run...");
 }
}
static class Framework {
        private String color;
        public Framework(String color){
            this. color= color;
            System.out.println("颜色:" +color );
        }
    }
 }

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

3.2DI

DI: DependencyInjection(依赖注入)容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注入。程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注入(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引入IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。

3.3IoC&DI使用

我们把Framework,和car交给Spring管理,那么我们只需要使用注解 :@Component,当需要使用的时候注入依赖,使用注解: @Autowired

public class CarController {
 @Autowired
 private Car car;
 public CarController(){
	 car.run;
 }
} 
//汽车
 @Component
 static class Car {
 @Autowired
 private Framework framework;
 public void run() {
 System.out.println("Car run...");
 }
}
//车身
@Component
static class Framework {
        private String color;
        public Framework() {
            this.color = "red";
            System.out.println("颜色:" + color);
        }
        public  Framework(String color){
            this. color= color;
            System.out.println("颜色:" +color );
        }
    }
 }

4.Ioc实现

类注解:@Controller、@Service、@Repository、@Component、@Configuration.
⽅法注解:@Bean.

4.1@Controller

 @Controller//一般用于注解controller
public class UserController {
 public void sayHi(){
 System.out.println("hi,UserController...");
 }
 }

4.2 @Service

@Service
public class UserService {
    public void doService(){
        System.out.println("do Service....");
    }
}

4.3@Repository

@Repository
public class UserRepository {
        public void doRespository(){
            System.out.println("do  Respository...");
        }
}

4.4@Configuration

@Configuration
public class UserConfiguration {
    public void doConfiguration(){
        System.out.println("do Configuration...");
    }
}

4.5@Component

public class UserComponent {
    public void doComponent(){
        System.out.println("do component...");
    }
}

4.6类注解区别

@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息
当我们去看源码时,会发现@Service、@Repository、@Configuration.中都包含@Component说明这些注解本身属于@Component的“子类”。
在这里插入图片描述
但@Controller注解比较特殊,当我们一个类中又url接口时,只能使用@Controller,其他四个一般清空下可以混用。

4.7@Bean

类注解是添加到某个类上的,但是存在两个问题:使⽤外部包⾥的类, 没办法添加类注解
⼀个类,需要多个对象,⽐如多个数据源这种场景, 我们就需要使⽤⽅法注解@Bean,在Spring框架的设计中,⽅法注解@Bean 要配合类注解才能将对象正常的存储到Spring容器中.

public class User {
    String name;
    public User(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Configuration
public class UserInfo {
    @Bean
    public User user(){
        return new User("张三");
    }
    @Bean 
    User user2(){
        return new User("李四");
    }
}

5.Bean的获取

5.1通过类型获取

既然已经把 UserController交给了Spring管理,那么如何获取呢?
从上下文对象中获取:

//获取Spring上下问对象
 ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
 //根据类型获取对象
 UserController userController = context.getBean(UserController.class);
 //通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();

5.2Bean的名称

除了通过类型获取,也可以通过名称获取,那么Bean的名称是说明呢?我们先来看一看官网的介绍:
在这里插入图片描述
类注解命名约定
1.bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写
例如:
类名:UserController, Bean的名称为:userController
类名:AccountManager,Bean的名称为: accountManager
2.有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写
类名:UController, Bean的名称为:UController
类名:AManager,Bean的名称为: AManage
方法注解命名约定:
方法名就是bean的名称

5.3通过名称获取

ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();

5.4结果

在这里插入图片描述
我们发现方法调用成功,但当我们打印引用地址的时候发现地址一样
在这里插入图片描述
那么就说明调用的是同一个对象,通过源码我们可以知道获取bean对象是父类BeanFactory提供的功能。
ApplicationContext VS BeanFactory(常⻅⾯试题)
继承关系和功能方面来说:Spring容器有两个顶级的接⼝:BeanFactory和
ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒,⽽
ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等方面的支持.
从性能方面来说:ApplicationContext是⼀次性加载并初始化所有的Bean对象,⽽BeanFactory 是需要那个才去加载那个,因此更加轻量。

6.DI实现

上面我们讲解了IOC实现的具体内容,接下来讲DI事项的内容,DI其实就是一个依赖注入的过程,简单来说就是把对象取出来放在某个类的属性中。
Spring给我们提供了三种方式注入:

1.属性注⼊(FieldInjection)
2. 构造⽅法注⼊(ConstructorInjection)
3. Setter 注⼊(SetterInjection)

6.1属性注入

就是使用@Autowired 实现的,将Service类注⼊到Controller类中。 Service 类的实现代码如下:

@Controller
 public class UserController { 
 @Autowired
 private UserService userService;
 public void sayHi(){
 System.out.println("hi,UserController...");
 userService.sayHi();
 }
 }

6.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();
 }
 }

注意
如果一个类只有一个构造方法,那么@Autowired 可以省略,如果一个类有多个构造方法默认使用无参的构造方法,那么此时需要添加@Autowired 来明确指定到底使⽤哪个构造⽅法。

6.3 Setter注入

@Controller
public class UserController3 {
private UserService userService;
 @Autowired
 public void setUserService(UserService userService) {
 this.userService = userService;
 }
 public void sayHi(){
 System.out.println("hi,UserController3...");
 userService.sayHi();
 }
 }

6.4三种注入优缺点

属性注⼊
优点:简洁,使⽤⽅便;
缺点:只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
不能注⼊⼀个Final修饰的属性
构造函数注入(Spring4.X推荐)
优点:可以注⼊final修饰的属性
注⼊的对象不会被修改
依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
缺点:注入多个对象时,代码会⽐较繁琐
Setter注⼊(Spring3.X推荐)
优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
缺点:不能注入⼀个Final修饰的属性
注⼊对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险.

6.5@Autowired问题

当一个类型存在多个对象时,使用@Autowired就会存在问题,例如:

@Configuration
public class UserInfo {
    @Bean
    public User user(){
        return new User("张三");
    }
    @Bean User user2(){
        return new User("李四");
    }
}
@Autowired
private User Uers;
public void sayhi(){
    System.out.println("hi,UserController");
    System.out.println(Uers);
 }

出现错误:
在这里插入图片描述
报错原因,非唯一的bean对象。那么如何解决呢?可以使用@Primary、@Qualifier、@Resource注解。
当有多个相同类型的对象时,用@Primary可以确定默认的实现:

@Configuration
public class UserInfo {
    @Bean
    @Primary
    public User user(){
        return new User("张三");
    }
    @Bean User user2(){
        return new User("李四");
    }
}

在这里插入图片描述
使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称。
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Autowired
    @Qualifier("user2")
    private User Uers;
    public void sayhi(){
        service.doService();
        System.out.println("hi,UserController");
        System.out.println(Uers);
    }

在这里插入图片描述
使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

  @Resource(name = "user2")
    private User Uers;
    public void sayhi(){
        service.doService();
        System.out.println("hi,UserController");
        System.out.println(Uers);
    }

注入顺序:
在这里插入图片描述
@Autowired执行流程:

按照类型查找:
如果没有找到就抛出异常
如果查找到一个就直接插入,
如果找到多个就根据名称查找,找到就注入,没有找到就抛出异常

@Qualifier+@Autowired执行流程:

直接按照类型+名称查找
如果@Autowired对应的类型只有一个,但是名称和@Qualifier名称不一样,注入也是失败的

@Autowird与@Resource的区别
@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
@Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired 来说@Resource ⽀持更多的参数设置,例如name设置,根据名称获取Bean。

7.总结

Spring, Spring Boot和SpringMVC的关系以及区别
Spring: 简单来说,Spring是⼀个开发应⽤框架,什么样的框架呢,有这么⼏个标签:轻量级、⼀站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发.
Spring的主要功能:管理对象,以及对象之间的依赖关系,⾯向切⾯编程,数据库事务管理,数据访问,web框架⽀持等.但是Spring具备⾼度可开放性,并不强制依赖Spring,开发者可以⾃由选择Spring的部分或者全部,Spring可以⽆缝继承第三⽅框架,⽐如数据访问框架(Hibernate、JPA),web框架(如Struts、JSF)
Spring MVC:SpringMVC是Spring的⼀个⼦框架,Spring诞⽣之后,⼤家觉得很好⽤,于是按照MVC模式设计了⼀个MVC框架(⼀些⽤Spring解耦的组件),主要⽤于开发WEB应⽤和⽹络接⼝,所以Spring MVC是⼀个Web框架. Spring MVC基于Spring进⾏开发的,天⽣的与Spring框架集成.可以让我们更简洁的进⾏Web层开发,⽀持灵活的URL到⻚⾯控制器的映射,提供了强⼤的约定⼤于配置的契约式编程⽀持,⾮常容易与其他视图框架集成,如Velocity、FreeMarker等。
Spring Boot: Spring Boot是对Spring的⼀个封装,为了简化Spring应⽤的开发⽽出现的,中⼩型企业,没有成本研究⾃⼰的框架,使⽤SpringBoot可以更加快速的搭建框架,降级开发成本,让开发⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现。Spring Boot 是个脚⼿架,插拔式搭建项⽬,可以快速的集成其他框架进来.⽐如想使⽤SpringBoot开发Web项⽬,只需要引⼊SpringMVC框架即可,Web开发的⼯作是SpringMVC完成的,⽽不是SpringBoot,想完成数据访问,只需要引⼊Mybatis框架即可.Spring Boot只是辅助简化项⽬开发的,让开发变得更加简单,甚⾄不需要额外的web服务器,直接⽣成jar包执⾏即可.
最后⼀句话总结:SpringMVC和SpringBoot都属于Spring,SpringMVC是基于Spring的⼀个MVC框架,⽽SpringBoot是基于Spring的⼀套快速开发整合包

下期预告:Spring Boot配置文件

  • 117
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 82
    评论
评论 82
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值