Spring知识点总结

一、 一个 Spring Bean 定义 包含什么?

1. Bean的名称:每个Bean都有一个唯一的名称,用于在应用程序中引用该Bean。

2. Bean的类型:指定Bean的类或接口。

3. Bean的作用域:定义Bean的生命周期和可见性范围,如单例、原型等。

4. Bean的依赖关系:指定Bean与其他Bean之间的依赖关系,可以通过构造函数注入、属性注入等方式。

5. Bean的初始化方法:在Bean实例化之后,可以执行一些初始化操作的方法。

6. Bean的销毁方法:在Bean被销毁之前,可以执行一些清理操作的方法。

7. Bean的配置属性:设置Bean的各种属性值,可以通过XML配置文件、注解等方式进行配置。

以上是一个Spring Bean定义中常见的内容,根据具体需求和配置方式,可能会有一些其他的属性和元数据。

二、 如何给 Spring 容器提供配置元数据?
有多种方式可以给Spring容器提供配置元数据,以下是几种常用的方式:

1. XML配置文件:可以使用XML格式的配置文件来定义和配置Spring Bean。在XML文件中,可以使用元素定义Bean的名称、类型、作用域、依赖关系等信息。

2. Java配置类:可以使用Java类来定义和配置Spring Bean。通过在Java类上添加@Configuration注解,并在方法上添加@Bean注解,可以将方法返回的对象注册为Spring Bean。

3. 注解:可以使用注解来标记和配置Spring Bean。通过在Bean类上添加@Component或相关的注解,可以将该类作为Spring Bean进行注册。还可以使用@Autowired等注解来进行依赖注入。

4. Groovy脚本:可以使用Groovy编写脚本来定义和配置Spring Bean。通过编写Groovy脚本,可以使用Groovy语法来定义Bean的属性、依赖关系等信息。

5. 属性文件:可以使用属性文件来提供配置信息,如数据库连接信息、日志级别等。可以通过@PropertySource注解将属性文件加载到Spring容器中。

无论是使用哪种方式,最终目的是将配置元数据提供给Spring容器,让容器能够根据配置来创建和管理Bean对象。根据具体需求和项目情况,选择适合的方式进行配置元数据。

三、 解释 Spring 框架中 bean 的生命周期

在Spring框架中,Bean的生命周期可以分为以下几个阶段:

1. 实例化:当Spring容器加载配置文件或者扫描注解时,会根据配置信息或注解来实例化Bean对象。这个阶段会调用Bean的构造函数来创建对象。

2. 属性赋值:在实例化后,Spring容器会根据配置文件或者注解来为Bean的属性赋值。这个阶段可以通过构造函数注入、属性注入或者方法注入等方式来完成。

3. 初始化:在属性赋值完成后,Spring容器会调用Bean的初始化方法(如果有定义的话)。可以通过在Bean中定义一个带有@PostConstruct注解的方法来标识初始化方法。

4. 使用:在初始化完成后,Bean就可以被应用程序使用了。此时,Bean可以响应应用程序的请求,处理业务逻辑等。

5. 销毁:当应用程序关闭或者Spring容器销毁时,会触发Bean的销毁阶段。此时,Spring容器会调用Bean的销毁方法(如果有定义的话),执行一些清理操作。可以通过在Bean中定义一个带有@PreDestroy注解的方法来标识销毁方法。

需要注意的是,Bean的生命周期是由Spring容器负责管理的。Spring容器会根据配置和需求来创建、初始化、使用和销毁Bean对象。开发人员可以通过实现一些特定的接口或者使用特定的注解来自定义Bean的初始化和销毁方法。

四、 bean 生命周期方法是什么?
在Spring框架中,Bean的生命周期方法有以下几种:

1. 构造方法:在Bean实例化时,会调用Bean的构造方法来创建对象。

2. 初始化方法:在Bean的属性赋值完成后,会调用Bean的初始化方法。可以通过在Bean类中定义一个带有@PostConstruct注解的方法来标识初始化方法。

3. 销毁方法:在应用程序关闭或者Spring容器销毁时,会调用Bean的销毁方法。可以通过在Bean类中定义一个带有@PreDestroy注解的方法来标识销毁方法。

需要注意的是,初始化方法和销毁方法可以有多种方式来定义:

- XML配置方式:在XML配置文件中,可以使用元素的init-method和destroy-method属性来指定初始化方法和销毁方法的名称。

- Java配置方式:通过在Java配置类中使用@Bean注解,可以使用initMethod和destroyMethod属性来指定初始化方法和销毁方法的名称。

- 注解方式:在Bean类中使用@PostConstruct注解标识初始化方法,使用@PreDestroy注解标识销毁方法。

