Spring+SpringBoot面试总结(近两万字)

Spring+SpringBoot面试总结

  • 一、Spring Bean
    • 1.1、bean的生命周期(对象的创建使用销毁)
      • 1.1.1、准备工作
      • 1.1.2、创建Bean对象
      • 1.1.3、注册销毁
    • 1.2、 bean的作用域
      • 1.2.1、配置方式
    • 1.3、 spring 自动装配 bean 有哪些方式(存疑存疑)
      • 1.3.1、xml
      • 1.3.2、注解扫描方式
  • 二、SpringlOC的理解,原理与实现?
    • 2.1、循环依赖问题
      • 2.1.1、什么是循环依赖问题
      • 2.1.2、为什么需要三级缓存
      • 2.1.3、如果构造方法出现了循环依赖问题怎么解决
    • 2.2、容器的创建
      • 2.3、基于XML管理bean
    • 2.4、基于注解管理bean
    • 2.5、javaConfig管理Bean
  • 三、Spring AOP
    • 3.1、代理的实现
      • 3.1.1、静态代理
      • 3.1.2、动态代理
    • 3.2、AOP使用
      • 什么情况AOP会失效
    • 4.3、 Spring事务实现原理
    • 4.4、Spring中事务失效的场景
  • 五、SpringBoot的自动装配
    • 5.1、使用和不使用SpringBoot在项目上有什么使用区别
    • 5.2、SpringBoot自动装配的实例
  • 六、SpringMVC的执行流程
    • 6.1、Spring MVC 的核心组件有哪些
    • 要将一个第三方的类配成为Bean有哪些方式?

一、Spring Bean

Bean 代指的就是那些被 IoC 容器所管理的对象。
IOC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类

1.1、bean的生命周期(对象的创建使用销毁)

在这里插入图片描述
在这里插入图片描述

1.1.1、准备工作

1.加载Bean定义
通过 loadBeanDefinitions 扫描所有xml配置、注解等将Bean记录在beanDefinitionMap

对于BeanDefinition的补充

Spring容器在进行实例化时,会将xml配置的<bean>的信息封装成一个BeanDefinition对象,Spring根据BeanDefinition来创建Bean对象,里面有很多的属性用来描述Bean
相关属性
beanClassName: bean 的类名
initMethodName:初始化方法名称
properryValues:bean 的属性值
scope:作用域
lazyInit:延迟初始化

1.1.2、创建Bean对象

通过 createBean 遍历 beanDefinitionMap 开始创建bean对象
具体步骤是
创建对象,填充属性,初始化示例,注册销毁

实例化
通过反射的方式生成对象
容器通过 createBeanInstance方法 进行对象构造,使用反射机制从Bean定义的BeanClass拿到类的构造方法(对于有多个构造方法的情况是,如果有@Autowired修饰的就优先拿),通过反射完成类的构造(此时Bean对象构造成功)

填充属性
通过populateBean(),方法为bean所需要的属性进行填充,对于@Autowired修饰的变量就会根据三级缓存进行依赖注入
调用aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置,可以实现这些接口就能拿到这些参数)

初始化
初始化示例
通过InitializingBean方法对这个实例进行初始化
初始化容器信息,通过invokeAwareMethod方法
初始化构造方法

如果Bean实现InitializingBean接口进行处理【未实现则不进行】
通过 invokeInitMethods 方法进行初始化:为实现了各种Aware接口(信息感知接口)的Bean设置诸如beanName、oeanFactory等容器信息(可以在bean实例中感知获取到对应的信息)

通过invokelnitMethods方法执行Bean的初始化方法(通过实现imnitializingBean接口而实现的afterPropertiesset方法(自己实现的 表示在Bean填充属性后执行)) 然后如果有标注的initMethod方法就会再执行这个方法

在初始化方法执行前后还会执行BeanPostProcessors(Bean后置处理器,继承这个接口实现自己的处理器)

Bean的后置处理
可以实现BeanPostProcessor接口重写其中的postProcessBeforeInitialization(前置) postProcessAfterInitialization(后置)
在invokeInitMethods 的前后进行

在后置处理中处理了包括:AOP

1.1.3、注册销毁

