详解Spring面试IoC

Spring IOC

一、前言

Spring核心容器的主要组件是Bean工厂(BeanFactory),Bean工厂使用控制反转(IoC)模式来降低程序代码之间的耦合度,并提供了面向切面编程(AOP)的实现。

简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的容器框架。

在具体介绍IoC和AOP之前,我们先简要说明下Spring常用注解

1、@Controller:用于标注控制器层组件

2、@Service:用于标注业务层组件

3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称

4、@Repository:用于标注数据访问组件,即DAO组件

5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名

6、@Scope("prototype"):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。

由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。

7、@Autowired:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

8、@Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。

  • 简单点说,就是,能够明确该类是一个控制器类组件的,就用@Controller;
  • 能够明确是一个服务类组件的,就用@Service;
  • 能够明确该类是一个数据访问组件的,就用@Repository;
  • 不知道他是啥或者不好区分他是啥,但是就是想让他动态装配的就用@Component。

@Controller、@Service、@Component、@Repository都是类级别的注解,如果一个方法也想动态装配,就用@Bean。

当我们想按类型进行自动装配时,就用@Autowired;当我们想按名称(beanID)进行自动装配时,就用@Resource;当我们需要根据比如配置信息等来动态装配不同的组件时,可以用getBean(“beanID”)。

二、 IoC和DI

什么是 IoC和DI?

IOC(Inversion of Control)控制反转

例如:现有类 A 依赖于类 B

  • 传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
  • 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面过去即可。

(1) 什么是控制反转呢?

  • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。
    • 业务层要用数据层的类对象,以前是自己new
    • 现在自己不new了,交给别人[外部]来创建对象
    • 别人[外部]就反转控制了数据层对象的创建权
    • 这种思想就是控制反转
    • 别人[外部]指定是什么呢?继续往下学

(2) Spring和IOC之间的关系是什么呢?

  • Spring技术对IOC思想进行了实现
  • Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"
  • IOC思想中的别人[外部]指的就是Spring的IOC容器

(3) IOC容器的作用以及内部存放的是什么?

  • IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
  • 被创建或被管理的对象在IOC容器中统称为Bean
  • IOC容器中放的就是一个个的Bean对象

(4) 当IOC容器中创建好service和dao对象后,程序能正确执行么?

  • 不行,因为service运行需要依赖dao对象
  • IOC容器中虽然有service和dao对象
  • 但是service对象和dao对象没有任何关系
  • 需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系

像这种在容器中建立对象与对象之间的绑定关系就要用到DI:

DI(Dependency Injection)依赖注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RyTHbZ8n-1672399074574)(E:\工作面试题\Java面试\自己学习笔记\image\1629735078619.png)]

(1) 什么是依赖注入呢?

  • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
    • 业务层要用数据层的类对象,以前是自己new
    • 现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来
    • 这种思想就是依赖注入

(2) IOC容器中哪些bean之间要建立依赖关系呢?

  • 这个需要程序员根据业务需求提前建立好关系,如业务层需要依赖数据层,service就要和dao建立依赖关系

为什么叫控制反转

控制 :指的是对象创建(实例化、管理)的权力

反转 :控制权交给外部环境(Spring 框架、IoC 容器)

img

使用IoC:对象不用卡法这创建,而是交给Spring框架完成(基于XML和基于注解)

基于XML:

开发者把需要创建的对象在XML中进行配置,Spring框架读取这个配置文件,根据配置文件的内容来创建对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    <bean class="com.southwind.ioc.DataConfig" id="config">
        <property name="driverName" value="Driver"></property>
        <property name="url" value="localhost:8080"></property>
        <property name="username" value="root">
        </property>
        <property name="password" value="root">
        </property>
    </bean>
</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    public static void main(String[] args) {
        // DataConfig dataConfig = new DataConfig();
        // dataConfig.setDriverName("Driver");
        //dataConfig.setUrl("localhost:3306/dbname");
        // dataConfig.setUsername("root");
        // dataConfig.setPassword("root");
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(context.getBean("config"));
    }
}
基于注解:
  1. 配置类(@Configuration

用一个 Java 类来替代 XML 文件,把在 XML 中配置的内容放到配置类中。

import com.southwind.ioc.DataConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfiguration {
    @Bean(value = "config")
    public DataConfig dataConfig(){
        DataConfig dataConfig = new DataConfig();
        dataConfig.setDriverName("Driver");
        dataConfig.setUrl("localhost:3306/dbname");
        dataConfig.setUsername("root");
        dataConfig.setPassword("root");
        return dataConfig;
    }
}
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
System.out.println(context.getBean("config"));
  1. 扫包+配置

更简单的方式,不再需要依赖于 XML 或者配置类,而是直接将 bean 的创建交给目标类,在目标类添加注解来创建。

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class DataConfig {
    @Value("localhost:3306")
    private String url;
    @Value("Driver")
    private String driverName;
    @Value("root")
    private String username;
    @Value("root")
    private String password;
}
ApplicationContext context = new AnnotationConfigApplicationContext("com.southwi
nd.ioc");
System.out.println(context.getBean(DataConfig.class));

自动创建对象,完成依赖注入

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class GlobalConfig {
    @Value("8080")
    private String port;
    @Value("/")
    private String path;
    @Autowired
    private DataConfig dataConfig;
}

@Autowired 通过类型进行注入,如果需要通过名称取值,通过 @Qualifier 注解完成名称的映射

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class GlobalConfig {
    @Value("8080")
    private String port;
    @Value("/")
    private String path;
    @Autowired
    @Qualifier("config")
    private DataConfig dataConfig;
}

IoC 解决了什么问题?

IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?

  1. 对象之间的耦合度或者说依赖程度降低;
  2. 资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。

知乎参考帖

参考资料:

  1. 本文中加入的知乎链接
  2. B站楠哥学Java – 《两小时弄清楚Spring IOC 和 AOP》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RockyBlog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值