- 在应用开发中用的非常多, @Component注解是一个通用注解,可以用在于任何类上。
- 包括普通java类,业务逻辑组件,持久化对象等等。
- 通过@Component注解spring自动创建该类的实例注入SpringIOC容器中。
- @Bean是用于配置类中声明一个Bean的,它通常是用于配置类的方法上面,表示把这个
- 方法的返回对象注册到Spring IOC容器中。 通过@Bean自定义Bean的创建和初始化过程,
- 包括指定Bean的名称、作用域、依赖关系等。
-
- 1.用途不同
- @Component用于标识普通的类
- @Bean是在配置类中声明和配置Bean对象
-
- 2.使用方式不同
- @Component是一个类级别的注解,Spring通过@ComponetScan注解扫描修饰并@Component
- 注解的一个类,并且把这些类注册到spring IOC容器里面。
- @Bean注解修饰在方法层面,它是在配置类中去手动声明一个Bean的定义
-
- 3.控制权不同
- @Component注解修饰的类是由Spring框架来创建和初始化
- @Bean注解允许开发人员手动控制Bean的创建和配置的过程,在配置上更加灵活
- 问题分析:
- spring boot默认使用CGLIB作为代理而不是使用JDK动态代理,这个选择实际上涉及到
- 底层字节码操作、反射和继承等多方面的一些问题。主要考查java代理模型、字节码操作
- 以及Spring AOP的了解。需要深入了解CGLIB和动态JDK动态代理的不同,以及为什么在
- CGLIB在某些场景下会是更优的选择。
- 问题解答:
- 1.不依赖接口:CGLIB通过生成子类来实现,代理对象无论是赋值给接口还是实现类这两者
- 都是代理对象的父类。
- 2.性能优化:CGLIB使用底层字节码技术创建动态代理对象,在性能上通常是比JDK动态代
- 理好。
- 3.粒度的控制:CGLIB提供更多的选项来控制代理的行为,这在复杂的代理场景下非常的有
- 用。
-
- 总的来说,Spring Boot的默认使用CGLIB的主要原因是因为它的灵活性和性能优势,但是
- 具体项目中选型还是通过具体项目来定。
- 问题解析:
- 在Spring boot中starter启动依赖是一个非常重要的特性,提供了第三方组件
- bean的自动装配机制,依赖包版本的统一管理,模块化方式实现jar包统一管理。
- 很好的帮助开发人员减少了配置项的管理。
- 在springboot中创建一个自定义的starter组件,可以把一些通用的代码逻辑和
- 自动配置,形成一个复用的模块。 在其他项目中,可以直接使用这个starter组件
- 极大地提高代码的复用性和开发效率。
- 考查:是否理解springboot starter的原理和作用;
- 是否有实际的编写自定义starter的经验;
-



并将自动配置类放到的这个文件中;


- Spring的核心是DispatcherServlet,它是整个流程控制的核心。负责把用户的请求分发到
- 不同的处理器进行处理。
- Spring MVC的执行流程大致可以分为几个步骤:
- 一、用户发送请求到前端控制器,DispatcherServlet;
- 二、DispatcherServlet收到请求以后利用HandMapping来查询一个或者多个HandlerExecutionChain;
- 三、DispatcherServlet把请求发送到HandleAdapter处理器适配器,这个处理器适配器会按照
- 特定的规则去执行Handler处理器;
- 四、Handler执行完成以后,会返回一个ModelAndView对象
- 五、HandlerAdapter把Handler执行的结果ModelAndView返回给DispatcherServlet;
- 六、DispatcherServlet把ModelAndView传给ViewReslover(视图解析器进行解析)
- 最后DispatcherServlet把返回值返回给请求者
-
- 实际项目中会根据实际要求写Controller、Model和View。

- 从技术选型考虑,从四个方面回答:
- Spring框架的核心特性
- 在实际项目中如何使用Spring
- 如何利用Spring的特性来解决问题
- 在使用过程中遇到哪些问题如何解决的
-
- 问题回答:
- Spring是一个轻量级的应用框架,提供了IOC和AOP两个核心功能;核心目的是为了简化
- 企业级应用程序的开发,使开发者只需要关系业务需求,不需要关心Bean的管理;以及通过
- 切面增强功能减少代码的侵入性;
- 从Spring本身的特性来看,选择Spring框架的原因:
- 1.轻量级:Spring是一个轻量级框架,它的基本版本大约2m;
- 2.IOC和DI:Spring通过IOC容器来实现Bean的生命周期的管理,以及通过DI来实现
- 依赖注入,从而实现了对象依赖的松耦合管理;
- 3.面向切面编程(AOP):Spring支持面向切面编程从而把应用业务逻辑和系统服务分开;
- 4.MVC框架:Spring MVC提供了功能更加强大且更加灵活的Web框架支持;
- 5.事务管理:Spring通过AOP实现了事务的统一管理,对应用开发中的事务处理提供了
- 非常灵活的支持;
-
- Spring从第一个版本发布到现在,它的整个生态已经是非常庞大了,在业务开发领域Spring
- 生态几乎提供了非常完善的支持。更重要的是社区的活跃度和技术成熟度都非常高