Spring Bean 的销毁流程主要包括两个阶段:销毁前和销毁后。

  1. 销毁前阶段:

    • 当 Spring 容器关闭时,会触发 Bean 的销毁工作。
    • 首先,会调用实现了 DisposableBean 接口的 destroy() 方法。该方法允许在销毁 Bean 之前做一些清理工作,例如释放资源等。
    • 然后,会调用自定义的销毁方法。我们可以在 Bean 中通过在方法上使用 @PreDestroy 注解,或在配置文件中使用 <destroy-method> 指定自定义的销毁方法。这些方法会在调用 destroy() 方法之后被调用。
  2. 销毁后阶段:

    • 在销毁 Bean 后,会调用实现了 BeanPostProcessor 接口的 postProcessBeforeDestruction() 方法。该方法允许在销毁 Bean 之后进行一些额外的处理。
    • 最后,会将销毁的 Bean 从 Spring 容器中移除。

需要注意的是,当 Bean 的作用域为原型(prototype)时,Spring 容器不会负责销毁这些 Bean。因此,我们需要自己确保在不再使用一个原型 Bean 时,手动进行销毁。可以通过自定义销毁方法或使用其他方式来实现。

1.2、 bean的作用域

在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围

singleton:单例(默认),对象在工厂初始化时创建
prototype:原型(多例),对象在工厂初始化后创建即获取对象时创建
request:在Web环境下,同一次请求创建一个实例
session:在Web环境下,同一次会话创建一个实例
application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。

1.2.1、配置方式

xml中也是scope
注解方式直接使用@Scope注解
是否是线程安全 也要看状态
比如Dao Service因为没有成员变量 所以是无状态的 单例也是线程安全

1.3、 spring 自动装配 bean 有哪些方式(存疑存疑)

1.3.1、xml

第一种 no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean

第二种 byName:通过bean的名称进行自动装配,(会自动搜索有没有与XXX同名的SetXXX)

byType:通过参数的数据类型进行自动装配

constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配

1.3.2、注解扫描方式

XML配置方式:
可以在Spring的XML配置文件中使用context:component-scan标签来启用组件扫描,并指定要扫描的包路径。

示例:

<context:component-scan base-package="com.example.app" />

基于Java Config的方式:
可以使用@Configuration注解的Java类作为配置类,通过在配置类中使用@ComponentScan注解来启用组件扫描,并指定要扫描的包路径。

示例:

@Configuration
@ComponentScan(basePackages = "com.example.app")
public class AppConfig {
    // 配置其他Bean等
}
基于注解的方式:
可以将@ComponentScan注解直接添加到Spring Boot应用程序的主类上,从而启用组件扫描,并指定要扫描的包路径。

示例:

@SpringBootApplication
@ComponentScan(basePackages = "com.example.app")
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

二、SpringlOC的理解,原理与实现?

控制反转: 原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理
DI: 依赖注入,把对应的属性的值注入到具体的对象中

容器
存储对象,使用map结构存储,在spring一般存在三级缓存,
整个bean的生命周期从创建到销毁都是由容器管理
开始吟唱Bean的生命周期

底层实现
在这里插入图片描述

2.1、循环依赖问题

在这里插入图片描述

2.1.1、什么是循环依赖问题

A依赖B B依赖A(A里面有属性B,B里面有属性A)
先创建A对象,实例化A对象,此时A对象的b属性为空,填充属性b
从容器中查找B对象,如果找到了就不存在循环依赖问题(因为可以直接赋值可)找不到就需要创建B对象
实例化B对象此时B对象中的a属性为空 ,需要填充a属性
所以再又从容器中找A对象,但是找不到(因为上面创建的A对象还是在实例化阶段,)
这就是完整的循环依赖问题

此时分析会发现A对象是存在的,只不过此时的A对象不是一个完整的状态,只完成了实例化但是未完成初始化,如果在程序调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先把非完整状态的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整对象的引用,
所以解决问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键,

当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中存在对象的几个状态,完成实例化但未完成初始化,完整状态,因为都在容器中,所以要使用不同的map结构来进行存储,此时就有了一级缓荐和二级缓存,如果一级缓存中有了,那么二级缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找的。一级缓存中放的是完整对象,二级缓存中放的是非完整对象
在这里插入图片描述

2.1.2、为什么需要三级缓存

一二级缓存能够解决普通对象的循环依赖问题但是代理对象就不行
如果A对象是代理对象只用二级缓存就没那么好
通过这个第三级缓存,里面有对象工厂,能够决定产生代理对象还是普通对象
A就会生成一个代理工厂放到三级缓存,当B需要时就会由这个代理工厂生成一个不完整的代理对象放到二级缓存
在这里插入图片描述

