Spring IoC

目录

一.IoC

 1.1什么是IoC?

1.2 loC容器具备以下优点: 

      二.DI

三.Bean的储存(五大注解)

3.1 @Controller(控制器存储) 

3.2 @Service(服务存储) 

3.3 @Repository(仓库存储) 

 3.4 @Component  (组件存储) 

 3.5 @Configuration(配置存储)

3.6为什么要这么多类注解?

3.6.1方法注解 @Bean

小总结:

四.DI 详解 

4.1属性注入

4.1构造方法注入 

4.2 Setter方法注入  

4.3三种注⼊优缺点分析:

​编辑 


一.IoC

               通过这篇博客 Spring Web MVC-优快云博客 我们已经了解Spring是一个开源框架,他可以让我们开发更加简单。

                用具体的话概括Spring的话,就是:Spring是包含了众多工具方法的IoC容器

 1.1什么是IoC?

           loC是Spring的核心思想

     

          其实loC我们在前面已经使用了,在类上面添加@RestController@Controller注解,就是把这个对象交给Spring管理,Spring 框架启动时就会加载该类.把对象交给Spring管理,就是loC思想. 

        IoC: Inversion of Control (控制反转) 也就是说 Spring 是⼀个"控制反转"的容器
                什么是控制反转呢?也就是控制权反转.什么的控制权发生了反转?获得依赖对象的过程被反转了也就是说,当需要某个对象时,传统开发模式中需要自已通过new创建对象,现在不需要再进行创建,把创建对象的任务交给容器,程序中只需要依赖注入(DependencyInjection,Dl)就可以了,这个容器称为:loC容器。Spring是一个loC容器,所以有时Spring也称为Spring容器.

        控制反转是一种思想,生活中处处体现

           例如:⾃动驾驶, 传统驾驶⽅式, ⻋辆的横向和纵向驾驶控制权由驾驶员来控制, 现在交给了驾驶⾃ 动化系统来控制, 这也是控制反转思想在⽣活中的实现

举个案例:

        需求:造一辆车 

   传统开发的实现思路:

        先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。这里就出现了一个"依赖"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子.

问题是:当最底层代码改动之后,整个调用链上的所有代码都需要修改.  (耦合高

IoC开发实现思路:

 


改进之后的控制权发生的反转,不再是使用方对象创建并控制依赖对象了,而是把依赖对象注入将当前对象中,依赖对象的控制权不再由当前类控制了.

优势在于 耦合低,这样的话,即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是loC的实现思想。从⽽实现了更加灵活、通⽤的程序设计了

1.2 loC容器具备以下优点: 

资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。

  1. 资源集中管理:loC容器会帮我们管理一些资源(对象等),我们需要使用时,只需要从loC容器中去取就可以了
  2. 我们在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度。

      二.DI

        DI:(依赖注入)

       容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。

        loC是一种思想,也是"目标",而思想只是一种指导原则,最终还是要有可行的落地方案,而DI就属于具体的实现。所以也可以说,DI是loC的一种实现

既然Spring是一个loC(控制反转)容器,作为容器,那么它就具备两个最基础的功能:

Spring 容器管理的主要是对象,这些对象,我们称之为"Bean".

三.Bean的储存(五大注解)

共有两类注解类型实现:

  1.  类注解:@Controller  @Service  @Component  @Repository  @Configuration                    ( 注意:如果类名前两个字符大写,则bean的名称是类名本身)
  2.  方法注解:@Bean  (Bean名就是方法名)

3.1 @Controller(控制器存储) 

 使用@Controller存储 bean的代码如下 :

@Controller //将对象存储到Spring中
public class UController {
    public void sayHi(){
        System.out.println(" hi  UController");
    }
}

如何判断是否存到容器当中了呢

下面尝试从Spring容器中获取对象 (共有三种方式):

读取 bean 的代码: @SpringBootApplication 

@SpringBootApplication
public class SpringIocDemoApplication {

    public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext run = SpringApplication.run(SpringIocDemoApplication.class, args);
        /*
        * 常用获取bean的方法(三种)
        * 输出三种方式,结果证明地址一样,对象一样
        * */
        //方式一:根据类型,从Spring上下⽂中获取对象
        userController bean = run.getBean(userController.class);
        bean.sayHi();
        System.out.println(bean);

        //方式二:根据bean名,从Spring上下⽂中获取对象
        userController bean1 = (userController)run.getBean("userController");
        bean1.sayHi();
        System.out.println(bean1);

        //方式三://根据bean类型+名称, 从Spring上下⽂中获取对象
        userController bean2 = run.getBean("userController", userController.class);
        bean2.sayHi();
        System.out.println(bean2);
    }
}

 

