• 详解Spring面试IoC和AOP


    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框架读取这个配置文件,根据配置文件的内容来创建对象

    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    基于注解:
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
    System.out.println(context.getBean("config"));
    
    • 1
    • 2
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    ApplicationContext context = new AnnotationConfigApplicationContext("com.southwi
    nd.ioc");
    System.out.println(context.getBean(DataConfig.class));
    
    • 1
    • 2
    • 3

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

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    @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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    IoC 解决了什么问题?

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

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

    知乎参考帖

    参考资料:

    1. 本文中加入的知乎链接
    2. B站楠哥学Java – 《两小时弄清楚Spring IOC 和 AOP》
  • 相关阅读:
    微服务拆分
    蓝桥杯——分巧克力
    互动直播UI设置 之 主播UI
    通义千问, 文心一言, ChatGLM, GPT-4, Llama2, DevOps 能力评测
    探画系统探画系统开发源码分享
    Kettle 简介
    在Android studio上开发APP之后,找不到应用图标,但是手机管家显示已经安装
    多体验DeFi项目,做个真正的DeFi玩家 2021-04-23
    websocket请求通过IteratorAggregate实现流式输出
    数据分析实际案例之:pandas在泰坦尼特号乘客数据中的使用
  • 原文地址:https://blog.csdn.net/weixin_44105632/article/details/128008559