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

news/2024/7/14 19:04:16/文章来源:https://blog.csdn.net/weixin_64618264/article/details/138704757

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使用
  • 四、Spring事务
  • 4.1、 Spring事务的传播行为
    • 4.2、 Spring事务实现原理
    • 4.4、Spring事务失效的场景
  • 五、SpringBoot的自动装配
    • 5.1、使用和不使用SpringBoot在项目上有什么使用区别
    • 5.2、SpringBoot自动装配原理
  • 六、SpringMVC的执行流程
    • 6.1、Spring MVC 的核心组件有哪些
    • 6.2、SpringMVC能干什么
    • 6.3、如何解决 get 和 post 乱码问题?
    • 6.3、过滤器和拦截器的区别
    • 6.4、要将一个第三方的类配成为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对象的属性设置,可以实现这些接口就能拿到这些参数,让 Bean 对其所属的容器或环境有意识(Awareness)比如BeanNameAware:允许 Bean 获取到自己在容器中的名称(Bean 的 ID)。通过实现该接口,Bean 可以在初始化过程中获知自己在容器中的名称,以及对这个名称进行一些操作)

初始化
初始化示例
通过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:单例模式,即每个容器中只存在一个 Bean 实例。默认情况下,Spring 的 Bean 是单例的,即在容器启动时就创建好了,并在整个应用程序的生命周期中共享。prototype:原型模式,即每次从容器中获取 Bean 时都会创建一个新的实例。每次获取 Bean 都会返回一个新的对象,这意味着 Bean 对象不会被共享。request:针对每一次 HTTP 请求创建一个新的 Bean 实例。每个 HTTP 请求都会创建一个新的 Bean 实例,并且在当前请求结束后销毁。session:针对每一次 HTTP 会话创建一个新的 Bean 实例。每个 HTTP 会话都会创建一个新的 Bean 实例,并且在当前会话结束后销毁。globalSession:针对全局 HTTP 会话(通常只在基于 Portlet 的 Web 应用中可用)创建一个新的 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的生命周期

底层实现
也就跟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{@Overridepublic void pay() {System.out.println("pay支付");}@Overridepublic void callback() {System.out.println("支付回调");}
}
代理类:public class StaticPayServiceImpl implements PayService{private PayService payService;public void StaticPayServiceImpl(PayService payService){this.payService = payService;}@Overridepublic void pay() {System.out.println("支付前增强一下");payService.pay();System.out.println("支付后增强一下");}@Overridepublic 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方法中,它是在调用代理对象的方法时被调用的。在该方法中可以写需要添加的操作,然后通过反射调用了被代理对象的相应方法,并将结果返回。
对于目标方法是通过反射来调用的而Cglib是直接调用父类对应的方法

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*/@Overridepublic 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;}
}

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 编程语言来定义切面和切入点,并通过织入器将切面逻辑织入到目标对象的字节码中。

四、Spring事务

如果事务设置为只读属性
@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.2、 Spring事务实现原理

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

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

4.4、Spring事务失效的场景

异常捕获处理,自己处理了异常,没有抛出,解决:手动抛出抛出检查异常,
配置rollbackFor属性为Exception(回滚时就能处理检查异常)
非public方法导致的事务失效,改为public

五、SpringBoot的自动装配

在Spring Boot项目中的引导类上有一个注解**@SpringBootApplication**,这个注解是对三个注解进行了封装,分别是:
@SpringBootConfiguration
@@EnableAutoConfiguration
@ComponentScan
其中**@EnableAutoConfiguration是实现自动化配置的核心注解。该注解通过@|mport注解导入对应的配置选择器。内部就是读取了该项目和该项目引用的Jar包的的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。 在这些配置类中所定义的Bean会根据条件注解所指定的**条件来决定是否需要将其导入到Spring容器中。
条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的cass文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。

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自动装配原理

SpringBoot的启动流程(简化版)
在Springboot配置类中是有一个run方法

package com.hmdp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan("com.hmdp.mapper")
@SpringBootApplication
public class HmDianPingApplication {public static void main(String[] args) {SpringApplication.run(HmDianPingApplication.class, args);}}
首先创建IOC容器,然后加载源配置类(源配置类就是使用@SpringBootApplication所修饰的类),接下来SpringBoot会自动找到所有的配置类

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