3.2 @Service(服务存储) 

使⽤ @Service 存储 bean 的代码如下所⽰:
@Service
public class UserService {
    public void sayHi(){
        System.out.println("Hi  UserService");
    }
}

从Spring容器中获取对象
 public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext run = SpringApplication.run(SpringIocDemoApplication.class, args);
        //方式一:根据类型,从Spring上下⽂中获取对象
        UserService userService = run.getBean(UserService.class);
        userService.sayHi();
        System.out.println(userService);
}

3.3 @Repository(仓库存储) 

使⽤ @Repository 存储 bean 的代码如下所⽰:
@Repository
public class UserRepository {
    public void sayHi(){
        System.out.println("Hi   UserRepository");
    }
}

从Spring容器中获取对象

  public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext run = SpringApplication.run(SpringIocDemoApplication.class, args);
        //方式一:根据类型,从Spring上下⽂中获取对象
        UserRepository userRepository = run.getBean(UserRepository.class);
        userRepository.sayHi();
        System.out.println(userRepository);
}

 3.4 @Component  (组件存储) 

使⽤ @Component存储 bean 的代码如下所⽰:


@Component
public class ComPonent {
    public void sayHi(){
        System.out.println("Hi   ComPonent");
    }
}

从Spring容器中获取对象:

    public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext run = SpringApplication.run(SpringIocDemoApplication.class, args);
        //方式一:根据类型,从Spring上下⽂中获取对象
        UserComPonent UserComPonent = run.getBean(UserComPonent.class);
        UserComPonent.sayHi();
        System.out.println(UserComPonent);
}

 3.5 @Configuration(配置存储)

使⽤ @Configuration存储 bean 的代码如下所⽰:

@Configurable
public class UserConfiguration {
    public void sayHi(){
        System.out.println("Hi   UserConfiguration");
    }
}

从Spring容器中获取对象

  public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext run = SpringApplication.run(SpringIocDemoApplication.class, args);
        //方式一:根据类型,从Spring上下⽂中获取对象
        UserConfiguration userConfiguration = run.getBean(UserConfiguration.class);
        userConfiguration.sayHi();
        System.out.println(userConfiguration);
  }

3.6为什么要这么多类注解?

这个也是和咱们前面讲的应用分层是呼应的.让程序员看到类注解之后,就能直接了解当前类的用途。

  • @Controller:控制层,接受请求,对请求进行处理,并进行响应
  • @Servie:业务逻辑层,处理具体的业务逻辑
  • @Repository:数据访问层,也称为持久层,负责数据访问操作
  • @Configuration:配置层,处理项目中的一些配置信息                                                    这四个类全是@Component的衍生类,功能实现上,除了@Controller类其他是可以混用的(不推荐)

 

3.6.1方法注解 @Bean

类注解是添加到某个类上的,但是存在俩个问题:

  1. 使用外部包里的类,没办法添加类注解
  2. 一个类中,需要多个对象,

以上两种场合,我们就需要使用方法注解@Bean 必须搭配五大类使用

 注意:

        只有在五大注解下@bean才会生效 , 查看启动类所在的目录及其子孙目录

        在获取对象时 ,发现有两个或多个时,可以采用bean名+类名,来获取对象

小总结:

程序被Spring管理,需要具备以下条件:
1.被Spring扫描到(默认扫描路径是 启动类所在的目录,包含子目录)


2.需要配置五大注解和@Bean使用

四.DI 详解 

依赖注入是一个过程,是指IoC容器在创建Bean时,去提供运行是所以来的资源,而资源指的就是对象,需要使用@Autowired这个注解,来完成依赖注入。

简单来说,就是把对象取出来放到某个类的属性中

Spring提供了三种方式进行依赖注入:

  1. 属性注入(Field Injection)
  2. 构造方法注入 (Constructor Injection)
  3. Setter注入 (Setter Injection)                 

                                                                           

4.1属性注入

 演示 属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中

 注意:无法注入一个final修饰的属性       

Service 代码如下:

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

Controller 代码如下: 

@Controller //将对象存储到spring中
public class UserController {
    //注入方法一:屬性注入
    @Autowired
    public UserService userService;
    
    public void sayHi(){
        System.out.println("Hi   UserController");
    }
}
获取 Controller 中的 sayHi⽅法:

4.1构造方法注入 

  • 如果类中只有一个构造方法,@Autowired注解可以省略,
  • 如果类中有多个构造方法,那么需要@Autowired来指定到底使用哪个构造方法              
  • 构造函数规范:   如果添加构造函数,把无参构造函数显示添加
@Controller //将对象存储到spring中
public class UserController {
    //注入方法二:构造方法注入

