目录
五、JDK动态代理(实现接口+反射+代理类+重写方法)和CGLIB代理有什么区别?
六、BeanFactory和FactoryBean有什么区别?
一、Spring中的常用注解
@Controller - 用于 Spring MVC 项目中的控制器类。
@Service - 用于服务类。
@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
@Autowired - 用于在 spring bean 中自动装配依赖项。
@Qualifier - 使用 @Autowired 注解,以避免在存在多个 bean 类型实例时出现混淆。
@Scope - 用于配置 spring bean 的范围。
@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。
@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)。
二、Spring的执行流程
1.启动容器(启动项目)。
2.读取配置文件,初始化。
3.使用 xml 直接注册 beanb)配置 bean 根 (扫描)路径,将 bean 存储到 spring 中,通过类注解进行扫描和装配。
4.将 bean 从 spring 读取出来,装配到相应的类。
三、Bean的生命周期
所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个对象的生命周期。
Bean 的生命周期分为以下 5 大部分:
1.实例化:当Spring容器接收到一个Bean的定义时,会根据该定义创建一个Bean的实例。
2.属性赋值:创建Bean的实例后,Spring通过反射机制将Bean属性设置为相应的值。通常情况下,这些 Bean 属性的值来自于配置文件或注解等方式。
3.初始化:在Bean实例化并设置好所有属性之后,Spring容器将调用特定的方法对Bean进行初始化,例如执行自定义的初始化方法或BeanPostProcessor接口中的回调方法等。
4.使用Bean:当Bean初始化完成后,它可以被Spring容器使用了。在此阶段,Bean可以响应容器中的请求,执行相应的业务逻辑。
5.销毁:当应用程序关闭或者Spring容器销毁时,会调用已注册的bean的销毁方法,以释放资源。这个销毁方法也可以是自定义的,需要实现DisposableBean接口或者添加@PreDestroy注解。
四、SpringIOC和AOP
IOC 叫做控制反转,指的是通过Spring来管理对象的创建、配置和生命周期,这样相当于把控制权交给了Spring,不需要人工来管理对象之间复杂的依赖关系,这样做的好处就是解耦。在Spring里面,主要提供了 BeanFactory 和 ApplicationContext 两种 IOC 容器,通过他们来实现对 Bean 的管理。
AOP 叫做面向切面编程,他是一个编程范式,目的就是提高代码的模块性。Srping AOP 基于动态代理的方式实现,如果是实现了接口的话就会使用 JDK 动态代理,反之则使用 CGLIB 代理,Spring中 AOP 的应用主要体现在事务、日志、异常处理等方面,通过在代码的前后做一些增强处理,可以实现对业务逻辑的隔离,提高代码的模块化能力,同时也是解耦。Spring主要提供了 Aspect 切面、JoinPoint 连接点、PointCut 切入点、Advice 增强等实现方式。
五、JDK动态代理(实现接口+反射+代理类+重写方法)和CGLIB代理有什么区别?
JDK 动态代理主要是针对类实现了某个接口,AOP 则会使用 JDK 动态代理。他基于反射的机制实现,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
而如果某个类没有实现接口,AOP 则会使用 CGLIB 代理。他的底层原理是基于 asm 第三方框架,通过修改字节码生成成成一个子类,然后重写父类的方法,实现对代码的增强.
六、BeanFactory和FactoryBean有什么区别?
BeanFactory是Bean的工厂, ApplicationContext 的父类,IOC 容器的核心,负责生产和管理 Bean 对象。
FactoryBean 是 Bean,可以通过实现 FactoryBean 接口定制实例化 Bean 的逻辑,通过代理一个Bean对象,对方法前后做一些操作。
七、Spring事务失效的场景
- 被@Transaction修饰的方法修饰符不是Public
- 存储引擎不支持事务(MySam)
- 方法内部使用了this
- 存在循环依赖
八、Spring如何解决循环依赖
首先,Spring 解决循环依赖有两个前提条件:
1.不全是构造器方式的循环依赖(Setter注入和接口方法注入)
2.必须是单例
构造器注入的方式实例化和初始化不能分离,因此构造器注入的方式解决不了循环依赖。
基于上面的问题,我们知道Bean的生命周期,本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。
第一级缓存:用来保存实例化、初始化都完成的对象(成品Bean)
第二级缓存:用来保存实例化完成,但是未初始化完成的对象(未初始化的半成品Bean)
第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象
假设一个简单的循环依赖场景,A、B互相依赖。
A对象的创建过程:
创建对象A,实例化的时候把A对象工厂放入三级缓存
A注入属性时,发现依赖B,转而去实例化B。同样创建对象B,初始化注入属性时发现依赖A,依次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,然后把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入一级缓存。
接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存。
最后,一级缓存中保存着实例化、初始化都完成的A、B对象
因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。
九、Spring事务传播机制有哪些?
- PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这也是通常我们的默认选择。(无创有加)
- PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。(有无事务创事务)
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。