- 从四个方面回答:
- 1.软件设计的范式:减少软件开发人员对配置项的维护,从而让开发人员更加聚集在
- 业务逻辑上;
- 2.Spring Boot约定配置这一理念下的产物,类似于Spring框架下的一个脚手架,
- 通过Spring Boot快速开发基于Spring生态下的应用程序;
- 3.基于传统Spring框架开发Web应用,需要做很多和业务开发无关的并且只做一次的
- 配置;
- 比如:管理jar包的依赖;
- web.xml维护
- Dispatch-Servlet.xml配置项维护
- 应用部署到Web容器
- 第三方组件集成到Spring IOC容器中的配置项维护
- 在Spring Boot中不需要再去组偶这些繁琐的配置,Spring Boot已经自动帮助
- 我们完成这样一些动作,这就是约定优于配置思想的体现。
- 4.约定优于配置的体现有很多
- 比如:Spring Boot starter启动依赖项,它能帮助我们管理所有jar包的版本;
- Spring Boot会自动内置Tomcat容器来运行web应用;
- Spring Boot自动装配机制的实现中,通过扫描约定路径下的spring.facotries文件来识别配置类,实现bean的自动装配。
- 默认加载的配置文件application.properties等等;
-
- 总的来说,是一种比较常见的软件设计思想,核心本质是为了更高效、更便捷的实现
- 软件系统的开发和维护;
- 问题出现原因:Spring中Bean是单例的,所以在多线程并发访问有可能出现安全性的问题。
- 考查的是: 1. Sping Bean作用域 2.依赖注入和管理 3.线程安全设计和实现
- 4.并发安全机制的理解(并发编程的领域和Spring框架应用方面的知识水平)
- 问题回答:
- 1. 可以设置Bean的作用域设置为原型,这样每次从容器中获取该Bean时,都会创建
- 一个新的实例,避免多线程共享同一个对象实例的问题。
- 2. 在不改变Bean的作用域的情况下,可以避免在bean中存在可变状态声明。
- 我们可以尽量将状态信息存储到方法内部的局部变量中,或者使用线程安全的数据
- 结构比如ConcurrentHashMap来管理状态。
- 3.使用java并发编程中提供的同步锁机制来保证并发安全性。
- 比如用synchronized关键字或者ReentrantLock来控制对共享状态的访问,从而
- 确保在用一个线程可以去修改状态。
- Spring加载Bean有哪些方式(将Bean装载到IOC容器中)
- 考查:
- 1.常见的Spring加载Bean的方式;
- 2.能解释每种方式的适用场景和特点;
- 问题解答:
- 1. 使用@Component以及衍生注解比如@Service、@Reponsitory、@Controller
- 标记为一个Bean。Java类标记为Bean,Spring会自动扫描并加载这些标记的类。
- 2.通过XML配置文件中的
元素定义Bean,然后Spring容器读取并解析配置文件, - 完成Bean的装载。
- 3.通过配置类的方式,在java类增加@Configration注解,在指定方法上增加@Bean
- 注解实现。
- 4.Spring还提供了两个扩展接口ImportSelector和BeanDefinitionRegister可
- 以更灵活地控制Bean的加载和注册过程。这两个接口可以更加灵活的控制Bean的加载和注册
- 过程。
- 问题:多个声明了事务的方式相互调用的时候存在事务嵌套的问题,那么事务行为
- 应该如何进行传递。
- 比如methodA()调用methodB(),两个方法都显示开启的事务。那么methodB()
- 是开启还是继续在methodA()这个事务中去执行就取决于事务的传播行为。Spring
- 为了解决这个问题定义了七种事务传播行为。
-
- PROPAGATION_REQUIRED: (默认)支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- PROPAGATION_SUPPORTS: 支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY: 支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW: 新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
- 首先在Spring里面并没有提供事务,它只是提供对数据库事务的一个管理的封装。我们
- 可以通过声明式事务的配置使的可以一些复杂的事务处理里面去脱离出来,不需要关心连接
- 的获取、连接的关闭、事务的提交、事务的回滚这样一些操作。我们可以更加聚集在业务的
- 开发层面。所以Spring里面的事务本质上是数据库层面的一个事务,而这种事务管理主要
- 针对单个数据库里面的多个数据表的操作。它去满足一个事物的ACID特性而分布式事务是解
- 决多个数据库。事务操作的一个数据库一致性的问题,传统的关系数据库不支持跨库的事务
- 操作,所以需要引入分布式事务的解决方案。
- 而Spring里面并没有提供分布式事务的场景支持,所以Spring里面的事务和分布式
- 事务在使用上并没有直接的关联关系。但是我们使用一些主流的分布式事务解决框架问题
- 比如说像Seata集成到Spring生态里面去解决分布式事务的一个问题。
-