2.1.3、如果构造方法出现了循环依赖问题怎么解决

(因为先前的二级缓存存的是进行了实例化的半成品对象,即刚进行了构造函数)
在这里插入图片描述
可以开启延迟加载,即对象什么时候需要用什么时候采取创建对象,而不是在实例化的时候就把对象创建了

2.2、容器的创建

①BeanFactory
这是 IOC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员用。
②ApplicationContext
BeanFactory 的子接口,最常用

2.3、基于XML管理bean

入门案例
在这里插入图片描述
注意:此时获取的bean是没有属性值

依赖注入之setter注入
首先需要有一个类,这里假定是Student类,有属性和get和set方法(默认是无参构造器)
配置bean时为属性赋值

<bean id="studentOne" class="com.atguigu.spring.bean.Student">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)
-->
<!-- value属性:指定属性值 -->
<property name="id" value="1001"></property>
<property name="name" value="张三"></property>
<property name="age" value="23"></property>
<property name="sex" value="男"></property>
</bean>

依赖注入之构造器注入
首先在之前Student类的基础上添加有参构造器
配置bean

<bean id="studentTwo" class="com.atguigu.spring.bean.Student">
<constructor-arg value="1002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg value="女"></constructor-arg>
</

为类类型属性赋值 (在student类中有clazz类)
创建Clazz类和Student类后,在Student类中添加返回类型为Clazz的set和get方法
首先在XML中定义Clazz的Bean对象

<bean id="clazzOne" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="1111"></property>
<property name="clazzName" value="财源滚滚班"></property>
</

为Student中的clazz属性赋值:

<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
</bean>

为数组类型属性赋值
Student类中添加数组属性

②配置bean

<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
<property name="hobbies">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>打豆豆</value>
</array>
</property>
</bean>

2.4、基于注解管理bean

@Autowired注解
在成员变量上直接标记@Autowired注解即可完成自动装配,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。
@Autowired注解可以标记在构造器和set方法上
@Autowired注解在构造器上的使用类似于使用@Autowired注解在字段上,用于将依赖注入到构造器参数中。这种方式被称为构造器注入。
补充
注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
使用组件要先扫描才能找到注解(后面有补充)
使用注解后,每个组件仍然应该有一个唯一标识
可以将@Autowired注解加在成员变量,构造器 或者set方法上 这样都可以自动装配所需的对象

@Autowired工作流程
在这里插入图片描述

2.5、javaConfig管理Bean

在这里插入图片描述

三、Spring AOP

3.1、代理的实现

3.1.1、静态代理

通过将目标类和代理类实现相同的接口,让代理类持有真实类对象,然后在代理类方法中调用真实方法,在调用真实方法的前后增加我们需要的功能来达到增强的功能。

接口类:

public interface PayService {
    /**
     * 支付
     */
    public void pay();
 
    /**
     * 回调
     */
    public void callback();
}

实现类:
public class PayServiceImpl implements PayService{
    @Override
    public void pay() {
        System.out.println("pay支付");
    }
 
    @Override
    public void callback() {
        System.out.println("支付回调");
    }
}
代理类:

public class StaticPayServiceImpl implements PayService{
 
    private PayService payService;
 
    public void StaticPayServiceImpl(PayService payService){
        this.payService = payService;
    }
    @Override
    public void pay() {
        System.out.println("支付前增强一下");
        payService.pay();
        System.out.println("支付后增强一下");
    }
 
    @Override
    public void callback() {
        System.out.println("回调前增强一下");
        payService.callback();
        System.out.println("回调后增强一下");
    }
}

缺点:代码冗余,不利维护。

3.1.2、动态代理

AOP原理
aop 底层是采用动态代理机制实现的:接口+实现类

在Spirng当中动态代理的使用
1.如果目标对象实现了接口,默认情况下会采用JDK的动态代理来实现AOP
2.如果目标对象实现了接口,也可以强制使用CGlib来实现AOP
3.如果目标对象没有实现接口,必须采用Cglib库,Spirng会自动在JDK和CGlib用切换

Cglib动态代理补充
Cglib是动态代理对代理对象的Class文件加载进来,通过修改其字节码生成的子类来处理 , Cglib是基于继承父类生成的代理类.