    public UserService userService;
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(){
        System.out.println("Hi   UserController");
        userService.sayHi();
    }
}

4.2 Setter方法注入  

Setter注入和属性的Setter方法实现类似,只不过在设置set方法的时候需要加上@Autowired注解

@Controller //将对象存储到spring中
public class UserController {
    //注入方法三:Setter方法注入

    public UserService userService;
   
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(){
        System.out.println("Hi   UserController");
        userService.sayHi();
    }
}

 

当程序中同一个类型有多个对象时,使用@AutoWired会报错(一些情况下) 解决方法:

Spring提供了以下⼏种解决⽅案:
  • @Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现 
  • @Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤
  • 使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
       解决思想:指定Bean的名称
                       指定Bean

 @Autowird与@Resource的区别

 

4.3三种注⼊优缺点分析:

 

Autowired装配顺序 :

 

### Spring IOC 原理及实现 #### 1. 控制反转(IOC)的概念 控制反转(Inversion of Control,简称 IOC)是一种设计思想,旨在将对象的创建和管理从应用程序代码中分离出来。通过 IOC,开发者无需手动管理对象的生命周期和依赖关系,而是由框架负责这些任务。这种思想使得开发者可以专注于业务逻辑的实现,而不需要关心对象之间的交互细节[^1]。 #### 2. 依赖注入(DI) 依赖注入(Dependency Injection,简称 DI)是实现 IOC 的一种方式。DI 的核心在于通过外部配置或注解的方式,将对象的依赖关系注入到目标对象中,而不是由对象自己负责依赖的创建和管理。依赖注入有三种主要形式:构造器注入、Setter 方法注入和字段注入[^4]。 #### 3. Spring IOC 容器的核心接口 Spring 框架提供了两种主要的 IOC 容器接口: - **BeanFactory**:这是 Spring 框架的基础接口,面向 Spring 内部使用。它负责配置、创建和管理 Bean 的生命周期。 - **ApplicationContext**:这是一个更高级的容器接口,面向开发者使用。它扩展了 BeanFactory 的功能,提供了更多的企业级特性,如国际化支持、事件传播等。在实际开发中,通常使用 ApplicationContext 而非 BeanFactory[^2]。 #### 4. Spring IOC 的实现方式 Spring IOC 的实现主要包括以下几个方面: ##### (1) 元数据解析 Spring 使用 XML 文件、Java 注解或 Java 配置类来定义 Bean 的元数据。例如,通过 `<bean>` 标签在 XML 文件中定义 Bean,或者使用 `@Component`、`@Service` 等注解在 Java 类上声明 Bean[^5]。 示例代码(XML 配置): ```xml <bean id="userDao" class="com.mayuanfei.springioc.dao.impl.UserDaoImpl" /> ``` 示例代码(注解配置): ```java @Component public class UserDaoImpl implements UserDao { // 实现方法 } ``` ##### (2) 依赖注入 Spring 通过反射机制解析 Bean 的依赖关系,并将其注入到目标对象中。以下是一个简单的依赖注入示例: 示例代码(字段注入): ```java @Service public class UserService { @Autowired private UserDao userDao; // 自动注入 UserDao } ``` ##### (3) 生命周期管理 Spring 容器会管理 Bean 的整个生命周期,包括初始化、运行时和销毁阶段。开发者可以通过实现特定的接口(如 `InitializingBean` 和 `DisposableBean`)或使用注解(如 `@PostConstruct` 和 `@PreDestroy`)来定制 Bean 的生命周期行为。 示例代码(生命周期管理): ```java @Component public class MyBean { @PostConstruct public void init() { System.out.println("Bean 初始化"); } @PreDestroy public void destroy() { System.out.println("Bean 销毁"); } } ``` ##### (4) 扩展机制 Spring 提供了丰富的扩展点,允许开发者自定义容器的行为。例如,通过实现 `BeanFactoryPostProcessor` 或 `BeanPostProcessor` 接口,可以在 Bean 初始化前后插入自定义逻辑[^4]。 #### 5. Spring IOC 的优势 Spring IOC 的核心优势包括: - **解耦**:对象之间不再直接依赖具体实现,而是通过接口或抽象类进行交互。 - **灵活性**:通过配置文件或注解动态管理 Bean,便于修改和扩展。 - **可维护性**:集中处理对象的创建和依赖关系,降低了代码复杂度。 ### 总结 Spring IOC 是一种通过容器管理对象生命周期和依赖关系的设计模式。其核心原理包括元数据解析、依赖注入、生命周期管理和扩展机制。通过这些机制,Spring 实现了对象控制权的反转,从而提高了系统的解耦性、灵活性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值