- Spring Cloud是官方推出来的一套微服务的解决方案,准确来说Spring Cloud
- 其实是对微服务架构里面出现的各种技术场景定义的一套规范。 Spring集成了Netflix
- 公司里面的OSS开源套件。
- 比如说 Zuul去实现应用网关
- Eureka实现服务注册与发现
- Ribbon实现负载均衡
- Hystrix实现服务熔断
- 我们可以去使用Spring Cloud Netflix这样一套组件,去快速落地微服务架构以及去
- 解决微服务治理的一系列的一些问题。但是随着Netfilx OSS相关的一些技术组件的闭
- 源和停止维护,所以Spring官方也自研了一些组件。
- 比如说像Getway来实现网关
- LoadBalancer实现负载均衡
- 另外 Alibaba里面的开源组件也实现了Spring Cloud这样一套标准,也实现了Spring
- Cloud这样一套标准。成为了Spring Cloud里面的另外一套微服务解决方案。
- 包括:
- 1.Dubbo来实现rpc通信
- 2.Nacos实现服务注册与发现
- 3.Nacos实现服务注册与发现
- 4.Sentinel实现服务限流和降级
- Spring Cloud生态的出现有两个很重要的意义:
- 1.在Spring Cloud出现之前,为了解决微服务架构里面的各种技术问题,需要去集成
- 各种技术问题,需要去集成各种开源架构,需要去集成各种开源架构,因为标准和兼容性问题,
- 所以在实践的时候很麻烦,而Spring Cloud统一了标准
- 2.降低了微服务架构的开发难度,只需要在Spring Boot的项目基础上通过starter
- 启动依赖集成相关组件就能轻松解决各种服务治理的问题。
-
-
- 首先在同一个XML配置文件里面不能存在id相同的两个bean,否则Spring容器在启动时会
- 报错。因为id这个属性表示Bean里面的唯一标志符号,所以Spring在启动的时候会去验证
- id的一个唯一性,一旦发现就会报错。而这个错误发生在Spring对XML文件进行解析转化为
- BeanDefintion的一个阶段。
- 但是在两个不同的Spring配置文件里面可以存在id相同的两个bean,IOC容器在加载
- Bean的时候默认会把多个相同id的bean进行覆盖。
- 在Spring3.x版本以后这个问题发生了变化,提供了一个@Configration这样一个注解
- 去声明一个配置类,然后是使用@Bean这个注解去实现Bean的声明。这种方式完全取代了XML
- 的一个配置形式。在这种情况下如果同一个配置类里面去声明多个相同名字的Bean。那么Spring
- IOC容器在解析的时候,只会注册第一个声明Bean的一个实例,后面重复名字的Bean的实例就
- 不会再注册。如果使用@Autowired这个注解去根据类型进行实例注入的时候,因为IOC容器
- 只存在UserServiceO1这个实例,所以在启动时候回提示找不到UserServiceO2这样的实例。
- 如果我们使用@Resource这个注解去根据名字来实现依赖注入,而在Spring IOC容器里面根据
- 名字只是得到UserService01这个实例对象于是Spring把UserServiceO1这样一个实例赋值
- 给UserService02的时候会提示一个类型不匹配的一个错误。那么这个错误是在Spring IOC
- 容器里面的Bean初始化之后依赖注入阶段发生的。
-
- 注意:下面代码在Spring IOC容器只会报存UserServiceO1中这样一个实例,后续相同名字
- 的实例不会再加载。




- 1.IOC(Inversion Of Control 控制反转)是什么?
- 核心思想是把对象的管理权限交给了容器。 应用程序如果需要使用某个对象的实例那么
- 直接从IOC容器里面去获取就可以了。那么这种设计的好处在于降低了程序里面对象与对
- 象之间的耦合性,使得程序整个体系结构变得更加灵活。
-
-
- 2.Bean的声明方式?
- spring里面提供了很多方式去声明一个Bean,(图2)比如说在XML配置文件里面通过
的标签或者通过@Service注解或者通过@Configration配置类里面通过@Bean - 注解去声明等等。那么Spring在启动的时候会去解析这些Bean然后保存到IOC容器里面。
-
- 3.IOC的工作流程
- 大致可以分为两个阶段:
- 第一个阶段是IOC容器的初始化阶段,这个阶段主要是根据程序里面定义XML或者注解
- 等Bean的声明方式。(图3)通过解析和加载后生成BeanDefinition,然后把BeanDefinition
- 注册到IOC容器里面。通过注解或者xml声明的bean都会解析到一个BeanDefinition实体。
- 这个实体里面会包含一些bean的定义和基本的一些属性。最后把这个BeanDefinition保存
- 到一个Map集合里面,从而去完成IOC的一个初始化。
- IOC容器的作用就是对这些注册的Bean的定义信息进行处理和维护。它是IOC容器控制反转
- 的一个核心。
- 第二个阶段是完成Bean的初始化和依赖注入进入第二阶段会做两个事情,第一个是通过反射
- 去针对没有lazy-init属性的单例bean进行初始化。第二个是完成Bean的依赖注入。最后一个
- 阶段就是Bean的一个使用。(图5)通常我们会通过@Autowired注解或者通过BeanFactory.getBean()从IOC容器里面去获取一个指定bean的一个实例。另外针对设置了
- layy-init属性以及非单例bean的一个实例化。是在每一次获取bean对象的时候调用bean的
- 初始化方法来完成实例化的并且Spring IOC容器不会去管理这些Bean。