在这里插入图片描述

六、SpringMVC的执行流程

对于前后端分离
1、用户发送出请求到前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HanderMapping(处理器映射器)
HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet.
④ DispatcherServlet调用HandlerAdapter(处理器适配器)
⑤ HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
方法上添加了@ResponseBody
⑦ 通过HttpMessageConverter来返回结果转换为JSON并响应

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

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

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

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

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

6.2、SpringMVC能干什么

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

6.3、如何解决 get 和 post 乱码问题?

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

6.3、过滤器和拦截器的区别

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

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

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

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

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

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

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

相关文章

扔掉 MacBook,挑战带OrangePi出差!

背景 由于工作需要&#xff0c;博主经常会到各大企业的自建机房中私有化部署公司的软件产品。 在某些企业自建机房中&#xff0c;有时给到全新的机器&#xff0c;没有基础环境&#xff0c;甚至有的还无法互联网&#xff0c;而且因为近几年CentOS的停止更新&#xff0c;服务器…

【Postman接口测试】第二节.Postman界面功能介绍(上)

文章目录 前言一、Postman前言介绍二、Postman界面导航说明三、使用Postman发送第一个请求四、Postman 基础功能介绍 4.1 常见类型的接口请求 4.1.1 查询参数的接口请求 4.1.2 表单类型的接口请求 4.1.3 上传文件的表单请求 4.1.4 JSON 类…

服务器主机托管一站式托管服务有哪些?

服务器主机托管一站式托管服务&#xff0c;作为现代企业信息化建设的重要一环&#xff0c;为企业提供了一种高效、安全、可靠的服务器运行环境。下面&#xff0c;我们将从多个方面详细介绍这一服务的内容。 一、硬件与基础设施 服务器主机托管服务首先涵盖了服务器硬件和网络基…

【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化+完美使用

模版介绍 【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化完美使用 腾讯官方出品discuz论坛DIY的后台设置&#xff0c;功能齐全&#xff0c;论坛功能不亚于葫芦侠&#xff0c;自定义马甲&#xff0c;自定义认证&#xff0c;自定义广告&#xff0c;完全可以打造出自己想…

27快28了,想转行JAVA或者大数据,还来得及吗?

转行到JAVA或者大数据领域&#xff0c;27岁快28岁的年龄完全来得及。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&#xff0c;我在后台发给你。…

Java解析JSON并修改属性值:从JSON到JsonObject的逐层解析

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在Java中&#xff0c;可以使用各种库来解析和操作JSON数据。其中&#xff0c;Gson和Jackson是两个非常流行且功能强大的库。在这篇文章中&#xff0c;将使用Gson库来解析给定的JSON字符串&#xff0c;修改operationB…

面试:eureka、nacos、consul的区别

配置中心 配置中心eureka不支持nacos支持 用起来简单&#xff0c;符合springBoot的命名风格&#xff0c;支持动态刷新consul支持 但用起来偏麻烦&#xff0c;不太符合springBoot框架的命名风格&#xff0c;支持动态刷新 注册中心

使用Python发送电子邮件

大家好&#xff0c;当我们需要迅速、方便地与他人沟通时&#xff0c;电子邮件是无疑是一种不可或缺的通信工具。无论是在个人生活中还是工作场合&#xff0c;电子邮件都是我们日常生活中的重要组成部分。它不仅能够传递文字信息&#xff0c;还可以发送附件、链接和嵌入式多媒体…

Ubuntu 如何根据NVIDIA显卡型号确定对应的显卡驱动版本并安装

目录 一、查询推荐安装的驱动版本 二、安装推荐版本的驱动 1. 通过终端安装&#xff0c;只安装 nvidia 驱动&#xff08;亲测可用&#xff01;&#xff09; 2. 通过 software & Updates 安装&#xff0c;安装 nvidia 驱动。 三、查询能安装的最新的显卡驱动版本 1. 方…

贪心算法[1]