无论是使用哪种方式,Bean的生命周期方法都是由Spring容器负责调用的。开发人员可以在这些方法中编写自定义的初始化和销毁逻辑,以满足特定的业务需求。
五、Bean 工厂和  Application contexts 有什么区别?
Bean工厂和Application Contexts是Spring框架中的两个核心概念,它们有以下区别:

1. 功能不同:Bean工厂是Spring IoC容器的基础,负责管理和提供Bean的实例化、依赖注入和生命周期管理等核心功能。而Application Contexts是对Bean工厂的扩展,提供了更多的企业级特性,如国际化、事件传播、资源管理等。

2. 配置方式不同:Bean工厂通常使用编程式的方式进行配置,即通过编写Java代码或XML配置文件来创建和配置Bean工厂。而Application Contexts则更加注重于声明式的配置,可以通过XML配置文件、Java注解或Java配置类来定义和配置Bean。

3. 功能扩展不同:Application Contexts相比于Bean工厂提供了更多的功能扩展,如AOP、事务管理、消息传递等。它还可以与其他框架进行集成,如Spring MVC、Spring Security等。

4. 生命周期管理不同:Bean工厂在加载配置文件或注解后,会立即实例化所有的Bean,并在需要时进行依赖注入。而Application Contexts则更加灵活,可以延迟加载Bean,根据实际需求进行按需实例化和依赖注入。

总的来说,Bean工厂是Spring IoC容器的基础,提供了核心的Bean管理功能;而Application Contexts是对Bean工厂的扩展,提供了更多的企业级特性和功能扩展。在实际开发中,可以根据需求选择使用Bean工厂还是Application Contexts来管理和配置Spring Bean。

六、Spring框架中用到的设计模式?
Spring框架在实现各种功能时使用了多种设计模式,以下是一些常见的设计模式在Spring中的应用:

1. 单例模式(Singleton Pattern):Spring容器默认使用单例模式管理Bean对象,确保在容器中只有一个实例。可以通过在配置文件中设置作用域为"singleton"或使用注解@Scope("singleton")来实现。

2. 工厂模式(Factory Pattern):Spring使用工厂模式来创建和管理Bean对象。通过配置文件或注解,Spring容器根据配置信息来创建和初始化Bean对象。

3. 代理模式(Proxy Pattern):Spring的AOP(面向切面编程)功能使用了代理模式。通过动态代理技术,Spring在运行时生成代理对象,实现对目标对象的增强。

4. 观察者模式(Observer Pattern):Spring的事件机制使用了观察者模式。通过定义事件和监听器,实现对象之间的解耦和事件的发布与订阅。

5. 模板模式(Template Pattern):Spring的JdbcTemplate和HibernateTemplate等模板类使用了模板模式。这些模板类提供了通用的操作方法,封装了复杂的底层操作,简化了开发过程。

6. 适配器模式(Adapter Pattern):Spring的适配器模式用于将现有的类或接口适配成符合Spring要求的类或接口。比如,Spring的HandlerAdapter用于将不同类型的处理器适配成统一的处理器接口。

7. 策略模式(Strategy Pattern):Spring的策略模式用于在运行时选择不同的算法或实现。通过配置不同的策略,Spring可以在不修改代码的情况下切换不同的实现。

8. 依赖注入模式(Dependency Injection Pattern):Spring的核心特性是依赖注入(DI),它使用了依赖注入模式。通过在配置文件或注解中声明依赖关系,Spring容器负责将依赖对象注入到目标对象中。

这些设计模式在Spring框架中的应用,使得开发者能够更加灵活、高效地开发和管理应用程序。
七、Spring框架中的单例bean是线程安全的吗?
在Spring框架中,默认情况下,单例Bean是线程安全的。Spring容器在创建单例Bean时,会保证在整个应用程序中只有一个实例存在,并且该实例会被多个线程共享。

Spring通过以下方式来确保单例Bean的线程安全性:

1. 实例化阶段:Spring容器在创建单例Bean时,会在单个线程中进行实例化和初始化操作。这保证了在多线程环境下只有一个实例被创建。

2. 依赖注入阶段:Spring容器在实例化单例Bean后,会将其依赖的其他Bean通过依赖注入的方式注入到单例Bean中。Spring会确保依赖的Bean先于被依赖的Bean进行初始化,避免了多线程环境下的竞争条件。

然而,需要注意的是,单例Bean的线程安全性并不意味着其中的方法或操作都是线程安全的。如果在单例Bean中存在共享的可变状态,那么需要开发者自己确保在多线程环境下正确地处理同步和竞争条件。

如果在单例Bean中需要使用到可变状态或进行并发操作,可以考虑使用同步机制(如synchronized关键字)或使用线程安全的数据结构来保证线程安全性。

总结起来,Spring框架中的单例Bean是线程安全的,但如果单例Bean中存在可变状态,需要开发者自己确保线程安全性。

