spring
- bean 生命周期
- 事务
- spring 面试题
- @SpringBootApplication 注解介绍
- Bean 实例化与初始化的区别
- Spring Aop 与AspectJ的简明区别
- Spring 事务失效场景
- ApplicationContext 和 BeanFactory 区别
- springboot 中spring.factories 作用
- spring 事件简介
bean 生命周期
介绍bean 生命周期
bean 生命周期梳理
一、生命周期梳理
- 实例化前 【InstantiationAwareBeanPostProcessor】
在实例化目标bean之前应用此BeanPostProcessor。返回的bean对象可能是要使用的代理,而不是目标bean,从而有效地抑制了目标bean的默认实例化。
如果此方法返回非null对象,则bean创建过程将短路。应用的唯一进一步处理是来自配置的BeanPostProcessors的postProcessAfterInitialization回调 - 实例化
- 实例化后 【InstantiationAwareBeanPostProcessor】在bean实例化后,通过构造函数或工厂方法,但在Spring属性填充(从显式属性或自动布线)发生之前执行操作。
这是在Spring的自动布线开始之前,对给定的beainstance执行自定义字段注入的理想回调。 - 属性赋值
- 初始化前 【BeanPostProcessor】
- 初始化
- 初始化后 【BeanPostProcessor】
- 注册销毁相关的回调接口
- 使用
- 销毁
-
* 1、推断构造函数
* 2、实例化
* 3、填充属性(依赖注入)
* 4、处理 Aware 回调
* 5、初始化前(如果某个方法有@PostConstruct)
* 6、初始化 (实现 InitializingBean)
* 7、初始化后(AOP 代理)
* 8、容器销毁
二、图例说明
bean 容器启动流程
- 扫描给定路径下的class 生成所有类的bean对象定义,并放在一个map中
- 然后筛选出非懒加载的BeanDefinition对象进行创建Bean,对于多例Bean不需要在启动过程中进行创建,获取时创建
- 利用BeanDefinition创建Beanj就是Bean的生命周期,这期间包含合并BeanDefinition、推断构造函数、实例化、属性填充、初始化、初始化后等步骤,其中AOP就是发生在初始化这一步
- 单例Bean创建后,Spring会发布容器启动事件
- Spring 启动结束
1、AnnotatedBeanDefinitionReader 构造函数
* 1、创建环境变量对象设置属性registry 即注解配置应用上下文对象(AnnotationConfigApplicationContext)
* 2、配置属性conditionEvaluator(用于计算{@link Conditional}批注的内部类。)
* 3、在给定注册表中注册所有相关的注解后处理程序。(AnnotationConfigUtils.registerAnnotationConfigProcessors)
* 4、bean工厂注册的解析器有
* 1、注解感知顺序比较器(AnnotationAwareOrderComparator)
* 2、设置此BeanFactory的自定义自动装配候选解析器,以在决定是否应将bean定义视为自动连线的索引时使用。(ContextAnnotationAutowireCandidateResolver)
* 5、注册的注解处理器有
* 1、内部托管配置注解处理器(具有名称和别名的BeanDefinition的持有者。可以注册为内部bean的占位符。
也可以用于内部beandefinition的编程注册。如果您不关心BeanNameAware等,
那么注册RootBeanDefinition或ChildBeanDefcription就足够了。
自:(BeanDefinitionHolder))ConfigurationClassPostProcessor
2、内部托管的自动装配注解处理器。(AutowiredAnnotationBeanPostProcessor)
3、内部托管JSR-250注释处理器 AutowiredAnnotationBeanPostProcessor
4、jpaPresent=true时 内部托管JPA注解处理器 CommonAnnotationBeanPostProcessor
5、持久性注解处理器(PersistenceAnnotationBeanPostProcessor)
6、内部托管的@EventListener注解处理器(EventListenerMethodProcessor)
* 2、 创建读取路径里的class文件对象
* 1、 注册默认过滤器
* 1、 AnnotationTypeFilter(Component.class)
* 2、 AnnotationTypeFilter(javax.annotation.ManagedBean)
* 3、 AnnotationTypeFilter(javax.inject.Named)
* 2、设置环境变量
* 3、设置资源处理器
* 1、 给定资源加载器的默认资源模式解析器。resourcePatternResolver ResourcePatternUtils.getResourcePatternResolver
* 2、 为给定的资源加载器创建新的缓存元数据读取器工厂,如果支持,则使用共享资源缓存,否则使用本地资源缓存。CachingMetadataReaderFactory
* 3、 使用给定的类加载器从“META-INF/spring.components”加载并实例化候选组件索引。
* 如果noindex可用,则返回null CandidateComponentsIndexLoader(框架内内部使用的候选组件索引加载机制。).loadIndex
* 4、调用register方法注册一个或多个要处理的组件类。请注意,必须调用refresh(),以便上下文完全处理新类。
* 1、AnnotatedBeanDefinitionReader this.reader.register(componentClasses);
* 1、调用doRegisterBean
* 1、创建通用注解解析器对象(AnnotatedGenericBeanDefinition)abd
* 2、根据@Conditional注释确定是否应跳过项目。
* ConfigurationPhase将从项目类型中推导出来
* (即@Configuration类将为ConfigurationPhase.PARSE_Configuration)
* 3、指定用于创建bean实例的回调,作为声明式指定的工厂方法的替代方法。
* 如果设置了这样的回调,它将覆盖任何其他构造函数或工厂方法元数据。
* 然而,bean属性总体和潜在的注解驱动注入仍将照常应用。
* 4、解析适用于所提供的Bean定义的ScopeMetadata。
* 实现当然可以使用他们喜欢的任何策略来确定作用域元数据,
* 但一些立即想到的实现可能是使用所提供定义的类上存在的源代码级注释,
* 或者使用所提供的定义的BeanDefinition.attributeNames()中存在的元数据
* this.scopeMetadataResolver.resolveScopeMetadata(abd)
* 5、为bean设置目标作用域的名称。
* 默认状态是singleton状态,尽管只有当bean定义在包含工厂中变为活动状态时才应用此状态。
* bean定义最终可能会从父bean定义继承其作用域。
* 由于这个原因,默认的作用域名称是一个空字符串(即“”),在设置解析的作用域之前,将假定为singleton状态。
* 6、处理通用定义注解 processCommonDefinitionAnnotations
* 7、限定符(qualifiers)注解不为空 处理限定符
* 1、Primary.class == qualifier
* 2、Lazy.class == qualifier
* 3、用于解析自动装配候选者的限定符。
* 包含一个或多个此类限定符的bean定义允许对字段或参数上的注释进行细粒度匹配。
* AutowireCandidateQualifier
* 8、创建一个新的Bean定义持有者BeanDefinitionHolder
* 9、为提供的目标bean生成一个作用域代理,使用内部名称注册targetbean,
* 并在作用域代理上设置“targetBeanName”。
* ScopedProxyUtils.createScopedProxy
* 10、向给定的bean工厂注册给定的bean定义。
* BeanDefinitionReaderUtils.registerBeanDefinition
* 5、调用refresh()
* 1、准备此上下文以进行刷新 prepareRefresh()
* 1、设置开始刷新标志
* 2、初始化上下文环境中的任何占位符属性源。initPropertySources()
* 3、验证标记为必需的所有属性是否可解析:请参阅ConfigurationPropertyResolver#setRequiredProperties
* getEnvironment().validateRequiredProperties()
* 4、存储预刷新ApplicationListeners。。。
* 5、允许收集早期ApplicationEvents,将在多播主机可用后发布。。。
* this.earlyApplicationEvents = new LinkedHashSet<>()
*
* 2、告诉子类刷新内部bean工厂。obtainFreshBeanFactory()
* 1、指定一个用于序列化的id,如果需要,允许将此BeanFactory从此id序列化回BeanFactory对象。
* refreshBeanFactory();
* 2、ConfigurableListableBeanFactory.getBeanFactory
*
* 3、准备bean工厂以便在此上下文中使用。prepareBeanFactory(beanFactory)
* 1、告诉内部bean工厂使用上下文的类加载器等。
* 2、{@code spring.spel.ignore}系统属性控制的布尔标志,
* 该属性指示spring忽略SpEL,即不初始化SpEL基础设施。<p>默认值为“false”
* 3、添加一个PropertyEditorRegister以应用于所有bean创建过程。这样的注册器创建新的PropertyEditor实例,
* 并在给定的注册表中注册它们,对于每次创建bean的尝试都是新鲜的。
* 这避免了在自定义编辑器上进行同步的需要;因此,通常最好使用此方法而不是registerCustomEditor。
* 4、使用上下文回调配置bean工厂。beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
* 5、忽略自动装配的给定依赖项接口。
* 这通常由应用程序上下文用于注册以其他方式解析的依赖项,
* 如BeanFactory通过BeanFactory软件或ApplicationContext通过ApplicationContextAware。
* 默认情况下,仅会忽略BeanFactoryAware接口。对于要忽略的其他类型,请为每个类型调用此方法。
* 6、BeanFactory接口未在普通工厂中注册为可解析类型。MessageSource已注册(并为自动装配找到)为bean。
* 7、注册早期后处理器,以便将内部bean检测为ApplicationListeners。
* beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
* 8、检测LoadTimeWeaver并准备编织(如果发现)
* 9、注册默认环境bean。
*
* 4、允许在上下文子类中对bean工厂进行后处理。postProcessBeanFactory(beanFactory)
*
* 5、调用在上下文中注册为bean的工厂处理器。invokeBeanFactoryPostProcessors(beanFactory)
* 1、调用bean工厂后置处理器。PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
* 1、尽管看起来这种方法的主体很容易,重构以避免使用多个循环和多个列表,使用的多个列表和对处理器名称的多次传递是
故意的。我们必须确保遵守PriorityOrdered的合同和有序处理器。
具体来说,我们决不能让处理器实例化(通过getBean()调用)或在ApplicationContext中注册顺序不对。
在提交更改此方法的拉取请求(PR)之前,请查看
所有拒绝的涉及更改PostProcessorRegistrationDelegate的PR的列表
如果有,请首先调用BeanDefinitionRegistryPostProcessors。
2、若beanFactory是BeanDefinitionRegistry的实例
1、在标准初始化后修改应用程序上下文的内部bean定义注册表。
所有的常规bean定义都将被加载,但还没有任何bean被实例化。
这允许在下一个后处理阶段开始之前添加进一步的bean定义。
遍历beanFactoryPostProcessorslist 调用registryProcessor.postProcessBeanDefinitionRegistry(registry)
2、不要在这里初始化FactoryBeans:我们需要保留所有常规bean。
未初始化,让bean工厂的后处理器应用于它们!
在实现的BeanDefinitionRegistryPostProcessors之间分离PriorityOrdered、Ordered和其他。
* 3、首先,调用实现PriorityOrdered的BeanDefinitionRegistryPostProcessors。
* beanFactory.getBeanNamesForType(
* BeanDefinitionRegistryPostProcessor.class, true, false);
* 。。。。。
* 4、接下来,调用实现Ordered的BeanDefinitionRegistryPostProcessors。
* beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
* 5、最后,调用所有其他BeanDefinitionRegistryPostProcessors,直到不再出现其他处理器为止。
* 6、现在,调用到目前为止处理的所有处理器的postProcessBeanFactory回调。
* 3、若不是则调用在上下文实例中注册的工厂处理程序。
* 4、在实现PriorityOrdered的BeanFactoryPostProcessors之间分离,有序,其余。
* 5、像是再重复第二步下面的。。。。。
* 2、检测LoadTimeWeaver并准备编织(如果同时发现)(例如,通过ConfigurationClassPostProcessor注册的@Bean方法)
* 6、注册拦截bean创建的bean处理器。registerBeanPostProcessors(beanFactory)
* 1、调用PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this)
* 1、注册BeanPostProcessorChecker,该程序在以下情况下记录信息消息:
// bean是在BeanPostProcessor实例化期间创建的,即当
// bean不符合由所有BeanPostProcessor处理的条件。
2、在实现PriorityOrdered的BeanPostProcessor之间进行分隔,有序,以及其他。
3、首先,注册实现PriorityOrdered的BeanPostProcessor。
4、接下来,注册实现Ordered的BeanPostProcessor。
5、现在,注册所有常规BeanPostProcessor。
6、最后,重新注册所有内部类BeanPostProcessor。
7、将用于检测内部bean的后处理器重新注册为ApplicationListeners,将其移动到处理器链的末尾(用于拾取代理等)。
* 7、初始化此上下文的消息源。initMessageSource()
* 1、检查bean是否存在MESSAGE_SOURCE_BEAN_NAME
* 1、存在
* 1、使MessageSource知道父MessageSource。
* 2、不存在 使用空MessageSource可以接受getMessage调用。
* 实例化一个DelegatingMessageSource对象注册进bean工厂
* 8、初始化此上下文的事件多播器。initApplicationEventMulticaster()
* 1、实例化SimpleApplicationEventMulticaster对象
* 2、将其注册进bean工厂
*
* 9、初始化特定上下文子类中的其他特殊bean。onRefresh()
*
* 10、检查侦听器bean并注册它们。registerListeners()
* 1、首先注册静态指定的侦听器。
* 2、发布早期的应用程序事件,现在我们终于有了一个多播。。。
*
* 11、实例化所有剩余的(非惰性init)singleton。
* 1、为此上下文初始化转换服务。
* 2、如果没有BeanFactoryPostProcessor,则注册默认嵌入值解析器,
* (如PropertySourcesPlaceholderConfigurer bean)在以下任何之前注册:
* 此时,主要用于注释属性值的解析。
* 3、尽早初始化LoadTimeWeaverAware bean,以便尽早注册其转换器。
* 4、停止使用临时ClassLoader进行类型匹配。
* 5、允许缓存所有bean定义元数据,不需要进一步更改。beanFactory.freezeConfiguration()
* 6、实例化所有剩余的(非延迟初始化)单例。beanFactory.preInstantiateSingletons()
*
* 12、最后一步:发布相应的事件。
* 1、清除上下文级资源缓存(例如来自扫描的ASM元数据)clearResourceCaches()
* 2、为此上下文初始化生命周期处理器。initLifecycleProcessor()
* 3、首先将刷新事件传播到生命周期处理器。getLifecycleProcessor().onRefresh()
* 4、发布最终事件。publishEvent(new ContextRefreshedEvent(this))
*
* 13、如果有异常则处理异常
* 1、销毁已创建的singleton以避免挂起资源。destroyBeans()
* 2、重置“活动”标志。停止刷新。cancelRefresh
* 14、重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。。。resetCommonCaches()
* 1、清除内部方法/字段缓存。ReflectionUtils.clearCache()
* 2、清除内部注解元数据缓存。AnnotationUtils.clearCache()
* 3、清除内部ResolvableType/SerializableTypeWrapper缓存。ResolvableType.clearCache()
* 4、清除给定ClassLoader的自省缓存,删除该ClassLoador下所有类的自省结果,并从接受列表中删除ClassLoader。CachedIntrospectionResults.clearClassLoader(getClassLoader())
*
事务
介绍spring事务
spring 事务失效场景
一、Spring事务失效的几种常见场景:
-
方法不是public的:Spring的AOP代理只适用于public方法。如果你的方法不是public,Spring将无法创建代理来管理事务。
-
方法不是同一个实例的:如果你在方法调用时使用了不同的实例(可能是通过new关键字直接创建的实例,而不是通过Spring容器获取的实例),Spring将无法管理这个方法的事务。
-
事务方法被静态方法调用:Spring事务需要通过代理类调用事务方法,而静态方法不能被代理。
-
事务方法内部调用:如果在事务的方法内部调用了另一个方法,且该方法也被声明为事务性方法,内部方法不会参与外部方法的事务。
-
异常处理不当:默认情况下,Spring事务只有在运行时异常(RuntimeException)和错误(Error)发生时才会回滚。如果捕获了异常并且没有重新抛出,事务不会回滚。
-
未正确配置@Transactional注解:例如,propagation、isolation等属性设置不当,可能导致事务行为不符合预期。
-
数据库本身不支持事务:例如,某些数据库如MyISAM不支持事务,若配置在这类数据库上,事务将不会生效。
-
事务方法未在事务管理的Bean中:如果事务方法不在Spring管理的Bean中,或者没有配置为Bean,事务将不会生效。
-
方法不是Bean的自己的方法:如果方法是通过类的实例(非Bean实例)调用的,Spring无法创建事务。
-
异步方法没有正确配置:如果你使用了@EnableAsync和@Async注解,并希望在事务方法中异步执行某些操作,确保异步方法被正确配置,否则事务可能不会按预期工作。
- 没有加@Configuration注解
解决这些问题的方法通常涉及到确保方法是public的,确保使用Spring容器管理的Bean,检查@Transactional注解的使用,确保数据库支持事务,并且正确处理异常。
二、图例
spring 面试题
1.实例化bean的方式
1,使用类构造器实例化(无参构造函数) :直接通过Spring工厂返回类的实例对象
2,使用静态工厂方法实例化(简单工厂模式) :Spring工厂调用自定义工厂的静态方法返回类的实例对象。
3,使用实例工厂方法实例化(工厂方法模式) :Spring工厂调用工厂的普通方法(非静态方法)返回类的实例对象。
2.定义Bean有几种方式
1.Component
2.Controller Service Mapper RestController
3.Bean
4.Configuration
5.Imoprt
6.BeanDefinition
7.<bean/>配合ImportResource
8.ControllerAdvice 控制器的切面 可以对响应的数据进行增强
5.3@Resource和@Autowired的区别
@Resource注解会先根据名字去找Bean,没找到就会去根据属性去找,诺是找到多个就会报错,同时@Resource还能指定名字,一旦没找到直接报错,不会根据类型再去找
@Autowired注解会根据属性去找Bean,如果找到多个,会根据名字去确定Bean,还是没找到就会报错
@Autowired是Spring层面提供的,与Spring强绑定
@Resource是jdk提供的,没有和Spring强绑定
4.Mybatis-plus对比Mybatis的优势是什么?
1.封装了常用的操作,减少了代码量
2.提供了一些常用的CRUD的操作
3.提供了分页查询,逻辑删除,多表查询,乐观锁,大大提高了开发效率
4.插件支持,方便二级缓存,性能分析,分页插件等等的集成
5.也可以通过配置文件或注解进行配置
5.单例Bean是单例模式吗?
通常来说,单例是值在一个jvm中,一个类只能创建出一个对象,有很多方式来实现单例Bean,那如果在两个jvm中保持单例就要用到分布式锁,
而在spring中的单例也是单例模式,只不过范围比较小,它的范围是在一个BeanName中,一个BeanName对应的一个Bean对象,不同的BeanName对应着不同的Bean的对象,同一个类也可以有不同的BeanName
6.AspectJ和SpringAop的区别
SpringAop是利用动态代理来实现的,如果一个Bean实现了接口,就会采用jdk动态代理来生成该接口的动态代理,如果Bean没有实现接口,那么就会采用CGLIB动态代理来实现,可以用SpringAop来实现登录验证,日志记录,权限控制
他们两者之间没有啥特别的关系,AOP表示面向切面编程,是一种思想,什么人都可以实现,AspectJ就是其中之一,它会在编译期就对类进行增强,要用Aspectj就要用Aspectj开发的编译器来执行项目,SpringAop是基于动态代理来实现的Aop,同时支持@before,@after,@Around等注解,虽然注解相同,但是底层的实现完全不同
7.如何理解Spring事务的传播机制?底层如何实现的
一个线程在运行过程中,可能连续调用好几个方法,调用某一个方法是可能就开启了一个spring事务,那么在调用接下来的方法时,到底是共用一个事务,还是开启一个新的事务,这就是事务的传播机制;
事务的传播机制种类
REQUIRED:如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务。这是默认的传播行为。
REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则挂起当前事务。
SUPPORTS:如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务方式执行。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起当前事务。
MANDATORY:如果当前存在事务,则加入该事务,如果当前没有事务,则抛出异常。
NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
NESTED:如果当前存在事务,则在当前事务的嵌套事务中执行,如果当前没有事务,则创建一个新的事务。
9.BeanFactory和ApplicationContext的区别
BeanFactory是spring中的核心组件,也是顶级接口,表示Bean的工厂,可以生成Bean,维护Bean,而ApplicationContext继承该接口,拥有这接口的所有方法,并且同时继承了其他的接口,例如国际化,和获取环境变量,事件发布的能力 这些都是BeanFactory接口所没有的
10.什么是自动配置和自动装配
我的理解是自动装配就是@Autowrite注解,也就是依赖注入
自动配置就是在用springboot时springboot帮我们配置的一些比如
1.Mybatis 的SqlSessionFactory
2.AOP的EnableAspectJAutoProxy注解 等等
而在使用spring的时候,这些配置需要自己去配置
11.Spring容器的启动流程
1.在启动或创建Spring容器时:
2.首先会扫描得到所有的BeanDefinition对象,然后存入一个Map中
3.然后筛选出非懒加载的单例BeanDefinition进行创建Bean,而多例Bean不需要启动容器时去创建,而是每次获取Bean的时候就会用BeanDefiniton创建
4.利用BeanDefinition创建Bean就是创建Bean的生命周期,
5.单例Bean创建完成后,spring会发布一个容器启动事件 你可以监听容器启动事件,在事件监听器中执行一些初始化操作、加载缓存数据、启动定时任务等
6.spring容器启动结束
12.SpringBoot的启动流程,又做了哪些事?
1.加载配置文件,加载application.properties、application.yml等的配置文件,文件中配置了一些重要信息
2.创建Spring容器(ApplicationContext),基于配置文件加载一个Spring的应用上下文,管理和维护Bean的生命周期
3.执行自动配置,springboot提供了自动配置,找到spring.factories文件中定义的配置类信息,比如是否懒加载,等
4.启动嵌入的容器,Tomcat,jetty容器等,来监听端口
5.处理请求,springboot会接收http请求,并找到相应的Contrller,进行处理及响应
6.关闭程序,接收到关闭信号后,springboot会先关闭嵌入的容器,停止接收新的请求,摧毁容器,释放资源
13.如何理解SpringBoot的自动配置
自动配置是springboot中最重要的一个特性,大大减轻了开发人员的工作量
我的理解有:
首先,他是约定大于配置,SB会使用一系列约定来判断应用程序的配置需求,从而减少显示配置的需求,在绝大数情况下不需要自己手动,SB会帮你配置好
然后,自动扫描和类路径,SB在启动时会扫描classpath路径下的配置信息
自动装配Bean:Spring Boot的自动配置会根据项目的依赖关系和配置信息,自动装配相应的Bean
还有,条件配置和自定义配置,SB里面的配置会根据一个条件注解来判断是否需要加载Bean,如果你自己自定义配置了,也能覆盖SB的配置
jdk的SPI和springboot的自动装配 知乎 CSDN
14.如何理解SpringBoot的Starter机制
1.简化依赖管理:starter可以手动避免大量的依赖,只需要引入相关的Starter依赖,就可以获取所需的全部依赖,并且版本都兼容
2.自动配置:SpringBootStarter包含了与功能相关的自动配置类,减轻了开发人员的工作量
3.模块化和可重用性:将一组相关的依赖打包为一个Starter,这样就能反复重用
编写一个自己的starter
5.15如何理解spring.factories文件的作用?
这个文件其实spring框架中的一个机制,用于实现类路径下自动发现和加载扩展的功能,它允许第三方库或模块在应用程序中注册自己的实现,从而扩展或定义spring框架的行为
16为什么springaop默认cglib动态代理
功能扩展性:CGLIB 可以对类的任意方法进行代理,而不仅限于接口中定义的方法。这使得它在某些情况下更加灵活和强大,特别是对于没有实现接口的类进行代理。
无需接口:CGLIB 代理不依赖于接口,这对于一些只有具体实现类而没有接口的情况非常方便。Spring Boot 鼓励使用基于注解的开发,常见的 Bean 往往是普通的类,而不是接口的实现类。
简化配置:通过使用 CGLIB 代理,Spring Boot 可以自动完成代理的生成和注入,无需额外的配置。这样可以减少开发人员的工作量,简化配置过程
17.@Bean的工作原理
spring容器启动时会扫描到该注解的类 如何解析该类,发现类中有@Bean注解,就会把名字作为bean的名字,把返回类型作为bean的类型,解析@Bean中的各个属性,解析该方法有没有其他注解 最后放入BeanDefinition对象中,解析BeanDefinition中的非懒加载的Bean,然后创建Bean
18.SpringBoot中用到的设计模式
单例模式:spring中的大多数Bean都是单例Bean
简单工厂:BeanFactory ,Bean的工厂getBean创建Bean
工厂方法:factoryBean,实现这个接口重写getObject进行增强
代理模式:SpringAop,使用了动态代理 ,jdk动态代理和cglib字节码生产技术
模板方法模式:redisTemplate jdbcTemplate,里面提供了一些列模板方法
观察者模式:当一个对象的状态发生改变的时候,所有依赖于它的对象都会得到通知,比如ApplicationListener
策略模式:Bean的实例化包含原生对像的实例化和代理对象的实例化,不同的实例化内部逻辑不一样
装饰器模式:一些以Wrapper命名的类都是装饰器模式 。BeanWrapper去访问Bean的属性和方法的一个类
适配器模式:MVC模块的HandleAdapter就用到适配器模式
19.过滤器和拦截器的区别
①:拦截器是基于java的反射机制的,而过滤器是基于函数的回调。 ②:拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。 ③:拦截器只对action请求起作用,而过滤器则可以对几乎所有的请求起作用。 ④:拦截器可以访问action上下文、值、栈里面的对象,而过滤器不可以。 ⑤:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。 ⑥:拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
20.Static为什么不能依赖注入
依赖注入是对对象而言的,而静态成员static不依赖于特定的对象,它与类的本身关联,所以spring不支持
session是一个会话,默认情况下服务端会根据每一个浏览器的请求servlet容器都分配一个session对象,本质上可以认为是一个currenthashmap,用来存储当前会话的数据,http本身是一个无状态的协议,服务端不知道客户端发来的多次请求是不是属于同一个用户,所以session是用来弥补http无状态的一个不足,服务端可以利用session存储用户端在同一个会话里面的产生的多次请求的一个记录,
这两者就能实现一个有状态的http协议
22.Component和Bean的区别
用途不同:@Component普通标识类,@Bean标识配置类中Bean对象
使用方式不同:@Component是类级别的注解,Spring可以扫描被标注的类,并把它们注入到容器中。@Bean使用在方法上,表示此方法返回一个Bean对象注入到spring容器中
控制权不同,@Component备注的类是由Spring框架统一管理和创建,@Baen允许开发人员手动控制Bean的创建和配置
23.用户在浏览器输入url后会有什么操作
DNS解析,浏览器会对输入的URL进行域名解析,查找到对应的IP地址,如果该域名被缓存过就直接去缓存获取,如果没被缓存就向本地DNS服务器发出请求,本地DNS没有缓存就会向根域名服务器发出请求来获取IP地址
进行TCP可靠性连接,浏览器向服务器进行三次握手操作,syn,syn-ack,ack三个阶段
发送http请求,向服务端发送http请求,请求返回响应数据
服务器响应请求,包括状态码,响应头,响应体
浏览器解析渲染
断开TCP连接,四次挥手fin,ack,fin,ack四个阶段
24.遇到死锁如何解决
互斥条件
请求保持条件:在第一次执行的时候一次性申请所有的共享资源
不可抢占条件:在申请其他资源的时候,如果申请不到就主动放弃自己占有的资源
循环等待条件:按照顺序来申请锁资源
互斥条件是锁本身的特点所以不能被破坏,但凡涉及到互斥锁的地方都会有死锁的可能,行锁,表锁,分布式锁
25.SpringIoc工作流程
IOC容器的初始化阶段,根据xml和注解等bean的声明方式,解析加载后生成BeanDefinition,然后把BeanDefinition注册到IOC容器中去,BeanDefinition实体包含Bean的一些定义,把他保持到map集合里面,是ioc容器控制反转的一个核心
完成初始化和依赖注入,通过反射对非懒加载的单例Bean进行初始化,完成Bean的依赖注入
Bean的使用,通过注解进行依赖注入使用
@SpringBootApplication 注解介绍
@SpringApplication 注解是Spring Boot框架中用来标识Spring Boot应用主类的。它提供了一种快捷的方式来启动和配置Spring应用程序。
@EnableAutoConfigration注解: 负责自动配置类的导入,也就是把自动配置类导入到Spring容器中,从而得到解析
@SpringBootConfigration注解:等同于@Configration,表示当前类是一个配置类
主要作用是配置和启动Spring Boot应用。它提供了一些有用的属性,例如@ComponentScan:
-
scanBasePackages:定义Spring扫描的基础包路径。 -
exclude:排除某些自动配置的类。 -
excludeName:排除某些自动配置的类的名称。
所以在使用SpringBoot时,我们一般会加上@SpringBootApplication 这个注解,因为只有加了他SpringBoot才会进行扫描、自动配置并解析。
指示一个配置类,该类声明一个或多个@Bean方法,还触发自动配置和组件扫描。这是一个方便的注释,相当于声明@Configuration、@EnableAutoConfiguration和@ComponentScan。
Bean 实例化与初始化的区别
- Spring 创建一个Bean对象时,会先创建出一个Java对象,会通过反射来执行类的构造方法来得到一个Java对象,而这个过程就是Bean的实例化。
- 得到Bean对象后会进行依赖注入,依赖注入之后就会进行初始化了,而Bean的初始化就是调用Bean对象里面的特定方法,比如如果实现了InitialzingBean接口,那么框架就会调用aferPropertiesSet方法,或者执行init-method指定的方法
Spring Aop 与AspectJ的简明区别
- AspectJ 是在编译前把额外的逻辑生成到字节码逻辑
- AOP 是动态代理的,在运行中生成的
- 共用AspactJ一套注解
- 类实现了接口底层会用JDK 实现,否则就用CgLib实现
Spring 事务失效场景
- 没加@Configuration注解
- 方法内的自调用
- 方法是私有的,Spring事务是基于Cglib实现的,而cglib是基于父子类的,被代理对象是父类,如果被代理的方法是私有的,子类无法重写,也就无法增加Spring事务逻辑
- 单独线程处理事务
- 手动处理了异常
- 类没有被Spring管理
- 数据库不支持事务
- 方法被final修饰
ApplicationContext 和 BeanFactory 区别
* 1、ApplicationContext继承了BeanFactory
* 2、ApplicationContext拥有BeanFactory的所有功能
* 3、ApplicationContext拥有额外的功能、例如获取环境变量、事件发布、资源等
springboot 中spring.factories 作用
- spring.factories 是SpringBoot SPI机制实现的核心,SPI表示一种扩展机制,spring.factories作用是对SpringBoot进行扩展的。
- 在spring.factories文件中配置上接口对应的实现类即可实现对springboot的扩展。
spring 事件简介
一、实现原理
使用了设计模式当中的观察者模式,该模式是定义了一种一对多的依赖关系,多个观察者可以监听同一个主题对象,当这个对象发生变化时,会通知相应的观察者会做出相应的变化。
二、组成
-
事件监听器:需要继承ApplicationListener或定义@EventListener,用于监听和处理特定的事件
-
事件类:需要继承ApplicationEvent或子类,用于封装事件的具体信息
-
事件发布者:用于发布事件,应用上下文ApplicationContext已实现 ApplicationEventPublisher
-
事件广播器:
ApplicationEventMulticaster用于管理事件监听器的注册和事件的广播。
三、特性
-
解耦:通过事件机制,发起事件的组件不需要关心谁执行,处理事件的组件也不需要关心来源,从而降低了组件之间的耦合度;
-
异步处理:spring事件支持异步处理,事件可以在不同的线程中执行,从而提高了响应速度及并发性
-
灵活性: 新的事件可以轻松的连接到事件流程里面,从而不需要修改原来的代码,容易扩展
-
应用场景广泛:可以应用在数据更新通知、日志处理、异步任务触发等
四、示例
// 定义事件类
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
// 定义事件监听器
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received CustomEvent: " + event.getMessage());
}
}
// 或者使用@EventListener注解
@Component
public class AnotherCustomEventListener {
@EventListener
public void handleCustomEvent(CustomEvent event) {
System.out.println("Another CustomEvent received: " + event.getMessage());
}
}
// 发布事件
@Component
public class CustomEventPublisher {
@Autowired
private ApplicationEventPublisher publisher;
public void publishCustomEvent(String message) {
CustomEvent customEvent = new CustomEvent(this, message);
publisher.publishEvent(customEvent);
}
}