首先用最最最经典的部分背包问题来引入贪心的思想。 由题意可知我们需要挑选出价值最大的物品放入背包&#xff0c;价值即单位价值。 我们需要计算出每一堆金币中单位价值。金币的属性涉及两个特征&#xff0c;重量和价值。 所以我们使用结构体。 上代码。 #include <i…

Github 2024-05-29 C开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-29统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C++项目3PHP项目1PHP:流行的Web开发脚本语言 创建周期:4710 天开发语言:C, PHP协议类型:OtherStar数量:37340 个Fork数量:7657 次…

基于python flask +pyecharts实现的气象数据可视化分析大屏

背景 气象数据可视化分析大屏基于Python Flask和Pyecharts技术&#xff0c;旨在通过图表展示气象数据的分析结果&#xff0c;提供直观的数据展示和分析功能。在当今信息化时代&#xff0c;气象数据的准确性和实时性对各行业具有重要意义。通过搭建气象数据可视化分析大屏&…

苹果手机屏幕录制在哪里?快速上手教程来啦!

随着智能手机的普及&#xff0c;手机录制屏幕功能变得越来越受欢迎。尤其是在苹果手机上&#xff0c;内置的屏幕录制功能非常方便&#xff0c;可以轻松录制手机操作过程、游戏过程等。本文将为您介绍苹果手机屏幕录制在哪里&#xff0c;帮助大家轻松掌握屏幕录制的技巧。 苹果手…

汽车制造业安全有效的设计图纸文件外发系统是什么样的?

在汽车制造的世界里&#xff0c;那些设计图不仅仅是公司智慧的闪光点&#xff0c;更是它们竞争的秘密武器。但问题来了&#xff0c;当公司需要和供应商、合作伙伴频繁交换数据时&#xff0c;怎样安全又高效地发送这些设计图&#xff0c;就成了一个头疼的问题。这篇文章会深挖一…

Vue进阶之Vue项目实战(四)

Vue项目实战 出码功能知识介绍渲染器性能调优使用 vue devtools 进行分析使用“渲染”进行分析判断打包构建的产物是否符合预期安装插件使用位置使用过程使用lighthouse分析页面加载情况使用performance分析页面加载情况应用自动化部署与发布CI/CD常见的CI/CD服务出码功能 出码…

科技引领未来:高速公路可视化

高速公路可视化监控系统利用实时视频、传感器数据和大数据分析&#xff0c;通过图扑 HT 可视化展示交通流量、车速、事故和路况信息。交通管理人员可以实时监控、快速响应突发事件&#xff0c;并优化交通信号和指挥方案。这一系统不仅提高了道路安全性和车辆通行效率&#xff0…

1806 jsp防疫物资销售管理系统 Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 防疫物资销售管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.…

香橙派OrangePi AIpro,助力国产AIoT迈向新的台阶!

前言&#xff1a;很高兴受邀CSDN与OrangePi官方组织的测评活动&#xff0c;本次测评是一块基于AI边缘计算的香橙派开发板OrangePi AIpro。这是 香橙派 联合 华为昇腾 合作精心打造的新一代边缘AI计算产品&#xff0c;于2023年12月初发布&#xff0c;提供 8/20TOPS澎湃算力[1]&a…

干货 | 学习网络安全,推荐6个常用的安全知识在线手册(非常详细)零基础入门到精通,收藏这一篇就够了

排名不分先后&#xff0c;欢迎各位小伙伴下方留言评论补充 **VulDoc ** 包含&#xff1a;IOT安全&#xff0c;Web安全&#xff0c;系统安全 地址&#xff1a;http://47.112.148.3:8000/ **滴水逆向学习笔记 ** 包含 汇编 C C Win32 MFC 网络编程 数据库 数据…

Python散点图矩阵代码模版

本文分享Python seaborn实现散点图矩阵代码模版&#xff0c;节选自&#x1f449;嫌Matplotlib繁琐&#xff1f;试试Seaborn&#xff01; 散点图矩阵&#xff08;scatterplot matrix&#xff09;展示原始数据中所有变量两两之间关系&#xff0c;可以规避单一统计指标的偏差&…