JDK动态代理:
实现InvocationHandler这个接口,然后重写invoke方法
在newProxyInstance方法中,通过传入被代理的对象objectTarget,使用Proxy.newProxyInstance方法创建了一个代理对象。
在invoke方法中,它是在调用代理对象的方法时被调用的。在该方法中,先打印了被调用的方法名前缀,然后通过反射调用了被代理对象的相应方法,并将结果返回。最后,又打印了被调用的方法名后缀。

public class JdkProxy implements InvocationHandler {
 
    private Object objectTarget;
 
    public Object newProxyInstance(Object objectTarget){
        this.objectTarget = objectTarget;
        return Proxy.newProxyInstance(objectTarget.getClass().getClassLoader(), objectTarget.getClass().getInterfaces(), this);
    }
    /**
     *
     * @param proxy 被代理的对象
     * @param method 要调用的方法
     * @param args 方法调用时所需要的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try{
            System.out.println("通过JDK动态代理调用前" + method.getName());
            result = method.invoke(objectTarget, proxy);
            System.out.println("通过JDK动态代理调用后" + method.getName());
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}

CGLIB动态代理

如果目标对象没有实现接口,就是用CGLIB代理,但是无法对final,private,static方法实现代理

这个类实现了MethodInterceptor接口,它是CGLib动态代理的核心接口。

在newProxyInstance方法中,通过传入被代理的对象targetObject,使用Enhancer类创建了一个代理对象。Enhancer是CGLib中的一个关键类,用于生成代理类。

在intercept方法中,它是在调用代理对象的方法时被调用的。在该方法中,先打印了被调用的方法名前缀,然后通过methodProxy.invokeSuper方法调用了目标对象的相应方法,并将结果返回。最后,又打印了被调用的方法名后缀。

public class CGLibProxy implements MethodInterceptor {

// 目标类
private Object targetObject;

// 绑定关系
public Object newProxyInstance(Object targetObject){
    this.targetObject = targetObject;
    Enhancer enhancer = new Enhancer();
    // 设置代理类的父类(目标类)
    enhancer.setSuperclass(this.targetObject.getClass());
    // 设置回调函数
    enhancer.setCallback(this);
    // 创建子类(代理对象)
    return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object result = null;
    try{
        System.out.println("通过CGLIB动态代理调用前" + method.getName());
        result = methodProxy.invokeSuper(o, args);
        System.out.println("通过CGLIB动态代理调用后" + method.getName());
    }catch(Exception e){

    }
    return result;
}

}

3.2、AOP使用

基于注解的AOP

待实现类

@Component
public class CalculatorPureImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("方法内部 result = " + result);
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
System.out.println("方法内部 result = " + result);
return result;
}

创建切面类并配置

// @Aspect表示这个类是一个切面类
@Aspect
// @Component注解保证这个切面类能够放入IOC容器
@Component
public class LogAspect {
@Before("execution(public int com.atguigu.aop.annotation.CalculatorImpl.*
(..))")
//表示匹配 com.atguigu.aop.annotation.CalculatorImpl 类中任意公共方法的执行。
public void beforeMethod(JoinPoint joinPoint){
	String methodName = joinPoint.getSignature().getName();
	String args = Arrays.toString(joinPoint.getArgs());
	System.out.println("Logger-->前置通知,方法名:"+methodName+",参
	数:"+args);
}
@After("execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))")
public void afterMethod(JoinPoint joinPoint){
	String methodName = joinPoint.getSignature().getName();
	System.out.println("Logger-->后置通知,方法名:"+methodName);
}
@AfterReturning(value = "execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result){
	String methodName = joinPoint.getSignature().getName();
	System.out.println("Logger-->返回通知,方法名:"+methodName+",结
	果:"+result);
}
@AfterThrowing(value = "execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){
	String methodName = joinPoint.getSignature().getName();
	System.out.println("Logger-->异常通知,方法名:"+methodName+",异常:"+ex);
}
@Around("execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
	String methodName = joinPoint.getSignature().getName();
	String args = Arrays.toString(joinPoint.getArgs());
	Object result = null;
	try {
		System.out.println("环绕通知-->目标对象方法执行之前");
		//目标对象(连接点)方法的执行
		result = joinPoint.proceed();
		System.out.println("环绕通知-->目标对象方法返回值之后");
		} catch (Throwable throwable) {
			throwable.printStackTrace();
			System.out.println("环绕通知-->目标对象方法出现异常时");
		} finally {
			System.out.println("环绕通知-->目标对象方法执行完毕");
		}
		return result;
		}
}

执行顺序
正常执行:@Before—>方法–>@AfterReturning–>@After

异常执行:@Before–>方法—>@AfterThrowing–>@After
后置通知在返回通知或者异常通知之后执行

Spring AOP and AspectJ AOP 有什么区别?

Spring AOP 是基于代理的 AOP 框架,它通过在目标对象的前后插入切面逻辑来实现横切关注点的支持。Spring AOP 的实现方式是通过动态代理来生成代理对象,并将切面逻辑织入到目标对象的方法调用中。

AspectJ AOP 是基于编译时或运行时的字节码增强技术实现的 AOP 框架。它使用 AspectJ 编程语言来定义切面和切入点,并通过织入器将切面逻辑织入到目标对象的字节码中。

什么情况AOP会失效

#四、 Spring事务
声明式事务基于@Transactional注解

如果事务设置为只读属性
@Transactional(readOnly = true)就只能进行读操作
在其中进行了增删改操作就会抛出异常
@Transactional(timeout = 3)
超时回滚 释放资源
也可以设置回滚策略
@Transactional(noRollbackFor = ArithmeticException.class)比如就是发生算数时异常不回滚

@Transactional注解的参数

propagation事务的传播行为,默认值为 REQUIRED,可选的值在上面介绍过
isolation事务的隔离级别,默认值采用 DEFAULT,可选的值在上面介绍过
timeout事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly指定事务是否为只读事务,默认值为 false。
rollbackFor用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。

##4.1、 Spring事务的传播行为

REQUIRED:如果当前存在事务,则方法在该事务中执行;如果当前没有事务,则创建一个新的事务。
SUPPORTS:如果当前存在事务,则方法在该事务中执行;如果当前没有事务,则以非事务的方式执行。
MANDATORY:方法必须在一个已存在的事务中执行,否则将抛出异常。
REQUIRES_NEW:创建一个新的事务,并挂起当前事务(如果有的话)。
NOT_SUPPORTED:以非事务的方式执行方法,如果当前存在事务,则挂起该事务。
NEVER:以非事务的方式执行方法,如果当前存在事务,则抛出异常。
NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则表现行为类似于 REQUIRED。

REQUIRED:如果当前存在事务的解释就是调用method2的主体是否存在事务

@Transactional
public void method1() {
    // 事务处理逻辑
    method2();
}

@Transactional(propagation = Propagation.REQUIRED)
public void method2() {
    // 事务处理逻辑
}

4.3、 Spring事务实现原理

@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。

如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用被@Transactional 注解的 public 方法的时候,实际调用的是,TransactionInterceptor 类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务。
在invoke方法里面实现目标方法的调用 以及开启事务回滚事务的处理
具体来说什么时候事务会回滚还是取决于数据库

4.4、Spring中事务失效的场景

异常捕获处理
对于可能抛出的异常在代码中进行了捕获,就会导致事务失效,就可能不会回滚
解决办法还是需要在catch将异常再次抛出去
抛出的是检查异常
因为Spring默认只会回滚检查异常
解决办法可以在注解中加入参数,@Transactional(rollbackFor=Exception.class)
非public方法

五、SpringBoot的自动装配

在这里插入图片描述

5.1、使用和不使用SpringBoot在项目上有什么使用区别

1.配置管理

  • 不使用Spring Boot:在传统的Java项目中,需要手动配置和管理各种框架和组件的配置文件,如Spring配置文件、数据库配置文件等。
  • 使用Spring Boot:Spring Boot提供了自动配置的特性,它可以根据项目的依赖和约定,自动配置大部分常见的框架和组件,简化了配置的过程。同时,Spring Boot还提供了一种集中式的配置方式,使用application.properties或application.yml文件来集中管理配置,灵活且易于维护。

2.项目启动方式

  • 不使用Spring Boot:在传统的Java项目中,需要手动编写启动类或使用外部的web容器来启动项目。
  • 使用Spring Boot:Spring Boot内置了一个嵌入式的web服务器(如Tomcat、Jetty),可以直接通过运行主类的方式来启动Spring Boot项目,无需依赖外部的web容器。

3.依赖管理

  • 不使用Spring Boot:在传统的Java项目中,需要手动管理和解决各个框架和组件的版本兼容性,手动引入各个框架和组件的依赖。
  • 使用Spring Boot:Spring Boot提供了一系列的“Starter”依赖,用于集成和自动配置常用的框架和组件。只需引入相应的starter依赖,Spring Boot将自动解决版本兼容性和自动配置相关的依赖。

4.项目部署

  • 不使用Spring Boot:在传统的Java项目中,需要将依赖的框架和组件打包成WAR或JAR文件,并且手动配置和管理部署环境。
  • 使用Spring Boot:Spring Boot项目可以直接打包成可执行的JAR文件,包含所有的依赖和配置文件,简化了项目的部署过程。可以通过java -jar命令启动项目,也可以与Docker等容器技术结合使用,方便部署和扩展。

静态资源访问
需要引用大量的js css 图片等静态资源
可以在resource目录下创建static放图片,通过路径.图片就能访问到图片

基于你引入的依赖jar包,对SpringBoot应用进行自动装配
为SpringBoot框架的开箱即用提供了基础支撑、

5.2、SpringBoot自动装配的实例

比如 对于Redis的自动装配
引入依赖 然后配置连接到Redis服务器 然后就可以直接自动装配RedisTemplate进行使用了

SpringBoot的启动流程(简化版)
在这里插入图片描述
在这里插入图片描述
第三步介绍
processConfigurationClasses方法
在这里插入图片描述
介绍parse方法
在这里插入图片描述
加载配置类的流程
从源配置类通过Parse方法不断递归的处理@ComponentScan和@Import注解,不断地去遍历新的配置类,直到没有新的配置类
处理每个配置类,将配置类本身注册到IOC容器中,处理配置类中的@Bean方法将其返回类型注册到IOC容器中
处理通过@Import导入的ImportBeanDefinitionRegistrar
在这里插入图片描述

@ComponentScan
在这里插入图片描述
@Import
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/90ecdd604f1340d2a0e306c11a1f1e76.png
@Import导入接口ImportBeanDefinitionRegistrar实现类 (利用该特性我们可以给IOC容器动态的导入多个BeanDefinition)

SpringBoot自动配置的原理剖析
在这里插入图片描述
从@SpringBootApplication源码的注解

在这里插入图片描述
结构图
在这里插入图片描述
@SpringBootApplication 修饰的类,也会被@Configuration 间接修饰,即“源配置类
SpringBoot 框架会对“源配置类”所在的package 进行组件扫描(Component scan)
SpringBoot 框架最终会导入 AutoConfigurationlmportSelector 来实现自动配置

问题:如何实现类AutoConfigurationImportSelector
AutoConfigurationImportSelector应该如何实现,才能优雅的发现classpath中jar包的自动配置类(用户只需要引用jar包,jar包中有哪些自动配置类,类名是什么等信息用户不用关心)

使用
SpringFactories 机制
√ Java SPI 机制的延伸和扩展
Spring 框架的基础机制,在Spring以及SpringBoot源码中到处可见可以基于它来实现SpringBoot的自动配置功能
核心逻辑是从 classpath 中读取到所有 Jar 包中的配置文件 META-IF/spring.factories然后根据指定的 key 从配置文件中解析出对应的 value 值

在这里插入图片描述
getAutoConfigurationEntry方法是自动配置的入口,方法逻辑如下
在这里插入图片描述

在这里插入图片描述
总结
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/04c4e95db3034ae18155fdb1dc69d132.png在这里插入图片描述

六、SpringMVC的执行流程

前后端分离阶段
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b887d3d4d45347dc883edceffed452b8.png在这里插入图片描述
Spring事务失效的场景
在思维导图中补充 或者是看在b站的这个java面试视频

6.1、Spring MVC 的核心组件有哪些

DispatcherServlet:核心的中央处理器,负责接收请求、分发,并给予客户端响应。

HandlerMapping:处理器映射器,根据 URL 去匹配查找能处理的

HandlerAdapter:处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的

Handler:请求处理器,处理实际请求的处理器。

SpringMVC

灵活的URL映射:可以将URL请求映射到对应的控制器处理方法,支持多种URL映射模式。
请求参数绑定:可以将请求参数自动绑定到控制器方法的参数中,简化参数的获取和处理。
数据验证:提供了数据验证机制,可以通过注解和验证器对请求数据进行验证和校验。
视图解析与渲染:支持多种视图解析器,可以根据请求的结果选择不同的视图进行渲染,如JSP、Thymeleaf、Freemarker等。
拦截器:提供了拦截器机制,可以在请求处理前后执行一些共享的预处理和后处理逻辑。
文件上传:支持文件上传功能,可以方便地处理文件上传的请求和处理。
异常处理:提供了全局的异常处理机制,可以统一处理应用程序中的异常,返回适当的错误页或错误信息。

基于原生的Servlet 通过前端控制器DispatcherServlet对请求和响应进行统一处理

如何解决 get 和 post 乱码问题?
解决post请求乱码问题:在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf­8;

过滤器和拦截器的区别

过滤器在Servlet容器中,如Tomcat、Jetty等,在请求到达Servlet之前执行预处理操作,然后在响应返回给客户端之前执行后处理操作。而拦截器则是在Spring MVC框架中,在请求被Controller处理之前和之后进行拦截处理。

过滤器对应用的所有资源产生影响
拦截器则是基于Bean的方式,可以对指定的Controller、方法或者路径进行拦截。

过滤器一般用于请求的预处理、响应的后处理、字符编码转换、请求的过滤等。拦截器除了提供类似过滤器的功能外,还可以在请求处理之前,通过HandlerInterceptor接口的preHandle方法进行权限验证、日志记录、数据绑定等操作

cookie和Session的区别

要将一个第三方的类配成为Bean有哪些方式?

第三方类由于无法更改不能加上@Conponent注解
所以只能在使用时操作@Bean(在返回的方法使用)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/651579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

452. 用最少数量的箭引爆气球(中等)

452. 用最少数量的箭引爆气球 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;452. 用最少数量的箭引爆气球 2.详细题解 引爆所有气球&#xff0c;弓箭数要最少&#xff0c;那么每支弓箭尽量多的引爆气球&#xff0c;采用贪心策略。对于…

基于小波熵阈值的心电信号R波检测算法(MATLAB)

心脏兴奋电活动过程可由心电信号(ECG)来反映&#xff0c;心电信号也是医学上对心血管疾病诊断的重要科学依据。心电信号具有一定的随机性且一般情况下十分微弱&#xff0c;在信号采集、放大及变换过程中&#xff0c;心电信号容易受到人体呼吸及检测仪器等因素影响&#xff0c;从…

在ARM开发板上,栈大小设置为2MB(常用设置)里面存放的数据

系列文章目录 在ARM开发板上&#xff0c;栈大小设置为2MB&#xff08;常用设置&#xff09;里面存放的数据 在ARM开发板上&#xff0c;栈大小设置为2MB&#xff08;常用设置&#xff09;里面存放的数据 系列文章目录 在ARM开发板上&#xff0c;栈&#xff08;Stack&#xff09;…

linux下cp和mv命令显示进度条

1.查看当前系统下coreutils工具包的版本号&#xff1a; [rootk8s-master ~]# rpm -qa | grep -w coreutils coreutils-8.22-24.el7_9.2.x86_64当前版本为8.22。 因为cp 和 mv 命令由 coreutils 软件包提供&#xff0c;所以需要重新下载 coreutils 软件包配置补丁 2.下载core…

148.栈与队列:前K个高频元素(力扣)

代码解决 class Solution { public:// 自定义比较类&#xff0c;用于优先队列&#xff08;小顶堆&#xff09;class mycomparison{public:// 重载操作符&#xff0c;用于比较两个pair&#xff0c;基于pair的第二个值&#xff08;频率&#xff09;bool operator()(const pair&l…

网页图片加载慢的求解指南

网页/图片加载慢的求解指南 一、前言与问题描述 今天刚换上华为的HUAWEI AX3 Pro New&#xff0c;连上WIFI后测速虽然比平时慢&#xff0c;但是也不算太离谱&#xff0c;如下图所示&#xff1a; 估计读者们有也和作者一样&#xff0c;还没意识到事情的严重性&#x1f601;。 …

UE_地编教程_创建地形洞材质

个人学习笔记&#xff0c;不喜勿喷。侵权立删&#xff01; 使用地形洞材质来遮罩地形上特定位置的可视性和碰撞。如要在山脉侧面创建进入洞穴的入口&#xff0c;此操作将非常有用。可使用地形材质和地形洞材质的相同材质&#xff0c;但注意&#xff1a;对比不使用不透明蒙版的…

基于Cloudflare/CloudDNS/GitHub使用免费域名部署NewBing的AI服务

部署前准备&#xff1a; Cloudflare 账号 https://dash.cloudflare.com/login CloudDNS 账号 https://www.cloudns.net/ GitHub 账号 https://github.com/Harry-zklcdc/go-proxy-bingai Cloudflare 部署 Worker CloudDNS 获取免费二级域名 GitHub New Bing Ai 项目 https://git…

Linux系统硬盘分区

文章目录 一、硬盘和分区1.1 硬盘的概念1.2 硬盘分区的类别1.3 硬盘分区的方式1.3.1 MBR分区1.3.2 GPT分区 1.4 硬盘分区的意义1.4.1 分区的作用1.4.2 分区的缺点 二、如何建立分区2.1 分区命令2.1.1 fdisk命令2.1.2 gdisk命令 2.2 建立分区2.2.1 建立MBR分区建立主分区建立扩展…

电脑如何在网页上下载视频 浏览器如何下载网页视频

对于现代职场人士而言&#xff0c;在日常生活中难免需要下载各种短视频&#xff0c;IDM下载加速器可以轻松获取抖音、快手等平台的无水印短视频文件。 Internet Download Manager&#xff0c;简称IDM。功能强大的网络下载器。您不需要多余的操作&#xff0c;IDM 能捕获您的下载…

实战

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 实战一&#xff1a;模拟支付宝蚂蚁森林的能量产生过程 支付宝的蚂蚁森林通过日常的走步、生活缴费、线下支付、网络购票、共享单车等低碳、环保行为…

行为设计模式之策略模式

文章目录 概述原理结构图 代码实现小结 概述 策略模式(strategy pattern)的原始定义是&#xff1a;定义一系列算法&#xff0c;将每一个算法封装起来&#xff0c;并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。 在软件开发中也会遇到相似的情况&…

【Lexus.4】Executive Sedan——Dismantling Follow-up

文章目录 【碰撞测试】前后防撞钢梁偏置碰撞A/B/C柱&#xff0c;边梁抗拉、屈服强度 【底盘】平整度护板&#xff08;发动机&#xff0c;底盘&#xff09;前副车架结构前悬架形式后悬架形式与材质簧下质量 【发动机】【轮上马力】【零部件供应商】 来自2021《懂车大爆炸》——是…

操作系统课程实验1-进程调度模拟实验

操作系统课程实验1-进程调度模拟实验 一、实验介绍 1.1 实验目的 本实验模拟在单处理机环境下的处理机调度&#xff0c;帮助理解进程调度的概念&#xff0c;深入了解进程控制块的功能&#xff0c;以及进程的创建、撤销和进程各个状态间的转换过程。 1.2 实验内容 进程调度算…

md是什么?如何打开md类型的文件?假如使用Typora打开,如何免费激活Typora?

md是什么&#xff1f;如何打开md类型的文件 前言一、md是什么简介常见打开md类型文件的方法使用文本编辑器使用专用Markdown编辑器使用在线Markdown编辑器在浏览器中安装插件打开 二、下载安装Typora三、免费激活Typora激活Typora关闭软件每次启动时的已激活弹窗去除软件左下角…

动手学深度学习4.6 暂退法-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;丢弃法_哔哩哔哩_bilibili 本节教材地址&#xff1a;4.6. 暂退法&#xff08;Dropout&#xff09;…

NDIS驱动程序堆栈

NDIS 6.0 引入了暂停和重启驱动程序堆栈的功能。 若要支持 NDIS 6.0 提供的堆栈管理功能&#xff0c;必须重写旧版驱动程序。 NDIS 6.0 还引入了 NDIS Filter驱动程序。 Filter驱动程序可以监视和修改协议驱动程序与微型端口驱动程序之间的交互。 与 NDIS 5 相比&#xff0c;F…

188M2传奇BLUEM2引擎源码开源版附带编译教程2024最新开源

2024最新开源188M2传奇BLUEM2引擎源码开源2版最初开源版本附带编译教程 源码下载地址&#xff1a;极速云 如果需要优惠可以选择第一版最初开源188M2传奇BLUEM2引擎源码开源1版最初开源版本附带编译教程2024最新开源

vue2的方法与监听

vue2的方法 不可以使用箭头函数 <template> <div><div>{{sum2()}}</div><button click"add">add</button> </div></template><script> export default {data(){return{name:"张三",num:20,num2:3…

AI分析SP和pk进行sk分析

SP原始表行标题代表题目序号&#xff0c;列代表学生&#xff0c;如果学生答对题目为1&#xff0c;否则为0。问题知识点矩阵这个文件横轴代表每个知识点&#xff0c;列标题代表每个题目序号&#xff0c;如果题目包含这个知识点则该处值为1。通过两个文件判断学生对于每个知识点的…