补充篇
补充
之前的Spring内容比较零散,也有些太简化这里做一些补充
如果让你设计一个Springloc,你觉得会从哪些方面考虑这个设计?
- Bean的生命周期管理:需要设计Bean的创建、初始化、销毁等生命周期管理机制,可以考虑使用工厂模式和单例模式来实现。
- 依赖注入:需要实现依赖注入的功能,包括属性注入、构造函数注入、方法注入等,可以考虑使用反射机制和XML配置文件来实现。
- Bean的作用域:需要支持多种Bean作用域,比如单例、原型、会话、请求等,可以考虑使用Map来存诸不同作用域的Bean实例。
- AOP功能的支持:需要支持AOP功能,可以考虑使用动态代理机制和切面编程来实现。
- 异常处理:需要考虑异常处理机制,包括Bean创建异常、依赖注入异常等,可以考虑使用try-catch机制来处理异常
- 需要支持从不同的配置文件中加载Bean的相关信息,可以考虑使用XML、注解或者Java配置文件加载:配置类来实现。
SpringAOP主要想解决什么问题
它的目的是对于面向对象思维的一种补充,而不是像引入命令式、函数式编程思维让他顺应另一种开发场景。AOP更像是一种对于不支持多继承的弥补,除开对象的主要特征被抽象为了一条继承链路,对于一些“弱共性”,AOP可以统一对他们进行抽象和集中处理。
举一个简单的例子,需要打印日志可能是许多对象的一个共性,但是日志的打印并不反应这个对象的主要共性。而日志打印又是一个具体的内容,它并不抽象,所以它的工作也不可以用接口来完成。而如果利用继承,打印日志的工作又横跨继承树下面的多个同级子节点强行侵入到继承树内进行归纳会干扰这些强共性的区分。
这时候,就需要AOP了。AOP首先在一个Aspect(切面)里定义了一些Advice(增强),其中包含具体实现的代码,同时整理了切入点,切入点的粒度是方法。最后,我们将这些Advice织入到对象的方法上,形成了最后执行方法时面对的完整方法。
AOP有哪些注解
- @Aspect:用于定义切面,标注在切面类上。
- @Pointcut:定义切点,标注在方法上,用于指定连接点。
- @Before:在方法执行之前执行通知。
- @After:在方法执行之后执行通知。
- @Around:在方法执行前后都执行通知。
- @AfterReturning:在方法执行后返回结果后执行通知。
- @AfterThrowing:在方法抛出异常后执行通知。
- @Advice:通用的通知类型,可以替代@Before、@After等
动态代理是什么?
Java的动态代理是一种在运行时动态创建代理对象的机制,主要用于在不修改原始类的情况下对方法调用进行拦截和增强。
Java动态代理主要分为两种类型:
- 基于接口的代理(JDK动态代理): 这种类型的代理要求目标对象必须实现至少一个接口。Java动态代理会创建一个实现了相同接口的代理类,然后在运行时动态生成该类的实例。这种代理的实现核心是
java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口。每一个动态代理类都必须实现InvocationHandler
接口,并且每个代理类的实例都关联到一个handler
。当通过代理对象调用一个方法时,这个方法的调用会被转发为由InvocationHandler
接口的invoke()
方法来进行调用 - 基于类的代理(CGLIB动态代理):CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它可以在运行时动态生成一个目标类的子类。CGLB代理不需要目标类实现接口,而是通过继承的方式创建代理类。因此,如果目标对象没有实现任何接口,可以使用CGLB来创建动态代理
动态代理和静态代理的区别
代理是一种常用的设计模式,为其他对象提供一个代理以控制对某个对象的访问,将两个类的关系解耦。代理类和委托类都要实现相同的接口,因为代理真正调用的是委托类的方法。
区别:
- 静态代理:由程序员创建或者是由特定工具创建,在代码编译时就确定了被代理的类是一个静态代理,静态代理通常只代理一个类;
- 动态代理:在代码运行期间,运用反射机制动态创建生成。动态代理代理的是一个接口下的多个实现类
spring是如何解决循环依赖的?
循环依赖指的是两个类中的属性相互依赖对方:例如 A 类中有B属性,B 类中有 A属性,从而形成了一个依赖闭环,如下图。
循环依赖问题在Spring中主要有三种情况:
- 通过构造方法进行依赖注入时产生的循环依赖问题。
- 通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题.
- 通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
只有【第三种方式】的循环依赖问题被 Spring 解决了,其他两种方式在遇到循环依赖问题时,Spring都会产生异常。
Spring 解决单例模式下的setter循环依赖问题的主要方式是通过三级缓存解决循环依赖。三级缓存指的是Spring 在创建 Bean 的过程中,通过三级缓存来缓存正在创建的 Bean,以及已经创建完成的 Bean 实例。具体步骤如下:
- 实例化 Bean:Spring 在实例化 Bean 时,会先创建一个空的 Bean 对象,并将其放入一级缓存中。
- 属性赋值:Spring 开始对 Bean 进行属性赋值,如果发现循环依赖,会将当前 Bean 对象提前暴露给后续需要依赖的 Bean(通过提前暴露的方式解决循环依赖)
- 初始化 Bean:完成属性赋值后,Spring 将 Bean 进行初始化,并将其放入二级缓存中。
- 注入依赖:Spring 继续对 Bean 进行依赖注入,如果发现循环依赖,会从二级缓存中获取已经完成初始化的 Bean 实例。
通过三级缓存的机制,Spring 能够在处理循环依赖时,确保及时暴露正在创建的 Bean 对象,并能够正确地注入已经初始化的 Bean 实例,从而解决循环依赖问题,保证应用程序的正常运行。
spring三级缓存的数据结构是什么?
都是 Map类型的缓存,比如Map {k:name; v:bean}
- 一级缓存(Singleton Objects):这是一个Map类型的缓存,存储的是已经完全初始化好的bean,即完全准备好可以使用的bean实例。键是bean的名称,值是bean的实例。这个缓存在
DefaultSingletonBeanRegistry
类中singleton0bjects
属性中。 - 二级缓存(Eary Singleton Objects):这同样是一个Map类型的缓存,存储的是早期的bean引用,即已经实例化但还未完全初始化的bean。这些bean已经被实例化,但是可能还没有进行属性注入等操作。这个缓存在
DefaultsingletonBeanRegistry
类中的earlysingleton0bjects
属性中。 - 三级缓存(Singleton Factories):这也是一个Map类型的缓存,存储的是ObjectFactory对象,这些对象可以生成早期的bean引用。
- 当一个bean正在创建过程中,如果它被其他bean依赖,那么这个正在创建的bean就会通过这个ObjectFactory来创建一个早期引用,从而解决循环依赖的问题。这个缓存在
DefaultSingletonBeanRegistry
类中singletonFactories
属性中
spring框架中都用到了哪些设计模式
- 工厂设计模式:Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
- 代理设计模式:Spring AOP 功能的实现。
- 单例设计模式:Spring 中的 Bean 默认都是单例的。
- 模板方法模式:Spring 中jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
- 包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
Spring的事务什么情况下会失效?
Spring Boot通过Spring框架的事务管理模块来支持事务操作。事务管理在Spring Boot中通常是通过@Transactional注解来实现的。事务可能会失效的一些常见情况包括:
- 未捕获异常: 如果一个事务方法中发生了未捕获的异常,并且异常未被处理或传播到事务边界之外,那么事务会失效,所有的数据库操作会回滚。
- 非受检异常: 默认情况下,Spring对非受检异常(RuntimeException或其子类)进行回滚处理,这意味着当事务方法中抛出这些异常时,事务会回滚。
- 事务传播属性设置不当: 如果在多个事务之间存在事务嵌套,且事务传播属性配置不正确,可能导致事务失效。特别是在方法内部调用有 @Transactional 注解的方法时要特别注意。
- 多数据源的事务管理: 如果在使用多数据源时,事务管理没有正确配置或者存在多个 @Transactional 注解时,可能会导致事务失效。
- 跨方法调用事务问题: 如果一个事务方法内部调用另一个方法,而这个被调用的方法没有@Transactiona 注解,这种情况下外层事务可能会失效。
- 事务在非公开方法中失效: 如果 @Transactional注解标注在私有方法上或者非 public 方法上,事务也会失效。
Spring的事务,使用this调用是否生效?
不能生效。因为Spring事务是通过代理对象来控制的,只有通过代理对象的方法调用才会应用事务管理的相关规则。当使用 this 直接调用时,是绕过了Spring的代理机制,因此不会应用事务设置。
Bean的单例和非单例,生命周期是否一样
不一样的,Spring Bean 的生命周期完全由 loC 容器控制。Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype的 Bean,Spring 在创建好交给使用者之后,则不会再管理后续的生命周期。
Spring bean的作用域有哪些?
Spring框架中的Bean作用域(Scope)定义了Bean的生命周期和可见性。不同的作用域影响着Spring容器如何管理这些Bean的实例,包括它们如何被创建、如何被销毁以及它们是否可以被多个用户共享。
Singleton(单例):在整个应用程序中只存在一个 Bean 实例。默认作用域,Spring 容器中只会创建一个 Bean 实例,并在容器的整个生命周期中共享该实例。
Prototype(原型):每次请求时都会创建一个新的 Bean 实例。次从容器中获取该 Bean 时都会创建个新实例,适用于状态非常瞬时的 Bean。
Request(请求):每个 HTTP 请求都会创建一个新的 Bean 实例。仅在 Spring Web 应用程序中有效每个 HTTP 请求都会创建一个新的 Bean 实例,适用于 Web 应用中需求局部性的 Bean。
Session(会话):Session 范围内只会创建一个 Bean 实例。该 Bean 实例在用户会话范围内共享,仅在 Spring Web 应用程序中有效,适用于与用户会话相关的 Bean。
Application:当前 ServletContext 中只存在一个 Bean 实例。仅在 Spring Web 应用程序中有效,该Bean 实例在整个 ServletContext 范围内共享,适用于应用程序范围内共享的 Bean。
WebSocket (Web套接字):在 WebSocket 范围内只存在一个 Bean 实例。仅在支持 WebSocket 的应用程序中有效,该 Bean 实例在 WebSocket 会话范围内共享,适用于 WebSocket 会话范围内共享的Bean。
Custom scopes(自定义作用域):Spring 允许开发者定义自定义的作用域,通过实现 Scope 接口来创建新的 Bean 作用域。
说一下Spring的事务传播行为
Spring框架的事务传播行为定义了当一个事务方法调用另一个事务方法时,新事务如何与已有事务进行交互的规则。Spring定义了七种事务传播行为:
- REQUIRED:默认的传播行为。如果当前没有事务,则创建一个新事务;如果当前已经存在事务,则加入该事务。这是最常用的传播行为。
- SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。适用于只读操作。
- MANDATORY:要求当前存在事务,如果没有,则抛出异常。适用于需要在事务内执行的操作。
- REQUIRES_NEW:创建一个新事务,并在新事务内执行。如果当前已经存在事务,则挂起该事务。
- NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将其挂起。
- NEVER:以非事务的方式执行操作,如果当前存在事务,则抛出异常。
- NESTED:如果当前存在事务,则创建一个嵌套事务,并在嵌套事务内执行;如果当前没有事务,则行为类似于REQUIRED。嵌套事务是外部事务的一部分,但有自己的保存点和回滚范围。
可以通过@Transactional注解或者XML配置来指定事务的传播行为。例如:
使用@Transactional注解:
@Transactional(propagation = Propagation.REQUIRED)
public void doSomething() {
// 事务方法体
}
在Spring中,在bean加载/销毁前后,如果想实现某些逻辑,可以怎么做
在Spring框架中,如果你希望在Bean加载(即实例化、属性赋值、初始化等过程完成后)或销毁前后执行某些逻辑,你可以使用Spring的生命周期回调接口或注解。这些接口和注解允许你定义在Bean生命周期的关键点执行的代码。
实现InitializingBean和DisposableBean接口
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class MyBeanClass implements InitializingBean, DisposableBean {
@0verride
public void afterPropertiesSet()throws Exception {// 初始化逻辑
}
@0verride
public void destroy()throws Exception {// 销毁逻辑
}
}
使用@PostConstruct和@PreDestroy注解
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class MyBeanClass{
@PostConstruct
public void init(){// 初始化逻辑
}
@PreDestroy
public void destroy(){
// 销毁逻辑
}
}
使用@Bean注解的initMethod和destroyMethod属性
@Configuration public class AppConfig{
@Bean(initMethod = "init", destroyedMethod = "destroy")
public MyBeanClass myBean(){
return new MyBeanClass();
}
}
Spring AOP and AspectJ AOP 有什么区别?
Spring AOP(Aspect-Oriented Programming)和AspectJ AOP都是面向切面编程的实现方式,但它们之间有一些区别:
依赖关系:
Spring AOP:Spring AOP是Spring框架的一部分,它提供了一种简单的方式来实现面向切面编程,基于代理模式实现。
AspectJ AOP:AspectJ是一个独立的AOP框架,它提供了更强大和灵活的AOP功能,包括编译时和运行时的织入。
织入方式:
Spring AOP:Spring AOP通过运行时代理(Runtime Proxy)或者编译时生成子类(CGLIB)的方式来实现织入。它只支持方法级别的切面。
AspectJ AOP:AspectJ可以通过编译时织入(Compile-Time Weaving)、类加载时织入(Load-Time Weaving)或者运行时织入(Runtime Weaving)的方式来实现切面,支持对方法、字段、构造器等更细粒度的切入点。
切面定义方式:
Spring AOP:切面通常使用Java注解或XML配置的方式进行定义。
AspectJ AOP:切面通常使用AspectJ语言(一种基于Java的专门语言)进行定义,AspectJ提供了更丰富的语法和功能来定义切面。
功能扩展:
Spring AOP:Spring AOP提供了一些便捷的切面编程功能,但相对来说功能较为有限,适用于简单的切面需求。
AspectJ AOP:AspectJ提供了更强大和灵活的功能,支持更复杂的切面编程,如引入新的方法和字段、织入到第三方库中的类等。
综上所述,Spring AOP是Spring框架提供的一种轻量级AOP实现,适用于简单的切面需求和Spring应用中的切面编程;而AspectJ AOP是一个独立的AOP框架,提供了更丰富和强大的功能,适用于复杂的切面需求和非Spring应用中的切面编程。选择哪种AOP取决于项目需求和复杂度。
SpringMVC的拦截器和过滤器有什么区别?执行顺序?
Spring MVC中的拦截器(Interceptor)和过滤器(Filter)都是用于在请求处理过程中添加额外的处理逻辑的组件,但它们有一些区别:
作用范围:
拦截器:拦截器是Spring MVC框架提供的组件,用于拦截Controller处理请求的过程,它只能拦截Spring MVC中的Controller请求。
过滤器:过滤器是Servlet规范中的一部分,它可以对所有请求进行拦截,包括静态资源的访问、JSP页面的请求等,不仅限于Spring MVC的请求。
依赖关系:
拦截器:拦截器是Spring MVC框架的一部分,依赖于Spring MVC的DispatcherServlet,通过DispatcherServlet来调用拦截器。
过滤器:过滤器是Servlet容器的一部分,独立于Spring MVC框架,由Servlet容器在请求处理链中调用。
接口和方法:
拦截器:拦截器需要实现HandlerInterceptor接口,并实现其preHandle、postHandle和afterCompletion方法。
过滤器:过滤器需要实现javax.servlet.Filter接口,并实现其doFilter方法。
对处理流程的影响:
拦截器:拦截器只对Controller的处理过程进行拦截,在Controller方法执行前后可以执行额外的逻辑,但不能修改请求或响应本身。
过滤器:过滤器可以对请求和响应进行修改,可以在请求被处理前后添加、修改或删除请求或响应的信息。
执行顺序:
拦截器:拦截器的执行顺序由配置的顺序决定,可以通过addInterceptor方法添加多个拦截器,并指定它们的执行顺序。
过滤器:过滤器的执行顺序由Servlet容器决定,通常根据过滤器在web.xml文件中的声明顺序来确定执行顺序。
综上所述,拦截器和过滤器在作用范围、依赖关系、接口和方法、对处理流程的影响以及执行顺序等方面存在一些区别。在实际开发中,可以根据具体需求选择使用拦截器还是过滤器来实现相应的功能。
Spring和SpringMVC为什么需要父子容器?【比较重点】
Spring和Spring MVC之所以需要使用父子容器的概念,是为了解决应用程序中不同组件之间的依赖关系和隔离性的问题。父子容器的设计可以提高应用程序的模块化、灵活性和可维护性,同时有效地管理组件之间的依赖关系。
具体来说,Spring和Spring MVC之间的父子容器关系主要体现在以下几个方面:
- 隔离性:父子容器之间的隔离性可以确保Spring和Spring MVC的各个模块在不同的容器中运行,彼此独立,互不干扰。例如,Spring容器负责管理应用程序中的业务逻辑和数据访问层组件,而Spring MVC容器负责管理Web层组件,两者之间的隔离性可以避免组件之间的冲突和耦合。
- 层次性:父子容器之间存在层次性的关系,子容器可以访问父容器中的Bean,但父容器不能访问子容器中的Bean。这种层次性的设计可以实现模块化的架构,便于管理和维护不同层次的组件。
- 依赖关系:Spring容器和Spring MVC容器之间存在依赖关系,Spring MVC容器依赖于Spring容器中定义的Bean。通过父子容器的关系,可以确保Spring MVC能够访问到Spring容器中定义的服务和组件,实现了业务逻辑和Web层的整合。
- 配置隔离:父子容器之间的隔离性还可以实现配置的隔离,每个容器可以拥有自己的配置文件或注解配置,减少了配置的冲突和混乱。
总的来说,Spring和Spring MVC之间的父子容器关系可以有效地实现组件的隔离和管理,提高了应用程序的模块化程度和可维护性,是Spring框架设计中重要的组成部分。
Spring事件监听的核心机制是什么?【重点】
Spring事件监听的核心机制是基于观察者设计模式(Observer Design Pattern)实现的。在Spring框架中,事件监听器(Event Listener)通过注册到事件发布者(Event Publisher)上,实现了事件的发布与订阅机制。
核心机制包括以下几个关键组件:
- 事件(Event):事件是一个抽象的概念,它代表着应用程序中某个特定的动作或状态变化。通常情况下,事件对象包含了与事件相关的信息,比如事件类型、发生时间等。
- 事件发布者(Event Publisher):事件发布者负责发布事件,即将事件对象发送给注册的事件监听器。在Spring框架中,ApplicationContext充当了事件发布者的角色,它负责管理事件监听器,并在适当的时机发布事件。
- 事件监听器(Event Listener):事件监听器是用于处理特定类型事件的组件,它实现了特定的监听器接口,并提供了处理事件的方法。当事件发布者发布事件时,注册到发布者上的监听器会接收到事件,并执行相应的处理逻辑。
- 事件监听器注册(Event Listener Registration):事件监听器需要注册到事件发布者上,以便能够接收到发布者发布的事件。在Spring框架中,可以通过配置或编程方式将事件监听器注册到ApplicationContext中。
- 事件传播(Event Propagation):事件传播是指事件在发布者和监听器之间的传递过程。在Spring框架中,事件发布者通常会遍历所有注册的事件监听器,并依次调用它们的事件处理方法来处理事件。
通过以上机制,Spring框架实现了事件的发布与订阅模式,使得应用程序中的各个组件可以解耦,提高了代码的可维护性和扩展性。开发人员可以通过定义自定义事件和监听器,实现特定功能的事件驱动型编程。
介绍下SpringAop的底层实现
Spring AOP的底层实现主要基于动态代理和字节码增强两种方式:
- JDK动态代理:
- 当目标对象实现了接口时,Spring AOP会使用JDK动态代理来生成代理对象。
- 在运行时,Spring会动态地创建一个实现了目标接口的代理类,并将切面逻辑织入到代理类的方法中。
- 代理类的方法中会首先调用拦截器链(Advice Chain)中的前置通知(Before advice),然后调用目标方法,最后调用拦截器链中的后置通知(After advice)等。
- CGLIB动态代理:
- 当目标对象没有实现接口时,Spring AOP会使用CGLIB动态代理来生成代理对象。
- 在运行时,Spring会动态地创建一个目标对象的子类(代理类),并将切面逻辑织入到子类的方法中。
- 子类的方法中会首先调用拦截器链中的前置通知,然后调用目标方法,最后调用拦截器链中的后置通知等。
- 字节码增强:
- Spring AOP也可以通过字节码增强的方式来实现切面功能。
- 在目标对象加载到内存中时,通过字节码增强工具(如ASM、Javassist等)修改目标类的字节码,将切面逻辑直接织入到目标类的方法中。
- 这种方式比动态代理更加灵活,但也更加复杂,通常用于性能要求较高的场景。
总体来说,Spring AOP的底层实现主要基于动态代理和字节码增强两种方式。通过在运行时动态生成代理对象或修改字节码来实现切面逻辑的织入,从而实现了面向切面编程的功能。
解释Spring中bean的生命周期
• 实例化Bean,new
• 根据属性,注入需要的 Bean
• 如果 Bean 实现了 BeanNameAware 等 aware 接口,则执行 aware 注入
• 如果有 BeanPostProcessor:before后置处理器,则调用preProcessBeforeInitialization() 方法。
• 如果 Bean 是 InitializingBean,则执行 afterPropertiesSet 方法
• 如果有 initMethod 方法,则执行
• 如果有 BeanPostProcessor:after后置处理器,则调用postProcessAfterInitialization() 方法
• 使用 Bean(最终暴露到一级缓存中,代理对象给其他对象调用)
• 如果 Bean 是 DisposableBean,则执行 destroy 方法
• 如果有 destroyMethod 方法,则执行
Spring-Ioc容器的加载过程
Spring IoC容器的加载过程通常包括以下几个主要步骤:
- 资源定位:Spring IoC容器首先会根据配置文件的位置,通过类路径、文件系统路径或者URL等方式来定位配置文件。Spring支持多种配置文件格式,包括XML、注解、Java配置类等。
- 资源加载:一旦定位到配置文件,Spring会加载配置文件,并根据配置文件中的定义来解析Bean的定义信息。在XML配置文件中,通常使用
<bean>
元素来定义Bean;在注解配置中,使用注解来标识Bean。 - Bean定义解析:Spring IoC容器会解析配置文件中的Bean定义信息,包括Bean的类型、作用域、依赖关系等。根据配置文件中的信息,Spring会创建对应的BeanDefinition对象,并将其注册到IoC容器中。
- Bean实例化:在解析完Bean的定义信息后,Spring IoC容器会根据Bean的定义信息,实例化对应的Bean对象。这个过程包括Bean的构造函数调用、属性赋值等。
- 依赖注入:在Bean实例化之后,Spring IoC容器会根据配置文件中的依赖关系,将依赖的对象注入到Bean中。依赖注入可以通过构造函数注入、Setter方法注入或字段注入等方式实现。
- 初始化方法调用:一旦Bean的依赖注入完成,Spring IoC容器会调用Bean的初始化方法(如果有)。初始化方法可以通过配置文件中的init-method属性、@PostConstruct注解等方式指定。
- Bean注册:在Bean实例化和初始化完成后,Spring IoC容器会将Bean注册到容器中,以便后续的依赖查找和注入。
- 应用启动完成:一旦所有的Bean都被实例化、初始化并注册到容器中,Spring IoC容器启动过程就完成了,应用程序就可以开始正常运行。
总的来说,Spring IoC容器的加载过程包括资源定位、资源加载、Bean定义解析、Bean实例化、依赖注入、初始化方法调用、Bean注册等多个步骤。通过这些步骤,Spring IoC容器能够完成对Bean的管理和控制,实现了IoC(控制反转)和DI(依赖注入)的功能。