八、 Spring的事务传播行为? 
Spring框架中的事务传播行为定义了在多个事务方法相互调用时,事务应该如何传播和管理。Spring提供了多种事务传播行为,可以通过@Transactional注解或编程方式进行配置。

以下是Spring框架中常见的事务传播行为:

1. REQUIRED(默认):如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新事务。该传播行为是最常用的,适用于大多数情况。

2. REQUIRES_NEW:无论当前是否存在事务,都创建一个新事务。如果当前存在事务,则将当前事务挂起,执行新事务,新事务完成后,再恢复执行原来的事务。

3. SUPPORTS:如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式执行。即,当前存在事务则使用事务,当前不存在事务则不使用事务。

4. NOT_SUPPORTED:以非事务的方式执行,如果当前存在事务,则将当前事务挂起,执行非事务操作,非事务操作完成后,再恢复执行原来的事务。

5. MANDATORY:要求当前必须存在事务,如果当前不存在事务,则抛出异常。

6. NEVER:要求当前必须不存在事务,如果当前存在事务,则抛出异常。

7. NESTED:如果当前存在事务,则在当前事务内嵌套一个子事务执行。嵌套事务是独立于父事务的,有自己的提交和回滚操作。如果子事务发生异常,只会回滚子事务,而不会影响父事务。如果父事务发生异常,则父事务和子事务都会回滚。

通过事务传播行为的配置,可以灵活地管理多个事务方法之间的事务行为,确保数据的一致性和完整性。在选择事务传播行为时,需要根据具体的业务需求和事务操作的逻辑来确定。

九、spring 的事务隔离级别?什么是脏读,不可重复读?幻读?
Spring框架支持以下五个标准的事务隔离级别:

1. DEFAULT:使用底层数据库的默认隔离级别。

2. READ_UNCOMMITTED(读未提交):事务可以读取其他事务未提交的数据,可能出现脏读、不可重复读和幻读问题。

3. READ_COMMITTED(读已提交):事务只能读取其他事务已提交的数据,避免脏读问题。但仍可能出现不可重复读和幻读问题。

4. REPEATABLE_READ(可重复读):事务在执行期间多次读取相同的数据时,数据保持一致。避免了脏读和不可重复读问题,但仍可能出现幻读问题。

5. SERIALIZABLE(串行化):事务串行执行,避免了脏读、不可重复读和幻读问题,但性能较差。

脏读(Dirty Read)是指一个事务读取了另一个未提交的事务所写入的数据。即,一个事务读取了尚未持久化的数据,如果未提交的事务回滚,读取到的数据就是脏数据。

不可重复读(Non-repeatable Read)是指一个事务多次读取同一数据,但在读取过程中,其他事务修改了该数据,导致每次读取的结果不一致。

幻读(Phantom Read)是指一个事务多次查询同一范围的数据,但在查询过程中,其他事务新增或删除了符合查询条件的数据,导致每次查询的结果不一致。

事务隔离级别的选择需要根据具体的业务需求和对数据一致性的要求来确定。较低的隔离级别可以提高并发性能,但可能会导致脏读、不可重复读和幻读等问题。较高的隔离级别可以保证数据的一致性,但会影响并发性能。

在Spring中,可以通过@Transactional注解或编程方式设置事务的隔离级别,确保在多个事务并发执行时,数据能够保持一致性和完整性。

十、jdk动态代理 和 cglib动态代理的区别?
JDK动态代理和CGLIB动态代理都是在Java中实现动态代理的方式,但它们有一些区别。

1. 基于继承和基于接口:JDK动态代理只能代理实现了接口的类,它是基于接口的代理实现。而CGLIB动态代理可以代理没有实现接口的类,它是基于继承的代理实现。

2. 代理类生成方式:JDK动态代理通过反射机制来生成代理类,它需要目标对象实现接口,并且只能代理接口中定义的方法。CGLIB动态代理通过继承目标类来生成代理类,它可以代理目标类中的所有非final方法。

3. 性能:由于JDK动态代理是基于接口,它的代理生成过程相对较快,执行速度也比较快。而CGLIB动态代理是基于继承,它的代理生成过程相对较慢,执行速度也比较慢。所以在性能要求较高的场景下,JDK动态代理更适合。

4. 类型限制:由于JDK动态代理是基于接口的,所以它只能代理接口中定义的方法,不能代理目标类中的非接口方法。而CGLIB动态代理可以代理目标类中的所有非final方法,包括私有方法。

综上所述,JDK动态代理适用于代理接口,对性能要求较高的场景;而CGLIB动态代理适用于代理没有实现接口的类,对性能要求较低的场景。在选择使用哪种动态代理方式时,需要根据具体的需求和场景来决定。

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值