spring
spring 核心模块
Spring Core:Spring Core是Spring框架的核心模块,提供了IoC(Inversion of Control)容器的实现和支持。它负责创建、配置和管理应用程序中的对象,并通过依赖注入的方式解耦组件之间的依赖关系。
Spring AOP:Spring AOP模块实现了面向切面编程(AOP)的支持。它允许开发者通过定义切点和切面,将横切关注点(如日志记录、性能监控等)与业务逻辑分离,从而提高代码的模块化和可维护性。
Spring Web MVC:Spring Web MVC是Spring框架的Web应用程序开发模块。它提供了一种基于MVC(Model-View-Controller)的架构,用于构建灵活、可扩展的Web应用程序。开发者可以使用注解或配置文件定义控制器、视图和模型,并实现Web请求的处理和响应。
Spring WebFlux:Spring WebFlux是Spring框架的响应式Web开发模块。它基于反应式编程模型,提供了一种异步、非阻塞的方式处理Web请求。开发者可以使用注解或函数式编程风格定义处理器函数,并利用响应式流处理请求和响应。
Spring Web:Spring Web模块是Spring框架的Web应用程序支持模块,提供了与Servlet API和其他Web相关技术的集成。它包括与Web安全、文件上传、WebSockets等相关的功能和工具,帮助开发者构建全功能的Web应用程序。
Spring DAO:Spring DAO模块提供了对数据访问对象(DAO)的支持。它简化了与数据库的交互,提供了一组抽象和实现,用于执行CRUD操作、批处理、存储过程调用等。开发者可以集成各种数据访问技术(如JDBC、Hibernate、JPA等)来实现灵活和可扩展的数据访问层。
Spring ORM:Spring ORM模块用于集成和支持各种对象关系映射(ORM)框架,如Hibernate、JPA等。它提供了事务管理、异常转换和对象关系映射等功能,简化了与关系型数据库的交互。
Spring Context:Spring Context是Spring框架的核心模块之一,实现了IoC容器的功能。它负责管理和组织应用程序中的各个组件,包括Bean管理、依赖注入、生命周期管理、事件机制等。Spring Context提供了一个上下文环境,使得开发者能够更方便地构建和管理应用程序。
[八大模块](https://blog.csdn.net/weixin_51465537/article/details/131049873)
bean.
Spring中XML配置和注解之间有什么区别
XML 配置可以和注解混合使用,但是混合使用的话,XML 配置会覆盖 annotation (注解),因此并不推荐混合使用。
XML 配置的优点:
XML 配置方式进一步降低了耦合,是的应用更容易拓展,即使对配置文件进一步修改也不需要对工程进行修改和重新编译。
在处理打业务量的时候,使用 XML 配置应该更好一些,因为 XML 中更加清晰的表明了各个对象之间的关系,各个业务类之间的调用。同时 Spring 的配置也能一目了然
若用 XML 配置大量业务代码时,会使 XML 文件过大,不易查看,这一点可以通过利用业务分解书写多个 XML 配置文件解决
XML 配置的缺点:
配置文件读取和解析需要花费一定时间
配置文件过多的时候难以管理
无法对配置的正确性进行校验,增加了测试难度
注解配置的优点:
注解在 class 文件中,可以降低维护成本,annotation 的配置机制简单明显
不需要第三方解析工具,利用反射技术就可以完成任务
编辑期即可验证正确性,查错更容易
注解配置的缺点:
如果需要对 annotation 进行修改,需要重新编译整个工程
业务类之间的关系不如 XML 配置那样容易把握
如果在程序中 annotation 过多,直接影响代码质量,对于代码的简洁度有一定的影响
简述Spring中@Primary注解 ?
Spring的@Primary注解,该注解是框架在3.0版中引入的。
其作用与功能,当有多个相同类型的bean时,使用@Primary来赋予bean更高的优先级
简述@RequestMapping 注解作用 ?
@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一。这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。并且一个处理请求地址映射的注解,可用在类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
简述@Component, @Controller, @Repository, @Service 有何区别?
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException
简述什么是Spring的内部bean?什么是Spring inner beans?
在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的,它们的Scope一般是prototype。
请简述Sping 构造器依赖注入和 Setter方法注入的区别 ?
-
Setter方式要对应的bean拥有set方法,而构造器方式则要拥有对应的构造器
-
setter方式更加直观,而构造器方式更加臃肿,因为需要将全部依赖设置进来.
-
·如果一个类有一组必需的依赖项,这些依赖项在对象创建时就应该设置好,并且不会发生变化,那么构造函数注入通常是更好的选择。如果依赖项是可选的,或者需要在对象创建后才能确定,那么setter注入可能更合适。
-
构造器注入保证依赖不可变(final关键字)保证依赖不为空(省去了我们对其检查)
保证返回客户端(调用)的代码的时候是完全初始化的状态 -
在构造函数注入,如果A和B对象相互依赖:A依赖于B,B也依赖于A,此时在创建对象的A或者B时,Spring抛出ObjectCurrentlyInCreationException。所以Spring可以通过setter注入,从而解决循环依赖的问题
阐述Spring如何解决循环依赖问题 ?
循环依赖的详细解决
循环依赖问题在Spring中主要有三种情况:
(1)通过构造方法进行依赖注入时产生的循环依赖问题。
(2)通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
(3)通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
在Spring中,只有第(3)种方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。这是因为:
第一种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
第二种setter方法(多例)的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。
Spring在单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要功臣。解决的核心原理就是:在对象实例化之后,依赖注入之前,Spring提前暴露的Bean实例的引用在第三级缓存中进行存储,以便在后续的创建过程中使用,从而打破循环依赖
解释JavaBean和SpringBean和对象的区别
(1)什么是JavaBean:
JavaBean是一种JAVA语言写的可重用组件。JavaBean符合一定规范写的Java类,是一种规范。它的方法命名
1.所有属性为private
2.这个类必须具有一个公共的(public)无参构造函
3.private属性必须提供public的getter和setter来给外部访问,并且方法的命名也必须遵循一定的命名规范
4.这个类是可序列化的,要实现serializable接口
(2)么是SpringBean
SpringBean是受Spring管理的对象 所有能受Spring容器管理的对象都可以成为SpringBean.
二者之间的区别:
用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean
写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法
生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行为
简述Bean实例化中有哪些扩展?
1:InstantiationAwareBeanPostProcessor接口,该接口是BeanPostProcessor的子接口,用于在实例化之后,但在设置显示属性或自动装配之前,设置实例化之前的回调函数。通常用于抑制特定目标bean的默认实例化。例如创建具有特殊TargetSource(池化目标,延迟初始化目标等)的代理,或者实现其他注册策略,如字段注入
2:BeanPostProcessor接口,这个接口允许自定义修改新的bean实例,例如检查标记接口或用代理包装,注意,如果有相互依赖的bean,这里可能无法使用代理
3:InitializingBean接口
在执行完BeanPostProcessor的postProcessBeforeInitialization方法后,如果这个bean实现了InitializingBean接口,则会去调用afterPropertiesSet方法
4:各种Aware
在在执行完BeanPostProcessor的postProcessBeforeInitialization方法前,如果bean实现了BeanNameAware或BeanClassLoaderAware或BeanFactoryAware,则会调用接口相关的方法,入参就是这个bean关心的值
5:BeanDefinition入口扩展
在定义bean时,可以指定构造函数,设置属性,还可以设置init-method和destroy-method。构造函数不用说,设置属性是在InstantiationAwareBeanPostProcessor#PostProcessPropertyValues方法后执行的,init-method是在InitializingBean的afterPropertiesSet方法后执行的,而destroy-method是在容器关闭是被调用的
请简述BeanFactory和FactoryBean的区别
org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑
1、简单介绍\n这个其实是所有Spring Bean的容器根接口,给Spring 的容器定义一套规范,给IOC容器提供了一套完整的规范,比如我们常用到的getBean方法等
在Spring框架中,BeanFactory
和FactoryBean
是两个不同的概念,它们在Spring的Bean管理和创建过程中扮演着不同的角色。
BeanFactory
BeanFactory
是Spring框架中最基础的IoC容器接口,它定义了Spring IoC容器的基本功能和行为。BeanFactory
负责管理Spring应用中的Bean,包括Bean的创建、配置、初始化和销毁等。它提供了一种延迟加载和按需获取Bean的机制,这意味着只有当客户端请求某个Bean时,BeanFactory
才会创建并返回该Bean的实例。BeanFactory
接口的一些常用实现类包括XmlBeanFactory
、DefaultListableBeanFactory
等。
FactoryBean
FactoryBean
是一个特殊的Bean,它的主要作用是创建其他Bean的实例。与普通Bean不同,FactoryBean
本身并不是一个简单的Bean,而是一个Bean工厂,它可以根据配置信息动态地创建Bean实例。FactoryBean
接口定义了三个方法:
Object getObject()
:返回由FactoryBean
创建的Bean实例。boolean isSingleton()
:表明由FactoryBean
创建的Bean是否为单例。Class<?> getObjectType()
:返回由FactoryBean
创建的Bean的类型。
使用FactoryBean
的主要原因是为了封装复杂的Bean创建逻辑,使得客户端代码可以更简单地获取Bean实例。例如,你可以创建一个FactoryBean
来连接数据库,并返回一个JdbcTemplate
实例,这样客户端代码就不需要关心如何创建和配置JdbcTemplate
,只需通过FactoryBean
获取即可。
区别总结
- 角色不同:
BeanFactory
是Spring IoC容器的基本接口,负责管理Bean的生命周期;而FactoryBean
是一个特殊的Bean,它负责创建其他Bean的实例。 - 功能不同:
BeanFactory
提供了Bean的基本管理功能,如创建、配置、初始化和销毁;而FactoryBean
提供了一种灵活的方式来创建和配置复杂的Bean实例。 - 使用场景不同:
BeanFactory
适用于所有需要Spring IoC容器管理Bean的场景;而FactoryBean
适用于需要动态创建或配置Bean实例的场景,特别是在Bean的创建逻辑比较复杂的情况下。
在Spring框架中,BeanFactory
和FactoryBean
相互配合,共同实现了Spring IoC容器的强大功能。
简述BeanDefinition的作用
BeanDefinition它主要负责存储Bean的定义信息:决定Bean的生产方式。
BeanDefinition在Spring中是用来描述Bean对象的,其不是一个bean实例,仅仅是包含bean实例的所有信息,比如属性值、构造器参数以及其他信息。Bean对象创建是根据BeanDefinition中描述的信息来创建的,BeanDefinition存在的作用是为了可以方便的进行修改属性值和其他元信息
简述BeanFactory的作用
BeanFactory是Spring中非常核心的一个顶层接口;
它是Bean的工厂,它的主要职责就是生产Bean;
它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean;
它有非常多的实现类,每个工厂都有不同的职责(单一职责)功能,最强大的工厂是:DefaultListableBeanFactory,Spring底层就是使用的该实现工厂进行生产Bean的。
简述将类声明为Spring的bean的注解有哪些方式 ?
我们一般使用@Autowired注解去自动装配bean。而想要把一个类标识为可以用@Autowired注解自动装配的bean,可以采用以下的注解实现:
1.@Component注解。通用的注解,可标注任意类为Spring组件。如果一个Bean不知道属于哪一个层,可以使用@Component注解标注。
2.@Repository注解。对应持久层,即Dao层,主要用于数据库相关操作。
3.@Service注解。对应服务层,即Service层,主要涉及一些复杂的逻辑,需要用到Dao层(注入)。
4.@Controller注解。对应Spring MVC的控制层,即Controller层,主要用于接受用户请求并调用Service层的方法返回数据给前端页面
简述@Component和@Bean的区别 ?
1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。
2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。
3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。
Spring框架中的Bean是线程安全的么?如果线程不安全,那么如何处理
Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。
(1)对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
(2)对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类和Dao等,这些Bean大多是无状态的,只关注于方法本身。
有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。
无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
对于有状态的bean(比如Model和View),就需要自行保证线程安全,最浅显的解决办法就是将有状态的bean的作用域由“singleton”改为“prototype”。
也可以采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的副本变量。
bean作用域
详细叙述Spring容器的启动流程
1、初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
2、将配置类的BeanDefinition注册到容器中
3、调用refresh()方法刷新容器
(1)初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中:
① 实例化BeanFactory【DefaultListableBeanFactory】工厂,用于生成Bean对象
② 实例化BeanDefinitionReader注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成 BeanDefinition 对象,(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等)
③ 实例化ClassPathBeanDefinitionScanner路径扫描器,用于对指定的包目录进行扫描查找 bean 对象
(2)将配置类的BeanDefinition注册到容器中:
(3)调用refresh()方法刷新容器:
① prepareRefresh()刷新前的预处理:
② obtainFreshBeanFactory():获取在容器初始化时创建的BeanFactory:
③ prepareBeanFactory(beanFactory):BeanFactory的预处理工作,向容器中添加一些组件:
④ postProcessBeanFactory(beanFactory):子类重写该方法,可以实现在BeanFactory创建并预处理完成以后做进一步的设置
⑤ invokeBeanFactoryPostProcessors(beanFactory):在BeanFactory标准初始化之后执行BeanFactoryPostProcessor的方法,即BeanFactory的后置处理器:
⑥ registerBeanPostProcessors(beanFactory):向容器中注册Bean的后置处理器BeanPostProcessor,它的主要作用是干预Spring初始化bean的流程,从而完成代理、自动注入、循环依赖等功能
⑦ initMessageSource():初始化MessageSource组件,主要用于做国际化功能,消息绑定与消息解析:
⑧ initApplicationEventMulticaster():初始化事件派发器,在注册监听器时会用到:
⑨ onRefresh():留给子容器、子类重写这个方法,在容器刷新的时候可以自定义逻辑
⑩ registerListeners():注册监听器:将容器中所有的ApplicationListener注册到事件派发器中,并派发之前步骤产生的事件:
⑪ finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean,核心方法是preInstantiateSingletons(),会调用getBean()方法创建对象;
⑫ finishRefresh():发布BeanFactory容器刷新完成事件
bean的声明周期
Spring Bean的生命周期包含下图的流程
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。
对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。
(3)处理Aware接口:Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:
①如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字;
②如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
②如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean:如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
(6)init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(7)BeanPostProcessor后置处理:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(8)DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(9)destroy-method:最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
简述Spring ApplicationContext ?
ApplicationContext 的主要实现类是 ClassPathXmlApplicationContext 和 FileSystemApplicationContext, 前者默认从类路径加载配置文件, 后者默认从文件系统中装载配置文件.
Spring框架提供的容器有哪些?
( 1 )Spring BeanFactory容器
( 2 )Spring ApplicationContext容器
请简述BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。
(1)BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
继承MessageSource,因此支持国际化。
资源文件访问,如URL和文件(ResourceLoader)。
载入多个(有继承关系)上下文(即同时加载多个配置文件) ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
提供在监听器中注册bean的事件。
(2)
①BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
③ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
(4)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader
请说明Spring中bean的作用域
(1)singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
(2)prototype:为每一个bean请求创建一个实例。
(3)request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
请列举Spring基于xml注入bean的几种方式
set()方法注入;
构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
静态工厂注入;
实例工厂;
请简述@Autowired和@Resource@ inject之间的区别 ?
一、@Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。
二、@Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
三、@Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,
四、@Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
五、推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
三者之间的区别
@Autowired
@Qualifier("orderDaoImplForOracle")//此处是bean的名字而不是类的
private OrderDao orderDao;
简述使用@Autowired注解自动装配的过程?
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,。
在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么
1 @Autowired会根据类上的spring中的@primary
2根据@javax.annotatiopn.priority
3再根据beanname进行匹配;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false
简述Spring的自动装配 .
在Spring中,使用autowire来配置自动装载模式,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象。
(1)在Spring框架xml配置中共有5种自动装配:
no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
byType:通过参数的数据类型进行自动装配。
constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
(2)基于注解的自动装配方式:
使用@Autowired、@Resource注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
简述什么是bean的自动装配
在Spring框架中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring 容器能够自动装配相互合作的bean,这意味着容器不需要和配置,能通过Bean工厂自动处理bean之间的协作。这意味着 Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。
数据库
简述NamedParameterJdbcTemplate以及其优点
NamedParameterJdbcTemplate建立在spring提供的JDBCTemplate之上,用于与数据库的低层通信。 它使得可以将SQL查询参数作为键值对传递。 结果,程序代码比索引或“?”更具可读性,因此可以作为更好的文档。 占位符方法。 如果参数数量巨大,则后者尤其难以遵循
详细阐述Spring事务的实现方式和实现原理 ?
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 redo log 和 undo log实现的。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。
(1)Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
(2)spring的事务传播机制:
spring事务的传播机制说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。
① PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。
② PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。
③ PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。‘
④ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑤ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。
⑥ PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。
⑦ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
(3)Spring中的隔离级别:
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。
④ ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。
⑤ ISOLATION_SERIALIZABLE:所有事务逐个依次执行。
Spring 框架中事务管理有哪些优点?
Spring框架为编程式事务管理提供了一套简单的API而不是一些复杂的事务API。
Spring框架支持声明式事务管理。
Spring框架和Spring各种数据访问抽象层很好得集
其他
思考Spring 框架中都用到了哪些设计模式?
1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
(2)单例模式:Bean默认为单例模式
(3)策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
(4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
(5)模板方法:可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,用来解决代码重复的问题。比如RestTemplate, JmsTemplate, JpaTemplate
(6)适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式,Spring MVC中也是用到了适配器模式适配Controller
(7)观察者模式:Spring事件驱动模型就是观察者模式的一个经典应用。
(8)桥接模式:可以根据客户的需求能够动态切换不同的数据源。比如我们的项目需要连接多个数据库,客户在每次访问中根据需要会去访问不同的数据库
请简述Spring框架中有哪些不同类型的事件
Spring 提供了以下5种标准的事件:
(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知
简述Spring如何自定义注解
① 创建一个自定义注解:与创建接口类似,但自定义注解需要使用 @interface
② 添加元注解信息,比如 @Target、@Retention、@Document、@Inherited 等
③ 创建注解方法,但注解方法不能带有参数
④ 注解方法返回值为基本类型、String、Enums、Annotation 或其数组
⑤ 注解可以有默认值;
请问什么是Java Spring注解 ?
Java 注解就是代码中的一些特殊标记(元信息),用于在编译、类加载、运行时进行解析和使用,并执行相应的处理。它本质是继承了 Annotation 的特殊接口,其具体实现类是 JDK 动态代理生成的代理类,通过反射获取注解时,返回的也是 Java 运行时生成的动态代理对象 $Proxy1。通过代理对象调用自定义注解的方法,会最终调用 AnnotationInvocationHandler 的 invoke 方法,该方法会从 memberValues 这个Map中查询出对应的值,而 memberValues 的来源是Java常量池。
注解在实际开发中非常常见,比如 Java 原生的 @Overried、@Deprecated 等,Spring的 @Controller、@Service等,Lombok 工具类也有大量的注解,不过在原生 Java 中,还提供了元 Annotation(元注解),他主要是用来修饰注解的,比如 @Target、@Retention、@Document、@Inherited 等。
@Target:标识注解可以修饰哪些地方,比如方法、成员变量、包等,具体取值有以下几种:ElementType.TYPE/FIELD/METHOD/PARAMETER/CONSTRUCTOR/LOCAL_VARIABLE/ANNOTATION_TYPE/PACKAGE/TYPE_PARAMETER/TYPE_USE
@Retention:什么时候使用注解:SOURCE(编译阶段就丢弃) / CLASS(类加载时丢弃) / RUNTIME(始终不会丢弃),一般来说,我们自定义的注解都是 RUNTIME 级别的,因为大多数情况我们是根据运行时环境去做一些处理,一般需要配合反射来使用,因为反射是 Java 获取运行是的信息的重要手段
@Document:注解是否会包含在 javadoc 中;
@Inherited:定义该注解与子类的关系,子类是否能使用。
AOP
Spring AOP 中,关注点和横切关注的区别是什么
关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点
解释Spring有几种不同类型的自动代理
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying
面试题:如何理解 Spring 中的代理?
在Spring框架中,代理是一种常用的技术,用于实现面向切面编程(AOP)和其他功能。Spring框架提供了两种代理模式:JDK动态代理和CGLIB动态代理。
代理在Spring中的理解可以从以下几个方面来考虑:
AOP实现:Spring中的代理用于实现AOP。通过代理,可以将横切逻辑(如日志记录、事务管理等)与核心业务逻辑进行解耦,提高代码的模块化和可维护性。Spring使用代理将切面逻辑织入到目标对象的方法调用中,从而在不修改原始代码的情况下实现切面功能。
面向接口:Spring的代理通常基于接口进行操作。当目标对象实现了接口时,Spring会使用JDK动态代理来创建代理对象。代理对象实现了目标对象的接口,并将方法调用委托给切面逻辑进行处理。这种基于接口的代理可以实现松耦合和动态性,对于面向接口编程的Spring组件非常有用。
CGLIB代理:当目标对象没有实现接口时,Spring会使用CGLIB动态代理。CGLIB通过继承目标对象来创建代理对象,并重写目标对象的非final方法,实现切面逻辑的拦截和增强。CGLIB代理可以扩展目标对象的功能,对于那些无法使用接口实现代理的类也提供了AOP功能。
简述Spring的AOP理解 ?
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理,也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
解释Spring AOP里面的关键词 ?
(1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
(2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。
(3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add*、search*。annotation方式可以指定被哪些注解修饰的代码进行拦截。
(4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
(5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。
(6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。
(7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制
Spring通知(Advice)有哪些类型:
(1)前置通知(Before Advice):在连接点(Join point)之前执行的通知。
(2)后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
(3)环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
(4)返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)
(5)抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知
(1)没有异常情况下的执行顺序:
around before advice
before advice
target method 执行
after advice
around after advice
afterReturning advice
(2)出现异常情况下的执行顺序:
around before advice
before advice
target method 执行
after advice
around after advice
afterThrowing advice
java.lang.RuntimeException:异常发生
IOC DI
简述什么是Spring的依赖注入(DI)?
实例不再由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类。
简述什么是Spring IoC容器 以及其优点 ?
所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。对于IoC来说,最重要的就是容器。容器管理着Bean的生命周期,控制着Bean的依赖注入。
优点:**集中管理对象,方便维护,降低耦合度
简述Spring IoC的实现机制
Spring IOC 的实现原理主要包括以下几个方面:
类扫描和装载
在Spring IOC容器启动时,会先进行XML配置文件的解析,然后通过类扫描器扫描指定的包路径,找出所有标注为@Component、@Service、@Controller、@Repository等注解的Java类,并将它们加载到JVM中。
Bean定义解析
将扫描出来的各个Java类根据它们的注解类型,解析成相应的Bean定义对象,并将这些Bean定义对象保存在Spring IOC容器内的Bean定义注册表中。
Bean实例化
Spring IOC容器根据Bean定义注册表中的信息,通过反射机制创建一个个Bean实例,并将其保存在单例Bean缓存池中。
Bean属性注入
在Bean实例化之后,Spring IOC容器会检测Bean中是否有需要自动注入的属性,并根据属性类型进行匹配注入。属性注入可以通过构造器注入、Setter方法注入以及注解注入等方式实现。
生命周期管理
Spring IOC容器中的Bean在创建和销毁时都会触发相应的生命周期事件,Spring IOC容器要负责监听和管理这些事件。当Spring IOC容器启动时,会先执行所有注册的Bean的初始化方法;当Spring IOC容器关闭时,会执行所有注册的Bean的销毁方法。
AOP支持
Spring IOC容器还提供了AOP的支持,通过动态代理技术,在Bean调用时动态地将一些公共逻辑织入Bean的方法中,从而避免了代码的冗余。
MVCM是指模型,V是视图,C则是控制器
简述@RequestParam注解的作用 ?
@RequestParam注解是Spring MVC框架中用于绑定HTTP请求参数到方法参数的注解。它的作用是告诉Spring MVC框架要从HTTP请求中获取特定名称的参数,并将其赋值给注解所标注的方法参数。
简述@ControllerAdvice和@RestControllerAdvice区别
在具体使用上:
1)注解有@ControllerAdvice的类, 需要在具体方法上同时添加@ExceptionHandler和@ResponseBody注解;
2)注解有@RestControllerAdvice的类,只需要在具体方法上添加@ExceptionHandler注解。