关注微信公众号:两行code,分享后端技术、算法、面经、以及后端场景问题~~
1.IOC 是什么,什么是 Spring IOC 容器?
IOC 是一种设计思想。 **IOC 容器是 Spring 用来实现 IOC 的载体, IOC 容器在某种程度上就是个Map(key,value),key是 name 属性,value 是对应的对象。**容器创建 Bean 对象, 使用依赖注入来管理对象之间的相互依赖关系,配置它们并管理它们的完整生命周期,很大程度上简化应用的开发,降低了耦合度。
容器通过读取提供的配置,比如 XML,注解或 Java 代码来接收对象信息进行实例化,配置和组装。
Spring IOC(Spring Inversion of Control)容器是 Spring 框架中的一个核心模块,用于管理和控制应用程序中的对象(也称为 bean)之间的依赖关系。Spring IOC 容器负责创建、配置和管理这些 bean,从而实现了IOC的原则。
Spring IOC 容器通过以下两种方式实现:
- Bean的定义文件(XML配置):您可以通过XML配置文件来定义应用程序中的 bean,包括它们的类型、属性和依赖关系。Spring IOC 容器会根据这些配置文件来实例化和组装 bean。
- 基于注解的配置:除了XML配置,Spring 也支持使用注解来标识和配置 bean。通过在类上使用注解,您可以告诉 Spring 容器如何创建和管理 bean
2.IOC 的实现机制/初始化流程
主要实现原理就是工厂模式加反射机制。
调用 refresh() 方法:
- 刷新准备,设置开始时间,状态, 初始化占位符等操作
- 获取内部的 BeanFactory,Spring 容器在启动的时候,先会保存所有注册进来的 Bean 的定义信息, 注册到 BeanFactory 中。
- 设置 BeanFactory 的类加载器和后置处理器,添加几个 BeanPostProcessor,手动注册默认的环境 bean
- 为子类提供后置处理 BeanFactory 的扩展能力,初始化上下文之前,可以复写 postProcessBeanFactory这个方法
- 执行 Context 中注册的 BeanFactory 后置处理器,对 SpringBoot 来说,这一步会进行 BeanDefintion 的解析
- 按优先级在 BeanFactory 注册 Bean 的后置处理器,这是在 Bean 初始化前后执行的方法
- 初始化国际化,事件广播器的模块,注册事件监听器
- 然后 Spring容器就会创建这些非延迟加载的单例 Bean
- 最后广播事件,ApplicationContext 初始化/刷新完成
3.什么是 Spring Bean
在Spring框架中,"Bean"是一个重要的概念,它表示由Spring IoC容器管理的对象。Bean可以是应用程序中的任何对象,包括服务、数据访问对象、控制器、实体等等。Spring IoC容器负责创建、配置和管理这些Bean的生命周期。
4.Spring Bean 的作用域有哪些?
- singleton(单例):
-
- 默认作用域,容器中只存在一个Bean实例。
- 当容器初始化时,会创建该Bean的实例,并在整个应用程序生命周期内共享。
- 所有对该Bean的请求都返回相同的实例引用。
- 适用于无状态的Bean,例如服务、工具类,以减少资源消耗和提高性能。
- prototype(原型):
-
- 每次请求都创建一个新的Bean实例。
- 容器不会缓存原型Bean的实例,每次都会创建新的Bean。
- 适用于有状态的Bean或需要频繁重建的Bean,每次请求都获取一个独立的实例。
- request(请求):
-
- 每个HTTP请求都创建一个新的Bean实例。
- 在Web应用中,每个HTTP请求都会创建一个新的Bean实例,该Bean仅在该请求的处理过程中存在。
- 适用于Web应用中需要请求级别状态的Bean。
- session(会话):
-
- 每个HTTP会话(session)都创建一个新的Bean实例。
- 在Web应用中,每个用户会话都会创建一个新的Bean实例,该Bean在整个会话期间存在。
- 适用于Web应用中需要会话级别状态的Bean。
- application(应用程序):
-
- 整个Web应用中共享一个Bean实例。
- 在Web应用中,该Bean在整个应用程序生命周期内存在,所有用户共享同一个实例。
- 适用于全局资源的共享,例如共享的配置信息。
- websocket(WebSocket):
-
- 每个WebSocket会话都创建一个新的Bean实例。
- 用于WebSocket应用中,每个WebSocket会话都会创建一个新的Bean实例,该Bean在WebSocket会话期间存在。
5.Spring Bean 的生命周期
Spring Bean的生命周期包括以下阶段:
- 实例化:当Spring容器启动时,它会根据配置文件或注解等信息,实例化(创建)Bean对象。Spring提供了多种方式来创建Bean,最常见的方式是使用默认构造函数实例化Bean。
- 设置Bean属性:一旦Bean对象被实例化,Spring容器会将Bean的属性设置为配置文件中定义的值,或者通过自动注入等方式将依赖注入到Bean中。
- Bean的初始化:在Bean的所有属性都被设置之后,Spring容器会调用Bean的初始化方法(如果有的话)。初始化方法可以通过两种方式来定义:
-
- 使用@Bean注解的initMethod属性
- 实现InitializingBean接口,覆盖afterPropertiesSet()方法
- 这些方法可以用来执行一些初始化任务,例如建立数据库连接、加载配置文件等。
- Bean可用:一旦Bean被初始化,它就可以被应用程序的其他部分使用了。
- 使用Bean:在Bean被初始化后,应用程序可以使用它执行相应的业务逻辑。
- 销毁Bean:当应用程序不再需要Bean时,Spring容器可以销毁它。销毁Bean时,容器会调用Bean的销毁方法(如果有的话)。销毁方法可以通过两种方式来定义:
-
- 使用@Bean注解的destroyMethod属性
- 实现DisposableBean接口,覆盖destroy()方法
- 这些方法可以用来执行一些清理任务,例如关闭数据库连接、释放资源等。
- Bean被销毁:一旦Bean被销毁,它将不再可用,并且将从Spring容器中移除。
6.Spring 自动装配 bean 有哪些方式?
- 自动装配 by Type(按类型自动装配):Spring容器会自动根据属性的数据类型(Type)来匹配依赖的Bean。如果容器中有且仅有一个匹配的Bean,就会将其注入到属性中,如果有多个匹配,Spring会抛出异常,表示不确定性。
@Autowired
private SomeBean someBean;
- 自动装配 by Name(按名称自动装配):Spring容器会根据属性的名称来匹配依赖的Bean。属性的名称要与要注入的Bean的名称一致。
@Autowired
private SomeBean someBean;
- 自动装配 by Qualifier(按限定符自动装配):当有多个同类型的Bean存在时,可以使用@Qualifier注解指定要装配的Bean的名称,以消除歧义。
@Autowired
@Qualifier("specificBean")
private SomeBean someBean;
- 自动装配 by Constructor(通过构造函数自动装配):可以使用构造函数进行自动装配,Spring容器会根据构造函数的参数类型和Bean的类型来匹配依赖。
@Autowired
public SomeService(SomeBean someBean) {
this.someBean = someBean;
}
- 自动装配 by Primary(主要Bean自动装配):使用@Primary注解来标记一个Bean作为首选Bean,当多个同类型的Bean存在时,Spring会优先选择@Primary注解标记的Bean进行装配。
@Component
@Primary
public class PrimaryBean implements SomeBean {
// ...
}
- 自动装配 by No(禁用自动装配):可以使用@Autowired的required属性将自动装配禁用,如果找不到匹配的Bean,则不会抛出异常。
@Autowired(required = false)
private SomeBean someBean;
7.ApplicationContext和BeanFactory有什么区别?
ApplicationContext 和 BeanFactory 是两个核心的Spring容器,它们用于管理和创建Bean,但在功能和用途上有一些重要的区别:
初始化时间:
- BeanFactory是Spring容器的最基本形式,它在初始化时延迟创建Bean,即只有当应用程序首次请求一个Bean时才会创建它。
- ApplicationContext是BeanFactory的子接口,通常在容器启动时就会预加载所有的Bean,提前创建和初始化Bean,因此在第一次请求Bean时,不需要等待Bean的初始化过程。
配置资源加载:
- BeanFactory:它可以从各种外部资源(如XML文件、属性文件等)加载Bean的配置信息。通常需要通过编程方式配置BeanFactory,手动加载配置。
- ApplicationContext:它是一个更高级的容器,可以从多种资源加载配置信息,包括XML文件、Java注解、Java配置类等。它提供了更多的功能,如国际化支持、事件发布、AOP等,通常用于大型应用程序。
Bean生命周期:
- BeanFactory:它仅负责创建和管理Bean,不提供高级功能,如事件处理、AOP等。如果只需要基本的Bean管理功能,可以使用BeanFactory。
- ApplicationContext:它扩展了BeanFactory的功能,提供了更多的企业级功能,如国际化、事件发布、资源加载等。通常更适合中大型企业应用程序。
性能:
- BeanFactory:由于延迟初始化,通常在启动时占用的内存较少,但在第一次请求大量Bean时可能会有一定的性能开销,因为需要动态创建和初始化Bean。
- ApplicationContext:由于预加载所有Bean,它在应用程序启动时可能会占用更多的内存,但在后续请求Bean时性能更高,因为Bean已经初始化完毕。
应用场景:
- BeanFactory:适用于资源受限的环境或需要更精细控制Bean创建和初始化的场景。
- ApplicationContext:适用于大型企业级应用程序,需要更多高级功能和自动配置的场景。
8.什么是循环依赖?怎么解决循环依赖?
Spring Bean的循环依赖是指两个或多个Spring Bean之间相互依赖,形成一个循环引用的情况。这种循环依赖可能发生在Spring容器中,其中一个Bean需要另一个Bean的引用,而同时另一个Bean也需要第一个Bean的引用,形成一个闭环。这种情况可能会导致应用程序无法正常启动,或者在运行时产生不一致的行为。
循环依赖示例:
考虑以下两个简单的Spring Bean:
@Component
public class A {
private B b;
@Autowired
public A(B b) {
this.b = b;
}
}
@Component
public class B {
private A a;
@Autowired
public B(A a) {
this.a = a;
}
}
在这个示例中,Bean A 依赖于Bean B,而Bean B 也依赖于Bean A,形成了一个循环依赖。
Spring框架通过使用三级缓存和"先创建实例,后填充属性"的方式来解决循环依赖问题。以下是Spring如何解决循环依赖的详细过程:
- Bean的注册与创建:
-
- 当Spring容器启动时,它会扫描并注册所有的Bean定义。
- 对于每个Bean,容器会在三级缓存中创建一个占位符,并尝试创建Bean的实例。
- 创建Bean实例(提前曝光):
-
- 在实例化Bean的过程中,如果发现循环依赖,Spring会创建一个尚未完全初始化的Bean实例,并将其存储在一级缓存(singletonObjects)中。这个实例是一个未填充属性的半成品。
- Spring创建这个半成品实例的目的是为了提前曝光,以满足其他Bean对该Bean的依赖。
- 填充属性:
-
- 继续创建Bean的实例,Spring会填充Bean的属性,包括依赖其他Bean的属性。
- 如果发现需要的依赖Bean已经在一级缓存中(之前创建的半成品实例),则将该依赖Bean注入到正在创建的Bean中。
- 循环依赖的处理:
-
- 当Bean A 需要依赖Bean B 时,Spring容器会首先创建半成品的Bean A,并将其放入一级缓存。
- 接着,Spring会创建半成品的Bean B,并发现Bean B 需要依赖 Bean A。此时,Spring会从一级缓存中获取Bean A(半成品)并注入到Bean B 中。
- 最后,Spring会继续初始化完整的Bean A 和 Bean B,分别填充其余的属性。
- Bean实例替换:
-
- 一旦Bean A 和 Bean B 都被完全初始化,它们将分别替换之前在一级缓存中的半成品实例。这意味着一级缓存中现在包含了完整的Bean实例,而不再是半成品。
- Bean的完整初始化意味着所有初始化方法(如@PostConstruct注解的方法)都已调用,属性都已填充。
通过上述机制,Spring能够解决循环依赖问题,同时确保所有Bean都能够在需要时被正确引用。需要注意的是,虽然Spring能够处理大多数情况的循环依赖,但过度复杂的依赖关系仍然可能导致问题,因此在设计应用程序时,应尽量避免复杂的循环依赖关系,以确保应用程序的可维护性和稳定性。
10.Spring中@Autowired和@Resource的区别?
@Autowired 和 @Resource 都是用于依赖注入的注解,主要有如下几个区别:
- 来源:
-
- @Autowired 是 Spring 框架自带的注解,它基于类型(byType)进行依赖注入。
- @Resource 是 Java EE(J2EE)规范提供的注解,通常与 Spring 集成时也可以使用,它基于名称(byName)进行依赖注入。
- 注入规则:
-
- @Autowired 按照变量的数据类型(类型匹配)来查找和注入依赖。
- @Resource 按照变量的名称(名称匹配)来查找和注入依赖。
- 默认情况:
-
- @Autowired 默认按照类型查找依赖,如果找到多个匹配的依赖,会抛出异常;可以与 @Qualifier 注解一起使用,指定要注入的 Bean 的名称。
- @Resource 默认按照名称查找依赖,可以指定 name 属性来指定要注入的 Bean 的名称。
- 兼容性:
-
- @Autowired 是 Spring 的特有注解,在 Spring 环境中使用。
- @Resource 是 Java EE 规范的一部分,可以在其他 Java EE 容器中使用,例如应用于 EJB 或其他 Java EE 技术的组件。
- 可选性:
-
- @Autowired 注解的依赖通常是必须的,如果找不到匹配的 Bean,会引发异常。
- @Resource 注解的依赖通常是可选的,如果找不到匹配的 Bean,它将尝试使用默认名称(变量名)进行查找,如果还找不到,将允许该字段为 null。
AOP
11.什么是 AOP?
AOP(面向切面编程)是一种软件开发方法,它允许开发者在不改变主要业务逻辑的情况下,将横切关注点(cross-cutting concerns)与主要业务逻辑进行分离。横切关注点通常包括日志记录、性能监视、安全性、事务管理等。AOP 的主要目标是提高代码的模块化性、可维护性和可重用性。
12.AOP 的核心原理是什么?
Spring框架中AOP的核心原理是基于代理机制和面向切面编程来实现横切关注点的分离和模块化,以下是Spring框架中AOP的核心原理:
- 代理模式: Spring使用代理模式来实现AOP。在Spring AOP中,目标对象(包含主要业务逻辑)被包装在一个代理对象中。这个代理对象负责管理切面的引入和通知的执行。
- 切面(Aspect): 在Spring AOP中,切面是一个普通的Java类,它包含了通知和切点的定义。通知是横切关注点的具体操作,切点定义了通知应该在何处执行。切面通常使用注解或XML配置来定义。
- 连接点(Join Point): 连接点是在应用程序执行过程中可以插入切面的特定点,通常是方法调用、异常处理或字段访问等。Spring AOP支持方法级别的连接点。
- 通知(Advice): 通知是切面中的具体操作,它定义了在连接点何时、何地以及如何执行横切关注点的代码。Spring AOP支持不同类型的通知,包括前置通知、后置通知、环绕通知、异常通知和最终通知。
- 切点表达式(Pointcut Expression): Spring AOP使用切点表达式来定义切点,这是一种规则或表达式,它指定了在哪些方法上应该应用通知。切点表达式可以基于方法的名称、包名、类名等来指定切点。
- 织入(Weaving): 织入是将切面与目标对象关联的过程。Spring AOP支持多种织入方式,包括编译时织入、类加载时织入和运行时织入。最常见的是运行时织入,其中代理对象在运行时动态创建,将切面引入到目标对象的方法调用中。
13.为什么要引入 AOP?
Java OOP 存在一些局限性:
- 静态化语言:类结构一旦定义,不容易被修改
- 侵入性扩展:通过继承或组合组织新的类结构
通过 AOP 我们可以把一些非业务逻辑的代码(比如安全检查、监控等代码)从业务中抽取出来,以非入侵的方式与原方法进行协同。这样可以使得原方法更专注于业务逻辑,代码接口会更加清晰,便于维护。
14.简述 AOP 中几个比较重要的概念
- 切面(Aspect): 切面是AOP的核心概念之一。它是一个模块化单元,用于封装横切关注点的定义。切面包含了通知和切点的定义。通知定义了在连接点何时、何地以及如何执行横切关注点的代码。切点定义了在何处应该应用通知。切面通常包括多个通知和切点的组合,用于实现不同的横切关注点。
- 通知(Advice): 通知是切面中的具体操作,它定义了在连接点何时、何地以及如何执行横切关注点的代码。根据执行时机,通知可以分为以下几种类型:
-
- 前置通知(Before Advice): 在连接点之前执行,通常用于执行预处理操作,如参数验证。
- 后置通知(After Advice): 在连接点之后执行,通常用于执行清理操作,如资源释放。
- 返回通知(After Returning Advice): 在连接点成功返回后执行,通常用于记录方法返回值或执行后续处理。
- 异常通知(After Throwing Advice): 在连接点抛出异常后执行,通常用于处理异常情况。
- 环绕通知(Around Advice): 在连接点之前和之后执行,可以完全控制连接点的执行,包括是否执行连接点以及如何修改连接点的执行。
- 切点(Pointcut): 切点是切面中定义的条件,它指定了在哪些连接点应该应用通知。切点使用切点表达式来定义,该表达式通常基于方法的名称、包名、类名等来选择连接点。切点确定了通知的作用范围。
- 连接点(Join Point): 连接点是在应用程序执行过程中可以插入切面的特定点,通常是方法调用、异常处理或字段访问等。连接点是切点的具体实例。通知会在连接点处执行。
- 织入(Weaving): 织入是将切面与目标对象关联的过程。它是AOP框架在运行时或编译时将切面引入到应用程序中的方式。织入可以在不同的时机进行,如编译时、加载时或运行时。运行时织入是最常见的,其中代理对象在运行时动态创建,并将切面应用于目标对象的方法调用。
- 引入(Introduction): 引入是AOP的一个概念,允许切面向现有类添加新的方法或字段,而无需修改目标类的代码。引入允许切面在不改变类继承关系的情况下添加额外的功能。
- 目标对象(Target Object): 目标对象是包含主要业务逻辑的类,它将被切面影响。通常,切面在目标对象的方法调用之前或之后执行通知。
15.什么是 AOP 代理?
AOP(Aspect-Oriented Programming)代理是在AOP中使用的一种机制,它是实现横切关注点引入的关键组成部分。AOP代理是一个代理对象,它包含了目标对象(主要业务逻辑)和与之关联的切面(Aspect)。AOP代理在客户端代码与目标对象之间充当了中间人的角色,用于在方法调用前后执行横切关注点的操作。
两种常见的AOP代理类型是:
- JDK动态代理: 基于Java反射机制,使用Java标准库中的java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建代理对象。JDK动态代理只能代理接口,要求目标对象实现接口。
- CGLIB代理: CGLIB(Code Generation Library)代理通过创建目标对象的子类来实现代理。因为它是基于字节码操作的,所以可以代理非接口类型的目标对象。但需要注意的是,CGLIB代理要求目标对象没有被标记为final,否则无法生成代理。
16.请详细说明JDK 动态代理
JDK(Java Development Kit)动态代理是Java标准库提供的一种代理机制,用于创建代理对象,这些代理对象实现了一个或多个接口,并且可以在运行时动态生成。它通常用于代理实现了特定接口的类,实现横切关注点的引入。
- 代理对象的创建: JDK动态代理通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建代理对象。代理对象实现了目标接口,所以客户端可以将代理对象当作目标接口的实例来使用。
- InvocationHandler接口: java.lang.reflect.InvocationHandler是一个函数式接口,通常需要自定义一个类来实现该接口。在这个实现类中,你可以编写代理对象在方法调用前后执行的逻辑。它的核心方法是invoke,接收三个参数:代理对象、方法对象和方法参数,然后返回方法执行的结果。
- 代理对象的创建方式: 使用Proxy类的newProxyInstance方法来创建代理对象。这个方法需要传递三个参数:类加载器、目标接口数组和InvocationHandler实例。例如:
MyInvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class },
handler
);
这里,proxy就是代理对象,它实现了MyInterface接口,handler是自定义的InvocationHandler实例,用于控制代理对象的行为。
- 代理方法的执行: 当客户端调用代理对象的方法时,实际上会触发InvocationHandler的invoke方法。在invoke方法中,你可以编写代码来处理横切关注点的逻辑,例如记录日志、执行额外操作等。然后,invoke方法会调用目标对象的对应方法,并返回结果。
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前执行横切关注点的逻辑
System.out.println("Before method execution");
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 在方法调用后执行横切关注点的逻辑
System.out.println("After method execution");
// 返回方法执行的结果
return result;
}
}
限制条件: JDK动态代理要求目标对象必须实现至少一个接口。此外,它无法代理被标记为final的类和方法,因为final修饰的类和方法无法被继承和重写。
17.请详细说明 CGLIB 动态代理
CGLIB 动态代理则是基于类代理(字节码提升),通过 ASM(Java 字节码的操作和分析框架)将被代理类的 class 文件加载进来,修改其字节码生成一个子类。
- 代理对象的创建: CGLIB动态代理通过生成目标类的子类来创建代理对象。这个子类继承自目标类,并且可以覆盖目标类中的方法以添加代理逻辑。代理对象是目标类的子类的一个实例。
- 代理类的创建方式: CGLIB代理通常需要使用第三方库,例如cglib-nodep。你需要编写一个代理类,这个代理类继承自net.sf.cglib.proxy.MethodInterceptor,然后在其中编写代理逻辑。例如:
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.Enhancer;
public class MyCglibProxy implements MethodInterceptor {
public Object createProxy(Class<?> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, java.lang.reflect.Method method, Object[] args, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
// 在方法调用前执行横切关注点的逻辑
System.out.println("Before method execution");
// 调用目标对象的方法
Object result = methodProxy.invokeSuper(proxy, args);
// 在方法调用后执行横切关注点的逻辑
System.out.println("After method execution");
// 返回方法执行的结果
return result;
}
}
- 代理对象的创建和使用: 使用CGLIB代理时,需要先创建一个Enhancer对象,然后设置目标类和回调对象(即上面的MyCglibProxy),最后调用create方法创建代理对象。代理对象可以像普通对象一样使用,但会触发回调对象的intercept方法来执行横切关注点的逻辑。
MyCglibProxy cglibProxy = new MyCglibProxy();
MyService proxy = (MyService) cglibProxy.createProxy(MyService.class);
proxy.doSomething();
- 代理方法的执行: 当客户端调用代理对象的方法时,CGLIB代理会通过代理类的方法调用触发intercept方法的执行。在intercept方法中,你可以编写代码来处理横切关注点的逻辑,然后调用methodProxy.invokeSuper来调用目标对象的方法。
20.JDK 动态代理和 CGLIB 有什么区别?
代理对象类型:
- JDK动态代理: JDK动态代理是基于接口的代理,它要求目标对象必须实现一个或多个接口。代理对象是通过实现目标接口来创建的。
- CGLIB代理: CGLIB代理可以代理非接口类型的目标对象,它通过继承目标类并生成子类来创建代理对象。这使得CGLIB代理可以代理那些没有实现接口的类。
实现方式:
- JDK动态代理: JDK动态代理是通过Java标准库中的java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现的。代理对象实际上是一个实现了目标接口的匿名内部类。
- CGLIB代理: CGLIB代理是通过字节码操作技术来生成目标类的子类,并在子类中添加方法拦截逻辑。这种方式不需要目标类实现接口,但需要在运行时生成字节码,因此通常比JDK动态代理略慢。
性能:
- JDK动态代理: 由于JDK动态代理基于接口,通常在处理接口代理时性能较好。但对于类代理,性能可能稍逊于CGLIB代理,因为需要进行接口和反射相关的操作。
- CGLIB代理: CGLIB代理通常在性能上略优于JDK动态代理,特别是对于类代理,因为它不需要进行接口和反射相关的操作。
代理对象创建方式:
- JDK动态代理: JDK动态代理是通过Proxy.newProxyInstance方法来创建代理对象,需要传入目标对象的类加载器、接口数组和InvocationHandler实例。
- CGLIB代理: CGLIB代理是通过CGLIB库来创建代理对象,它不需要目标对象实现接口,只需提供目标类即可。
限制条件:
- JDK动态代理: 由于基于接口,JDK动态代理无法代理那些没有实现接口的类。另外,它也无法拦截目标类内部自调用的方法。
- CGLIB代理: CGLIB代理可以代理没有实现接口的类,但无法代理被标记为final的类和方法。
21.Spring AOP 和 AspectJ 有什么关联?
Spring AOP: Spring AOP 是 Spring 框架内置的 AOP 框架,它提供了一种基于代理的轻量级 AOP 解决方案。Spring AOP 主要关注于对 Spring 容器管理的 bean 进行切面编程。它基于代理模式来实现 AOP,通常使用 JDK 动态代理或 CGLIB 来创建代理对象。Spring AOP 提供了对前置通知、后置通知、环绕通知等通知类型的支持,以及通过切点表达式来选择连接点。Spring AOP的主要优势在于它的集成性,可以与 Spring 的依赖注入和事务管理等功能无缝集成。
AspectJ: AspectJ 是一个独立的 AOP 框架,它提供了更强大和灵活的 AOP 功能。AspectJ 使用自定义的编译器或者在运行时织入字节码的方式来实现 AOP。相比于 Spring AOP,AspectJ 更为强大,可以应用于任何 Java 类,不仅限于 Spring 管理的 bean。它支持更多的通知类型和更复杂的切点表达式。AspectJ 还提供了一种静态织入的方式,可以在编译时或类加载时织入切面,而不仅仅是在运行时。
Spring AOP 整合 AspectJ 注解与 Spring IoC 容器,比 AspectJ 的使用更加简单,也支持 API 和 XML 的方式进行使用。不过 Spring AOP 仅支持方法级别的 Pointcut 拦截。
22.Spring AOP 中有哪些 Advice 类型?
前置通知(Before Advice): 前置通知在目标方法调用之前执行。它通常用于执行预处理操作,例如参数验证、日志记录、权限检查等。前置通知可以通过@Before注解或XML配置来定义。
后置通知(After Returning Advice): 后置通知在目标方法正常返回后执行。它通常用于执行清理操作或记录返回值等。后置通知可以通过@AfterReturning注解或XML配置来定义。
环绕通知(Around Advice): 环绕通知是最灵活的一种Advice类型,它可以在目标方法调用前后自定义处理逻辑。它可以完全控制方法的执行,包括是否执行目标方法以及如何修改方法的参数和返回值。环绕通知通常用于实现缓存、性能监控等复杂的横切关注点。环绕通知可以通过@Around注解或XML配置来定义。
异常通知(After Throwing Advice): 异常通知在目标方法抛出异常后执行。它通常用于处理异常情况、进行错误日志记录或异常恢复操作。异常通知可以通过@AfterThrowing注解或XML配置来定义。
最终通知(After (finally) Advice): 最终通知无论目标方法是否成功执行,都会执行。它通常用于执行清理操作,无论目标方法是否抛出异常。最终通知可以通过@After注解或XML配置来定义。
Spring 事务
23.Spring 管理事务的方式有几种?
- 编程式事务管理: 这是一种通过编写代码来管理事务的方式。您可以在方法内部使用Spring的PlatformTransactionManager接口以及TransactionDefinition来手动开始、提交或回滚事务。这种方式提供了最大的灵活性,但通常需要更多的代码。
- 基于XML配置的声明式事务管理: 这是一种通过XML配置来声明事务规则的方式。您可以在Spring的配置文件中定义事务管理器(例如DataSourceTransactionManager)以及事务通知(例如<tx:advice>元素),然后将它们应用到特定的方法或类上。这种方式提供了更好的可维护性和可配置性,而不需要修改代码。
- 基于注解的声明式事务管理: 使用Spring的注解,例如@Transactional,可以在方法级别或类级别上声明事务规则。这种方式与XML配置方式类似,但更加方便,并将事务声明与业务逻辑代码分离。
24.事务注解@Transactional实现机制
当您在一个方法上添加@Transactional注解时,Spring会在运行时动态生成一个代理对象,该代理对象包装了目标对象(包含@Transactional注解的方法所在的类)。这个代理对象的主要任务是截获方法的调用,以便在方法执行前后添加事务管理逻辑。
在生成代理对象时,Spring会创建一个事务切面(Transaction Aspect)。事务切面是一个横切关注点,它包含了事务管理的核心逻辑,如事务的开启、提交、回滚等。这个切面通过AOP的通知(Advice)机制来实现。
当客户端代码调用带有@Transactional注解的方法时,代理对象首先检查当前线程是否已经存在一个事务上下文(Transaction Context)。如果不存在,代理对象会使用配置的事务管理器来开启一个新的事务。然后,代理对象执行目标方法,目标方法内的数据库操作都会在这个新的事务中进行。
在目标方法执行完成后,代理对象会根据方法的执行情况来决定是提交事务还是回滚事务。如果方法正常完成,事务会被提交,否则,如果方法抛出了异常,事务会被回滚。这确保了事务的一致性和完整性。
@Transactional注解还允许配置各种事务属性,例如传播行为、隔离级别、超时等,以满足不同场景下的事务需求。这些属性可以在注解中指定,Spring会根据配置来管理事务。
25.Spring 事务的传播行为
在Spring中,事务的传播行为是指在一个方法已经运行在一个事务上下文中时,另一个方法被调用时如何处理事务。Spring中常见的事务传播行为有如下几种:
- REQUIRED(默认):
-
- 如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务。
- REQUIRED 是最常见的传播行为,也是 Spring 默认的传播行为。
- SUPPORTS:
-
- 如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务方式执行。
- 如果要求方法始终在事务内执行,但允许它在没有事务的情况下执行,可以使用 SUPPORTS 传播行为。
- MANDATORY:
-
- 要求方法在一个事务内执行,如果当前没有事务,则抛出异常。
- 如果方法需要在已存在的事务内执行,MANDATORY 传播行为可以确保这一点。
- REQUIRES_NEW:
-
- 无论当前是否存在事务,都会创建一个新的事务。如果当前存在事务,它将被挂起。
- REQUIRES_NEW 传播行为允许方法始终在自己的事务内执行,与外部事务无关。
- NOT_SUPPORTED:
-
- 方法不应在事务内执行。如果当前存在事务,它将被挂起,方法将以非事务方式执行。
- NEVER:
-
- 方法绝对不能在事务内执行。如果当前存在事务,将抛出异常。
- NESTED:
-
- 如果当前存在事务,则创建一个嵌套事务,嵌套事务是外部事务的一部分。如果当前没有事务,则行为类似于 REQUIRED。
- NESTED 传播行为允许在嵌套事务内执行,如果嵌套事务失败,则只回滚嵌套事务,而不会影响外部事务。
Spring框架中的Bean生命周期是什么?
Spring框架中的Bean生命周期包含以下关键步骤:
1、实例化Bean: 首先创建Bean的实例。
2、设置属性值: Spring框架通过反射机制注入属性。
3、调用BeanNameAware的setBeanName(): 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传给setBeanName()方法。
4、调用BeanFactoryAware的setBeanFactory(): 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。
5、调用ApplicationContextAware的setApplicationContext(): 如果Bean实现了ApplicationContextAware接口,此方法将被调用,传入当前的ApplicationContext。
6、BeanPostProcessor的前置处理: BeforeInitialization方法被调用。
7、调用InitializingBean的afterPropertiesSet(): 如果Bean实现了InitializingBean接口,Spring将调用其afterPropertiesSet()方法。
8、定义的init方法: 如果Bean定义了init方法,该方法将被调用。
9、BeanPostProcessor的后置处理: AfterInitialization方法被调用。
10、Bean的使用: 此时,Bean已准备就绪,可以被应用程序使用。
11、调用DisposableBean的destroy(): 如果Bean实现了DisposableBean接口,当容器关闭时,destroy()方法将被调用。
12、定义的destroy方法: 如果Bean定义了destroy方法,该方法将被调用。
Spring中的依赖注入是如何工作的?
Spring中的依赖注入(DI)是一个核心概念,它通过以下方式工作:
1、通过构造器注入: Spring通过类的构造器参数注入依赖。
2、通过Setter方法注入: 依赖可以通过Bean的Setter方法被注入。
3、基于注解的注入: 使用注解(如@Autowired)直接在属性、构造器或方法上注入依赖。
4、XML文件注入: 在Spring的XML配置文件中定义Bean及其依赖。
这种机制减少了代码间的耦合度,使得组件更易于测试和维护。
Spring框架中AOP的概念。
AOP(面向切面编程)在Spring框架中用于增强面向对象编程,其核心概念包括:
1、切面(Aspect): 横切关注点的模块化,比如日志、安全等。
2、连接点(Join Point): 程序执行过程中的某个特定点,如方法调用或异常抛出。
3、通知(Advice): 在切面的某个特定连接点上执行的动作。
4、切点(Pointcut): 匹配连接点的表达式。
5、引入(Introduction): 向现有类添加新方法或属性。
6、目标对象(Target Object): 被一个或多个切面通知的对象。
7、织入(Weaving): 把切面与其他应用类型或对象连接起来,创建一个被通知的对象。
这些概念共同工作,为Spring应用提供强大的编程方式以处理共性问题。
Spring框架中的事务管理是如何实现的?
Spring框架通过以下机制实现事务管理:
1、声明式事务管理: 使用注解或XML配置来管理事务,是最常用的方式。
2、编程式事务管理: 使用编程的方式直接管理事务,给予开发者更大的控制,但不如声明式事务简洁。
3、事务传播行为: Spring定义了多种事务传播行为,如REQUIRED、REQUIRES_NEW等,控制事务的创建和嵌套方式。
4、事务隔离级别: Spring支持多种事务隔离级别,帮助解决事务中常见的问题,如脏读、不可重复读、幻读等。
5、回滚规则: Spring允许自定义事务回滚的规则。
这些特性使得Spring在事务管理方面非常灵活和强大。
Spring MVC流程。
Spring MVC框架的流程主要包括以下步骤:
1、请求到达DispatcherServlet: 所有请求首先到达中央控制器DispatcherServlet。
2、请求映射: DispatcherServlet调用HandlerMapping确定请求的处理器。
3、调用处理器: 处理器接收请求并返回ModelAndView对象。
4、视图解析: DispatcherServlet调用ViewResolver来解析Handler返回的视图。
5、返回响应: 视图负责渲染并返回给客户端。
Spring MVC通过这种流程提供了一个灵活、解耦的方式来开发Web应用。
Spring Boot与Spring有什么区别?
Spring Boot是基于Spring的框架,旨在简化Spring应用的初始搭建及开发过程。主要区别包括:
1、自动配置: Spring Boot自动配置项目,简化了配置过程。
2、独立运行: Spring Boot应用可以独立运行,不需要外部Servlet容器。
3、内嵌服务器: 提供内嵌的Tomcat、Jetty或Undertow服务器。
4、无需XML配置: Spring Boot减少了对XML配置的依赖,更多使用注解和Java配置。
5、微服务支持: 为构建微服务提供了强大的支持。
Spring Cloud与Spring Boot有什么关系?
Spring Cloud是一系列框架的集合,用于构建微服务应用。与Spring Boot的关系如下:
1、基于Spring Boot: Spring Cloud建立在Spring Boot的基础上,利用其特性来简化分布式系统开发。
2、微服务工具集: Spring Cloud为微服务架构提供了一整套的解决方案,如服务发现、配置管理、消息路由等。
3、依赖管理: Spring Cloud依赖Spring Boot来管理各种依赖的版本。
4、增强的分布式系统支持: 通过Spring Cloud,Spring Boot应用可以更容易地构建为分布式系统的一部分。
Spring Cloud与Spring Boot共同提供了一个全面且一致的开发体验,用于构建现代的、可伸缩的微服务应用。
Spring Security中的认证和授权机制是如何工作的?
Spring Security提供了全面的安全服务,其认证和授权机制包括:
1、认证过程: 认证是确认用户身份的过程。Spring Security支持多种认证方式,如表单登录、LDAP、OAuth2等。
2、授权过程: 授权是决定用户是否有权执行特定操作的过程。Spring Security通过角色和权限来控制访问。
3、Security Filter Chain: 请求经过一系列的安全过滤器,每个过滤器负责不同的安全检查。
4、UserDetailsService接口: 用于根据用户名获取用户的详细信息。
5、PasswordEncoder接口: 用于密码的加密和匹配。
通过这些机制,Spring Security确保了应用的安全性。
Spring中Bean的作用域有哪些?
Spring框架中,Bean可以有不同的作用域,主要包括:
1、Singleton: 默认作用域,每个Spring容器中只有一个Bean实例。
2、Prototype: 每次请求都会创建一个新的Bean实例。
3、Request: 在一次HTTP请求中,每个Bean都是一个新的实例。
4、Session: 在一个HTTP会话中,每个Bean都是一个新的实例。
5、GlobalSession: 在全局HTTP会话中,每个Bean都是一个新的实例,主要用于Portlet应用。
6、Application: 在ServletContext生命周期内,Bean为单例。
7、WebSocket: 在WebSocket生命周期内,Bean为单例。
这些作用域提供了在不同情况下使用Bean的灵活性。
Spring框架中的IoC(控制反转)是什么意思?
IoC(控制反转)是Spring框架的核心概念,它指的是:
1、控制权转移: 将对象创建和管理的控制权从程序代码转移给框架。
2、依赖注入: IoC的一种实现方式,Spring框架通过依赖注入将组件彼此连接起来。
3、减少耦合: IoC使得代码之间的耦合度降低,提高了代码的可测试性和可维护性。
Spring Data JPA的工作原理。
Spring Data JPA简化了数据访问层的开发,其工作原理包括:
1、Repository接口: 开发者只需定义接口,Spring Data JPA会自动实现。
2、查询方法命名解析: 通过方法名解析查询逻辑。
3、实体管理: 自动处理实体类到数据库表的映射。
4、事务管理: 提供声明式事务管理。
5、集成Hibernate: 可与Hibernate等ORM框架无缝集成。
这样,Spring Data JPA为开发者提供了一个强大且易用的数据访问层。
Spring Boot中的自动配置是如何实现的?
Spring Boot的自动配置通过以下机制实现:
1、@EnableAutoConfiguration注解: Spring Boot应用加上此注解来启用自动配置。
2、条件注解: 如@ConditionalOnClass、@ConditionalOnMissingBean等,根据环境条件决定是否进行自动配置。
3、配置类: 提供默认的配置,如果用户没有定义自己的配置,则使用这些默认值。
4、外部配置: 通过application.properties或application.yml文件提供的配置。
这些机制使得在Spring Boot中配置项目变得简单快捷。
Spring Cloud中的服务发现和注册机制。
服务发现和注册是Spring Cloud微服务架构中的关键组成部分,工作原理如下:
1、服务注册: 微服务启动时,将自己的信息注册到服务注册中心。
2、服务发现: 应用通过服务注册中心来查找需要调用的服务的位置。
3、负载均衡: 在客户端实现负载均衡,选择一个合适的服务实例进行调用。
4、常见实现: 如Eureka、Consul和Zookeeper等。
这种机制允许微服务实例动态注册和发现,增加了系统的弹性和可伸缩性。
Spring中的事件和事件监听器是如何工作的?
Spring框架的事件和事件监听器机制包括:
1、事件(Event): 继承自ApplicationEvent的类,代表应用中发生的事件。
2、事件发布: 通过ApplicationEventPublisher发布事件。
3、事件监听器(EventListener): 实现ApplicationListener接口或使用@EventListener注解,用于处理特定类型的事件。
4、异步处理: 可以通过@Async注解使事件监听器异步处理事件。
这种机制使得应用组件间的通信更加灵活和解耦。
Spring框架中的事务传播行为有哪些?
Spring框架定义了多种事务传播行为,主要包括:
1、REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
2、SUPPORTS: 如果当前存在事务,则加入该事务;如果没有,则以非事务方式执行。
3、MANDATORY: 如果当前存在事务,则加入该事务;如果没有,则抛出异常。
4、REQUIRES_NEW: 总是创建一个新的事务,如果当前存在事务,则挂起当前事务。
5、NOT_SUPPORTED: 总是非事务地执行,如果当前存在事务,则挂起当前事务。
6、NEVER: 总是非事务地执行,如果当前存在事务,则抛出异常。
7、NESTED: 如果当前存在事务,则在嵌套事务内执行;如果没有,则行为同REQUIRED。
这些行为为事务管理提供了灵活性,适应不同的业务场景。
Spring框架中如何实现国际化(i18n)?
Spring框架实现国际化的主要步骤包括:
1、定义消息资源: 创建属性文件,存储不同语言环境下的消息。
2、配置MessageSource: 在Spring配置文件中配置MessageSource,指定消息资源的基础名(basename)。
3、使用MessageSource: 使用ApplicationContext或MessageSource接口获取国际化消息。
4、Locale解析: 通过LocaleResolver解析用户的Locale。
5、在应用中使用国际化消息: 在代码或模板中使用Spring的消息解析功能展示国际化内容。
Spring中,如何通过JdbcTemplate操作数据库?
使用JdbcTemplate操作数据库的步骤如下:
1、配置DataSource: 提供数据库的连接信息。
2、创建JdbcTemplate实例: 将DataSource注入到JdbcTemplate。
3、执行数据库操作: 使用JdbcTemplate提供的方法执行SQL查询或更新,如query、update等。
4、处理结果集: 使用RowMapper或ResultSetExtractor处理查询结果。
JdbcTemplate简化了JDBC操作,使数据库交互更加方便和安全。
Spring Cloud Config是如何工作的?
Spring Cloud Config为微服务应用提供集中化外部配置。其工作机制如下:
1、配置服务器(Config Server): 集中管理所有应用的配置文件。
2、配置客户端(Config Client): 微服务作为客户端从配置服务器获取配置。
3、配置仓库: 配置文件存储在Git或SVN等版本控制系统中。
4、动态刷新: 支持在不重启服务的情况下刷新配置。
5、环境分离: 不同环境(开发、测试、生产)可以有不同的配置。
Spring Boot中的Actuator是什么,它提供了哪些功能?
Spring Boot Actuator提供了应用的监控和管理功能,包括:
1、健康检查(Health check): 查看应用的健康状态。
2、度量收集(Metrics): 收集和展示应用的各种度量信息。
3、环境信息(Env): 展示配置的环境属性。
4、日志级别管理(Log Levels): 动态调整日志级别。
5、线程状态(Threads): 展示应用的线程信息。
6、HTTP跟踪(HTTP Trace): 显示HTTP请求-响应交换的信息。
7、应用信息(Info): 展示任意的应用信息。
8、审核事件(Audit Events): 查看审计事件。
Actuator使得管理和监控Spring Boot应用变得简单有效。
Spring中的数据访问异常层次结构。
Spring提供了一套数据访问异常层次结构,包括:
1、DataAccessException: 所有数据访问异常的基类。
2、DataRetrievalFailureException、InvalidDataAccessResourceUsageException等: 具体的异常类,对应于不同的数据访问问题。
3、异常转换: Spring将底层数据访问技术(如JDBC、Hibernate)的异常转换为DataAccessException的子类。
这种层次结构使得异常处理更加一致,且与底层数据访问技术解耦。
Spring MVC和Spring WebFlux之间有什么区别?
Spring MVC和Spring WebFlux都是Spring框架用于构建Web应用的模块,主要区别在于:
1、编程模型: Spring MVC是基于Servlet API和同步阻塞架构,而WebFlux是基于Reactive编程模型。
2、IO处理: Spring MVC使用传统的阻塞IO,WebFlux支持非阻塞IO。
3、性能: 在高负载和低延迟要求的场景下,WebFlux可以提供更高的性能。
4、适用场景: Spring MVC适合传统的Web应用开发,WebFlux适合处理长时间运行的异步任务和高并发的场景。
Spring框架中的Template设计模式。
Spring框架中的Template设计模式用于简化资源的使用,如JdbcTemplate、RestTemplate等。核心特点包括:
1、资源管理: 自动管理资源的打开和关闭。
2、异常处理: 提供统一的异常处理机制。
3、代码复用: 封装了常用的操作逻辑,减少重复代码。
4、简化API: 提供了简洁的API来执行常规任务。
这种设计模式使得与各种资源交互更加简单和安全。
Spring Security中的过滤器链是什么?
Spring Security中的过滤器链是一系列过滤器,负责处理安全相关的任务,如认证、授权等。主要特点包括:
1、多个过滤器: 包括认证过滤器、授权过滤器等。
2、执行顺序: 过滤器按照特定的顺序执行。
3、自定义扩展: 可以添加或修改过滤器来满足特定需求。
4、与Servlet过滤器链集成: 与Web应用的标准过滤器链集成。
这个过滤器链是Spring Security实现安全控制的核心。
Spring中如何使用AOP实现日志记录?
在Spring中使用AOP实现日志记录的步骤如下:
1、定义切面(Aspect): 创建一个类作为切面,用于实现日志记录的逻辑。
2、定义通知(Advice): 在切面类中定义方法,使用@Before、@After、@Around等注解标注,以在目标方法前后或环绕执行日志记录。
3、定义切点(Pointcut): 使用表达式定义哪些方法需要被日志记录。
4、配置AOP: 在Spring配置中启用AOP(如使用@EnableAspectJAutoProxy注解)。
5、应用切面: 将切面应用到需要记录日志的业务逻辑上。
这样,可以在不修改业务代码的情况下,灵活地添加日志记录功能。
Spring中BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring容器的两种形式,它们的主要区别包括:
1、功能范围: ApplicationContext比BeanFactory提供更多的功能,如事件传播、AOP支持等。
2、Bean的加载时机: BeanFactory是懒加载,即在请求时才创建Bean;ApplicationContext则在启动时就加载所有的Bean。
3、国际化支持: ApplicationContext提供了国际化的支持,而BeanFactory没有。
4、事件发布: ApplicationContext可以发布事件,BeanFactory则不支持。
5、资源加载: ApplicationContext提供了更灵活的资源加载方式。
因此,ApplicationContext更适合大多数企业级应用。
Spring Boot中如何自定义启动Banner?
在Spring Boot中自定义启动Banner的方法如下:
1、创建Banner文件: 在资源目录(如src/main/resources)下创建一个banner.txt文件。
2、添加自定义文本: 在banner.txt文件中添加自定义的ASCII艺术字或文本。
3、配置application.properties: 可以通过spring.banner.location属性指定Banner文件的位置。
4、使用编程方式: 也可以通过实现Banner接口,在代码中自定义启动Banner。
5、关闭Banner: 通过设置spring.banner.enabled=false来关闭Banner显示。
Spring MVC中HandlerInterceptor和Filter有什么区别?
HandlerInterceptor和Filter在Spring MVC中都用于在请求处理前后执行某些操作,但有以下区别:
1、处理阶段: Filter是基于Servlet的,作用于请求的最前端;HandlerInterceptor是Spring MVC的一部分,作用于控制器方法调用的前后。
2、功能范围: Filter适用于所有Web应用程序,而HandlerInterceptor仅适用于通过Spring MVC处理的请求。
3、参数访问: HandlerInterceptor可以访问控制器方法的元数据,而Filter不能。
4、配置方式: HandlerInterceptor通常在Spring的上下文中配置,而Filter可以在web.xml或使用Servlet 3.0的注解配置。
Spring中的事务管理器TransactionManager。
TransactionManager是Spring中用于事务管理的接口,主要功能包括:
1、事务控制: 提供了开始、提交、回滚事务的方法。
2、事务状态管理: 管理事务的整个生命周期和状态。
3、资源管理: 确保事务涉及的资源(如数据库连接)被正确管理。
4、不同类型的实现: 如DataSourceTransactionManager、HibernateTransactionManager等,支持不同持久化技术的事务管理。
5、与Spring集成: 与Spring的声明式事务管理和编程式事务管理紧密集成。
Spring框架中的设计模式有哪些?
Spring框架使用了多种设计模式,包括但不限于:
1、单例模式: 在Spring默认的作用域中,每个Bean都是单例的。
2、工厂模式: BeanFactory和ApplicationContext是工厂模式的实现。
3、代理模式: Spring AOP和Spring Security底层使用了代理模式。
4、模板方法模式: 如JdbcTemplate、HibernateTemplate等,提供了一种模板方法的实现。
5、观察者模式: Spring事件机制的实现。
6、适配器模式: Spring MVC中的Controller适配器。
7、装饰器模式: 在资源视图等方面使用。
这些设计模式使得Spring框架非常灵活且易于扩展。
Spring Boot中的Profiles。
Profiles是Spring Boot中用于根据不同的环境应用不同配置的机制。其主要特点包括:
1、环境分隔: 可以为开发、测试、生产等不同环境定义不同的配置。
2、激活方式: 可以通过环境变量、JVM参数、配置文件等方式激活特定的Profile。
3、条件化配置: 通过@Profile注解在组件上指定在哪个Profile激活时才生效。
4、配置文件分割: 如application-dev.yml、application-prod.yml等,根据激活的Profile应用不同的配置文件。
Spring中如何处理异常?
在Spring中处理异常的方法包括:
1、@ControllerAdvice和@ExceptionHandler: 提供全局异常处理机制。
2、ResponseEntityExceptionHandler: 提供了处理常见Spring MVC异常的方法。
3、自定义异常类: 创建自定义的异常类来处理特定的业务逻辑异常。
4、BindingResult: 在表单验证中使用,来处理验证错误。
5、@ResponseStatus: 可以在异常类上使用此注解定义异常对应的HTTP状态码。
这些方法使得异常处理在Spring中变得更加灵活和统一。
Spring Boot中的CommandLineRunner和ApplicationRunner有什么区别?
CommandLineRunner和ApplicationRunner都用于在Spring Boot应用启动后执行一些代码,区别在于:
1、参数差异: CommandLineRunner的run方法接受String数组参数,而ApplicationRunner接受ApplicationArguments对象。
2、使用便利性: ApplicationRunner提供了更丰富的API来解析命令行参数。
3、使用场景: 如果需要复杂的命令行参数解析,建议使用ApplicationRunner;如果参数简单,使用CommandLineRunner即可。
Spring Security中的OAuth2。
OAuth2是一个授权框架,Spring Security提供了OAuth2的支持,其主要特点包括:
1、四种授权模式: 授权码模式、简化模式、密码模式、客户端模式。
2、资源服务器和授权服务器: 支持将应用分为资源服务器和授权服务器。
3、令牌类型: 支持使用访问令牌(access token)和刷新令牌(refresh token)。
4、安全性: 提供了保护资源和验证用户身份的强大机制。
5、集成性: 可以与Spring应用中的其他安全特性集成。
OAuth2使得在Spring应用中实现安全的API访问变得简单且标准化。
Spring框架中BeanFactory和ApplicationContext的区别是什么?
BeanFactory和ApplicationContext都是Spring框架中用于管理Bean的容器,但它们之间存在一些关键差异:
1、Bean实例化时机: BeanFactory是懒加载的,即只有在请求时才会创建Bean实例。而ApplicationContext则在启动时就实例化所有的Bean。
2、功能丰富性: ApplicationContext相比BeanFactory提供了更多的功能,如国际化支持、事件传播、资源加载等。
3、AOP集成: ApplicationContext支持AOP(面向切面编程),而BeanFactory则需要额外的配置来实现AOP。
4、环境抽象: ApplicationContext提供了环境抽象,允许读取配置文件和环境变量。
5、注解支持: ApplicationContext支持各种注解,如@Component、@Service等,而BeanFactory则需要更多的配置。
这些差异使得ApplicationContext更适合企业级应用,而BeanFactory适合资源受限的环境。
Spring中如何实现事务管理?
Spring中事务管理可以通过声明式事务和编程式事务来实现:
1、声明式事务: 使用@Transactional注解来声明一个方法在事务环境下运行。Spring会为此方法创建一个代理,确保方法在事务中执行。
2、事务的传播行为: 可以设置不同的事务传播行为来处理事务方法之间的调用关系,如REQUIRED、REQUIRES_NEW、SUPPORTS等。
3、事务管理器: 需要配置一个事务管理器,如DataSourceTransactionManager或JpaTransactionManager,来管理数据库事务。
4、异常回滚: 默认情况下,事务在遇到运行时异常时回滚,但可以通过@Transactional注解的rollbackFor属性自定义回滚规则。
5、编程式事务: 使用TransactionTemplate或直接使用PlatformTransactionManager来在代码中控制事务的边界和规则。
这种灵活的事务管理方式使得Spring在不同的业务场景下都能提供强大的数据一致性保证。
Spring MVC中的DispatcherServlet是如何工作的?
DispatcherServlet是Spring MVC的核心,它负责将请求路由到不同的处理器。它的工作流程如下:
1、请求接收: DispatcherServlet接收到客户端请求后,会解析请求中的URL。
2、调用处理器映射器: 根据URL查找对应的Controller。
3、调用适配器: 选择合适的HandlerAdapter来处理请求。
4、执行处理器逻辑: HandlerAdapter调用Controller的方法执行业务逻辑。
5、模型和视图: 处理器返回一个ModelAndView对象,包含模型数据和视图名。
6、视图解析: 根据视图名,DispatcherServlet使用ViewResolver找到具体的View。
7、渲染视图: View负责渲染模型数据,生成响应。
这个过程展示了Spring MVC如何从接收请求到生成响应的完整流程,体现了其高度的可扩展性和灵活性。
Spring框架中的IoC(控制反转)是什么,它是如何工作的?
Spring框架中的IoC(控制反转)是一种设计原则,用于减少代码间的耦合。它的工作机制如下:
1、依赖注入: IoC的主要实现方式是依赖注入(DI)。对象不再自己创建依赖的实例,而是由Spring容器注入。
2、容器: Spring IoC容器负责实例化、配置和组装应用中的对象。
3、配置方式: 可以通过XML配置文件、注解或Java配置类来定义对象及其依赖关系。
4、Bean生命周期管理: 容器负责管理Bean的整个生命周期,包括创建、初始化、使用和销毁。
5、松耦合: 由于依赖注入的应用,应用组件之间的耦合度降低,增加了代码的灵活性和可维护性。
Spring框架中的AOP(面向切面编程)是什么,它的应用场景有哪些?
AOP(面向切面编程)是Spring框架的一个关键组成部分,用于增强面向对象编程。它的应用场景包括:
1、日志记录: 自动记录方法的调用,不需要在每个方法中添加日志代码。
2、事务管理: 在方法执行前后进行事务处理,实现声明式事务管理。
3、权限检查: 在方法执行前进行权限检查,确保安全性。
4、性能监控: 监控方法执行时间,用于性能调优。
5、异常处理: 在方法抛出异常时进行统一处理。
6、工作原理: AOP通过代理模式,将额外的行为(如日志、事务等)织入到对象的方法调用中。
Spring框架中Bean的生命周期。
Spring框架中Bean的生命周期包括以下阶段:
1、实例化: 根据Bean的定义创建Bean实例。
2、填充属性: 对Bean的属性进行注入。
**3、调用BeanNameAware、BeanClassLoaderAware等接口方法。
4、BeanPostProcessor前置处理: 执行前置处理逻辑。
5、调用InitializingBean的afterPropertiesSet方法: 执行自定义初始化逻辑。
**6、调用自定义的init方法。
7、BeanPostProcessor后置处理: 执行后置处理逻辑。
**8、Bean准备就绪,可用于应用。
9、当容器关闭时,调用DisposableBean的destroy方法: 执行清理逻辑。
10、调用自定义的destroy方法: 执行额外的清理工作。
Spring框架中的事务管理是如何实现的?
Spring框架中的事务管理实现方式如下:
1、声明式事务: 最常用的事务管理方式,通过@Transactional注解来声明方法上的事务需求。
2、编程式事务: 使用TransactionTemplate或直接使用PlatformTransactionManager来编程实现事务管理。
3、事务传播行为: Spring支持不同的事务传播行为,如REQUIRED、REQUIRES_NEW等,以适应不同的业务场景。
4、事务隔离级别: Spring允许配置事务的隔离级别,如READ_COMMITTED、SERIALIZABLE等。
5、异常回滚规则: Spring默认对运行时异常进行回滚,对检查型异常不回滚,但可以通过注解自定义回滚规则。
Spring MVC框架的工作原理是什么?
Spring MVC框架的工作原理包括以下几个主要部分:
1、DispatcherServlet: 作为前端控制器,负责接收请求并分发到相应的处理器。
2、HandlerMapping: 确定请求由哪个Controller处理。
3、Controller: 处理请求并返回ModelAndView对象。
4、ViewResolver: 根据Controller返回的视图名称解析出具体的View。
5、View: 渲染模型数据,返回给客户端。
6、工作流程: 请求首先到达DispatcherServlet,然后根据HandlerMapping找到相应的Controller,Controller处理完请求后,返回ModelAndView给DispatcherServlet,由ViewResolver解析视图,最后由View渲染最终结果返回给客户端。
Spring框架中BeanFactory和ApplicationContext的区别是什么?
BeanFactory和ApplicationContext是Spring框架中两个核心接口,它们之间的主要区别在于:
1、功能丰富程度: ApplicationContext比BeanFactory提供更多的功能。ApplicationContext继承自BeanFactory,提供了国际化支持、事件传播、资源加载等高级服务。
2、Bean的加载时机: BeanFactory采用的是懒加载,即只有在请求获取Bean时才会创建该Bean。而ApplicationContext则会在启动时预先创建和配置所有的单例Bean。
3、AOP集成: ApplicationContext提供了对AOP的完整支持,而BeanFactory则需要手动配置AOP代理。
4、事件发布: ApplicationContext可以发布事件,对Bean之间的通信提供支持。BeanFactory不提供这样的机制。
ApplicationContext通常是更加推荐的选择,因为它为大多数企业级应用提供了全面的支持。
Spring中的依赖注入是什么?它是如何工作的?
Spring框架的依赖注入(DI)是一种设计模式,用于实现类之间的松耦合。它的工作原理如下:
1、注入方式: Spring支持构造器注入和setter注入。构造器注入是通过类的构造器来注入依赖,而setter注入是通过类的setter方法。
2、配置: 依赖可以通过XML配置文件或注解(如@Autowired)来定义。Spring容器会根据这些配置来解析依赖关系。
3、创建Bean实例: 当Spring容器创建一个Bean实例时,它会查看该Bean需要哪些依赖,并自动将这些依赖注入到Bean中。
4、运行时依赖解析: Spring在运行时动态地注入依赖,这意味着代码不依赖于具体的实现,从而提高了模块之间的独立性和可测试性。
依赖注入是Spring实现控制反转(IoC)的主要方式,它极大地简化了Java企业级应用的开发。
Spring中的AOP(面向切面编程)概念?
AOP(面向切面编程)是Spring框架的一个关键部分,用于实现横切关注点的分离。它的主要概念包括:
1、切面(Aspect): 定义了跨多个类的横切逻辑,如日志、事务管理等。
2、连接点(Join Point): 程序执行过程中的某个特定点,比如方法调用或异常抛出。
3、通知(Advice): 切面在特定连接点上要执行的动作。分为前置通知、后置通知、环绕通知等。
4、切点(Pointcut): 指定哪些连接点会被拦截,通常通过表达式来指定。
5、代理(Proxy): AOP框架创建的对象,用于在运行时环绕原有对象,实现通知逻辑。
AOP允许开发者将这些横切关注点模块化,从而提高代码的可维护性和可复用性。
Spring Boot与传统Spring应用有何不同?
Spring Boot是基于Spring的一个框架,旨在简化新Spring应用的初始搭建以及开发过程。它与传统Spring应用的主要区别包括:
1、自动配置: Spring Boot提供了自动配置的功能,可以根据项目中的jar依赖自动配置Spring应用。
2、独立运行: Spring Boot应用可以作为独立的Java应用运行,不需要依赖外部的Servlet容器。
3、内嵌服务器: Spring Boot内嵌了Tomcat、Jetty或Undertow等Servlet容器,简化了Web应用的部署。
4、无需繁琐配置: Spring Boot减少了配置文件的使用,通过注解和自动配置来简化Spring应用的开发。
5、生产就绪特性: 提供了一系列生产就绪的特性,如健康检查、度量收集等。
Spring Boot使得开发者可以更快速地搭建和开发Spring应用,特别适用于微服务架构。
Spring Cloud与Spring Boot的关系是什么?
Spring Cloud和Spring Boot都是Spring家族中的重要成员,它们之间的关系可以描述如下:
1、基础框架: Spring Boot是构建任何Spring应用的基础,而Spring Cloud是在Spring Boot的基础上构建的。
2、专注点不同: Spring Boot主要简化了单个微服务的创建和开发过程。相比之下,Spring Cloud关注于微服务架构下的服务间通信和治理。
3、集成和兼容性: Spring Cloud利用Spring Boot的开发便利性,为微服务之间的通信提供了一套解决方案,如服务发现、配置管理、负载均衡等。
4、共同目标: 两者共同目标是简化分布式系统的开发,Spring Boot注重于简化单个应用的开发,Spring Cloud注重于微服务之间的协调和管理。
Spring Cloud和Spring Boot的结合为开发者提供了一套完整的微服务开发和部署解决方案。
Spring框架中的事务管理有哪些类型,它们的区别是什么?
Spring框架提供了两种主要的事务管理类型:
1、编程式事务管理: 这种方式通过编程的方式管理事务,给予开发者完全的控制权,但同时代码侵入性强。使用TransactionTemplate或直接使用PlatformTransactionManager。
2、声明式事务管理: 更常用的方法,通过配置来管理事务。它将事务管理代码从业务代码中分离出来,通过使用注解(@Transactional)或XML配置文件实现。
区别主要在于声明式事务管理提供了更简洁的方式来处理事务,减少了代码的复杂性,而编程式事务管理则提供了更大的灵活性和控制。
Spring MVC中HandlerInterceptor的作用是什么?
在Spring MVC框架中,HandlerInterceptor(处理器拦截器)用于实现请求的预处理和后处理:
1、预处理(preHandle): 在Controller方法执行前调用,可以进行编码、安全控制等处理。
2、后处理(postHandle): 在Controller方法执行后,视图返回前执行,可以对请求域中的属性或视图做出修改。
3、完成后(afterCompletion): 在请求完成后调用,即视图渲染后,常用于资源清理操作。
HandlerInterceptor是实现AOP(面向切面编程)在Spring MVC中的一个重要手段,广泛用于日志记录、权限检查、性能监控等。
Spring中的JdbcTemplate是什么?它解决了哪些问题?
JdbcTemplate是Spring框架提供的一个简化数据库操作的工具,它解决了以下问题:
1、简化代码: JdbcTemplate自动处理了创建和释放数据库连接的过程,减少了标准的JDBC操作中的样板代码。
2、异常处理: JdbcTemplate提供了统一的异常处理机制,将检查型异常转换为运行时异常,简化了错误处理代码。
3、支持泛型和参数化: 提供了泛型方法和参数化查询的支持,使数据库操作更安全、清晰。
JdbcTemplate是Spring中进行JDBC数据库操作的首选方式,特别是对于简单的数据库访问和操作。
Spring中的单例Bean和原型Bean的区别?
在Spring框架中,Bean的作用域决定了Bean的生命周期,主要区别在于:
1、单例Bean(Singleton): 在Spring IoC容器中只创建一次,所有对该Bean的请求都返回同一个实例,适用于共享单实例的情况。
2、原型Bean(Prototype): 每次请求都会创建一个新的Bean实例,适用于每个使用者都需要一个新实例的场景。
区别在于单例Bean是共享的,原型Bean则每次请求都创建新的实例。选择哪种类型取决于具体应用场景的需求。
Spring框架中的Bean生命周期是如何的?
Spring框架中的Bean生命周期包括以下阶段:
1、实例化: 通过构造器创建Bean实例。
2、填充属性: 设置Bean的属性值。
3、Bean名称赋值: 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法。
4、BeanFactory赋值: 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,传入BeanFactory。
5、预初始化(前置处理器): 如果Bean的后置处理器实现了BeanPostProcessor接口,将调用其postProcessBeforeInitialization()方法。
6、初始化: 如果Bean实现了InitializingBean接口,Spring将调用afterPropertiesSet()方法;也可以通过配置init-method指定初始化方法。
7、后初始化(后置处理器): 调用postProcessAfterInitialization()方法。
8、Bean使用: Bean现在可以使用了。
9、销毁: 如果Bean实现了DisposableBean接口,Spring将调用其destroy()方法;也可以通过配置destroy-method指定销毁方法。
了解Bean的生命周期有助于更好地理解和使用Spring容器对Bean的管理。
Spring尼恩
张洪亮
Spring面试题整理 - 来自飞书
林秋地面试题
8. 什么是Spring 中的 ApplicationContext ?
9. Spring 常用的 ApplicationContext 有哪些?
10. Spring 中 BeanFactory 和 ApplicationContext 的区别有哪些?
11. 说一说Spring 获取 ApplicationContext 的方法?
22. Spring 防止相同类型 Bean 注入异常的方法?
25. Spring 中 @Component, @Service, @Repository, @Controller 的区别是什么?
26. Spring 中的 @Bean 与 @Component 注解的区别有哪些?
27. Spring 中的 @Bean 与 @Component 注解用在同一个类上,会怎么样? 容器中Bean的数量?
28. Spring 中的 @Autowired 注解的作用?
29. Spring 中的 @Autowired 注解的用法有哪些?
30. Spring 中的 @Autowired 注解默认按什么方式装配?
31. Spring 中的 @Autowired 注入 request 是线程安全的吗?
32. Spring 中使用 @Resource,@Autowired,@lnject 的区别有哪些?
33. Spring 不推荐使用 @Autowired 字段注入的原因是什么? 应该怎么使用?
34. Spring 中的 @Required 注解的作用?
35. Spring 中的 @Qualifier 注解的作用?
37. Spring 中的 Bean 有多个实现类,该怎么指定注入?
45. Spring 需要三级缓存解决循环依赖,而不是二级缓存的原因是什么?
49. Spring AOP和 AspectJ AOP 的区别有哪些?
58. Spring 中的 @Transactional 事务注解支持哪些参数?
78. 解释一下Spring 中的 @Enable* 注解的原理?
牛客加载的面试题
Spring源码面试题
谈谈你对Spring框架的理解?
Spring 是一个开源的应用程序框架,它起源于 Rod Johnson 在其著名的 Spring Framework 专著中提出的一个轻量级框架的观念。下面是 Spring 的发展历史:
- 2002 年,Rod Johnson 发表了他的专著 “Expert One-On-One J2EE Design and Development”,提出了 Spring 框架的思想。
- 2003 年,Johnson 和一些开发者创建了 Spring Framework 项目,并在 SourceForge 上发布了第一个版本。
- 2004 年,Spring Framework 1.0 版本发布,包括核心容器、AOP 模块、DAO 模块、JDBC 模块和 Web 模块等组成部分。
- 2006 年,Spring Framework 2.0 版本发布,增加了对注解的支持、Web Services 支持、异步执行能力等新特性。
- 2009 年,Spring Framework 3.0 版本发布,引入了对 Java 5、Java 6 特性的支持,包括泛型、注解、并发等。
- 2013 年,Spring Framework 4.0 版本发布,提供对 Java 8 的支持,包括 lambda 表达式、Stream API 等。
- 2015 年,Spring Framework 4.2 版本发布,增加了对 WebSocket 和 STOMP 协议的支持。
- 2017 年,Spring Framework 5.0 版本发布,对响应式编程提供了支持,并对代码库进行了大规模升级和剪裁,去掉了过时和不必要的模块和类。
自从 2003 年发布以来,Spring Framework 在 Java 开发社区中变得越来越流行,并成为了多个企业级应用开发的首选框架之一。
Spring Framework的IoC容器实现原理是什么?
- 控制翻转
- Spring中IoC的实现:管理Bean对象的容器 ==》 容器是如何管理Bean对象 ==》 容器创建添加Bean对象 ==》Bean的定义。Bean定义的管理。Bean的声明周期
Bean的定义==》 BeanDefinition ==》 BeanFactory【存储了所有的BeanDefinition】==》BeanDefinitionRegistry ==》 Bean实例有两种类型 单例,原型 单例==》容器初始化的时候==》完成对应的实例。单例Bean保存在一级缓存中。 原型Bean 在我们获取Bean的时候getBean()会完成对象的实例化
Spring的IoC(Inversion of Control,控制反转)是一种设计模式,它的核心思想是将对象的创建、组装和管理过程交给框架来完成,而不是由应用程序直接控制。这种模式通过将应用程序的控制权交给框架来提高应用程序的可扩展性、灵活性和可维护性。
在Spring中,IoC容器负责管理和组装应用程序中的组件。IoC容器可以通过XML配置文件、Java注解和Java代码来配置和组装对象。Spring IoC容器的实现类包括BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,提供了更多的功能和便利的特性。
在源码层面,Spring IoC的核心组件是BeanFactory和BeanDefinition。BeanFactory是IoC容器的接口,它提供了管理和获取bean的方法。BeanDefinition是描述bean的元数据对象,包括bean的类型、作用域、依赖项和初始化参数等信息。BeanFactory通过BeanDefinition来创建、组装和管理bean。
在Spring中,BeanFactory和ApplicationContext之间的区别在于ApplicationContext在BeanFactory的基础上提供了更多的特性,例如国际化、事件机制、AOP和自动装配等功能。此外,ApplicationContext还可以管理生命周期和资源,提供了更方便的方法来管理Spring应用程序。
在源码中,Spring IoC通过使用反射、动态代理和BeanPostProcessor等技术来实现依赖注入和组件的创建和管理。在创建bean时,IoC容器会解析BeanDefinition,然后通过反射创建bean实例,设置bean的属性并执行初始化方法。对于需要注入其他bean的属性,容器会自动查找相应的bean实例并进行注入。在完成bean的创建和依赖注入后,容器将bean放入自己的容器中进行管理,同时可以根据需要进行销毁或重置。
Spring Framework的Bean生命周期是怎样的?
Spring的Bean的生命周期
Servlet的生命周期
Filter的生命周期
Vue 生命周期
....
Spring Framework AOP的实现原理是什么?
AOP:面向切面编程 ==补充==》OOP:面向对象编程
1。你们公司中对AOP的应用
2。在Spring中AOP的使用方式
3。AOP中的核心概念
4。SpringAOP的实现
核心概念讲解:
Spring Framework事务管理的实现原理是什么?
1。事务特性--》 事务的传播属性和事务的隔离级别 serviceA 事务管理a(){serviceB.b()} serviceB b();
serviceA a(){proxy.b();} b()
2。Spring中的事务的设计
3。基于AOP的事务实现
Spring Framework的事件机制是怎样的?
1.设计模式:发布订阅模式【观察者模式】
2。事件涉及到的核心概念:
Spring中的事件机制是基于观察者设计模式的实现。它包含三个核心组件:事件、事件监听器和事件发布器。
在Spring中,事件是一个普通的Java对象,通过继承 ApplicationEvent类来实现,它可以包含任意的数据。事件监听器是一个接口,只有一个方法 onApplicationEvent(),用来处理事件。事件发布器是 ApplicationEventPublisher接口的实现类,用来发布事件。
当一个事件发布器发布一个事件时,它会通知所有注册了对应事件类型的监听器。监听器会按照注册的顺序一次处理事件。如果事件处理抛出了异常,发布器会捕获并打印异常信息。
Spring事件机制的优点在于它可以实现模块之间的解耦合,一个模块只需要发布事件,而不需要知道哪些其他模块会对此事件进行处理。同时,使用Spring事件机制也可以实现事务的控制,例如在事件处理方法上添加 @Transactional注解,就可以保证整个事件在一个事务中执行。
Spring Framework中常用的设计模式有哪些?
Spring框架是一个基于多种设计模式的框架,以下是Spring中常用的几种设计模式:
- 依赖注入(Dependency Injection):也称为控制反转(Inversion of Control),通过控制反转,将对象的创建和依赖关系的管理交给Spring容器来处理,实现松散耦合和易于测试的目标。
- AOP(Aspect-Oriented Programming):面向切面编程,通过将横切关注点(如事务、安全、日志等)抽取出来,与业务代码分离,实现模块化开发、代码复用,提高系统的可维护性和可扩展性。
- 工厂模式(Factory Pattern):通过抽象工厂接口来统一管理对象的创建,增加新的实现类时不需要修改已有代码,只需要添加新的实现类,符合开闭原则。
- 单例模式(Singleton Pattern):通过单例模式确保一个类只有一个对象,提高系统性能和资源使用效率。
- 模板方法模式(Template Method Pattern):将一个操作中的算法框架固定,将具体实现延迟到子类中,实现了代码复用和扩展的目标。
- 观察者模式(Observer Pattern):定义一种一对多的关系,当一个对象的状态发生改变时,通知其他对象更新自己的状态,常用于事件处理等场景中。
通过以上常用的设计模式,Spring框架实现了松散耦合、面向切面、工厂化、可扩展、易于测试等优秀的特性,提高了系统的可维护性和可扩展性。
Spring Framework中常用的注解有哪些?
Spring框架中常用的注解有:
- @Autowired:自动装配,将需要的依赖注入到类中。通过使用不同的方式注入(如构造器注入、Setter注入、字段注入等)来指定要注入的实例对象。
- @Component:声明一个组件,将会由Spring框架进行扫描,并将其实例化作为一个Bean纳入Spring容器管理。
- @Controller:声明一个MVC控制器,标记该类为Spring的控制器,处理Web请求。
- @Service:声明一个服务类,标记该类为Spring的服务类,用于处理业务逻辑。
- @Repository:声明一个数据访问类,标记该类为Spring的数据访问类,用于进行数据库操作。
- @Configuration:声明一个Java配置类,其内部包含了若干个@Bean注解用于声明Bean对象。
- @Bean:声明一个Bean,用于在Java配置类中定义需要注入IOC容器中的Bean实例对象。
- @RequestMapping:用于将HTTP请求映射到对应的控制器中的处理方法上。
- @Value:用于将配置文件中的属性值注入到Spring Bean中的字段属性中。
以上是Spring框架中常用的注解,可以帮助开发者快速实现依赖注入、Bean管理、Spring MVC等功能。
Spring Framework中如何处理循环依赖问题?
1。什么是循环依赖 A--》 B B--》 A
构造注入:是解决不了循环依赖的
设值注入:是可以解决循环依赖的--》 提前暴露
2。Spring中的循环依赖是怎么处理?
三级缓存
3。为什么要三级缓存?如果没有代理对象。二级缓存是足够的
二级缓存提前暴露的是 Bean的真实对象。但是后面我们返回的其实是代理对象
4。为什么Spring没有使用二级缓存来解决。
5。Spring中一级缓存能处理循环依赖吗?
Spring中一级缓存存储的是单例bean
6。Spring支持对原型对象的循环依赖的支持吗?
原型对象==》有很多个。那么我就需要缓存 原型对象。
Spring容器支持处理循环依赖,即A对象依赖了B对象,而B对象又依赖了A对象的情况。
当Spring容器在创建一个Bean实例时,会记录该Bean实例的创建过程,当发生了循环依赖时,Spring会将该Bean实例的先前创建请求暂存到一个“早期引用”中,这时Spring容器并未将完全构造的Bean实例提供给请求它的对象,而是返回一个代理对象,等到该Bean实例构造完成后,将“早期引用”中的Bean实例注入到对应的属性中。
要注意的是,Spring只能处理单例模式下的循环依赖,因为每个单例Bean在Spring容器只会被创建一次,而在原型模式下,每次请求新的Bean实例时,Spring容器都会进行一次完整的Bean实例化过程,这样循环依赖就不存在了。
当存在循环依赖时,Spring容器会抛出BeanCurrentlyInCreationException异常,表明当前Bean正在创建中,此时可以通过调整Bean的依赖关系,或使用构造器注入等方式解决循环依赖问题。
JavaGuide - Spring面试题
尼恩
SpringMVC面试题
牛客网八股文
为什么依赖注入不适合使用字段注入(封装性差,耦合度()高)
Spring的事务,使用this调用是否生效(不生效,需要代理对象)
Spring的循环依赖
Spring MVC的工作流程;如果是传输文件呢(未答出)
答:传输文件时:dispatcherservlet拦截后会使用MultipartResolver解析请求,再使用handlerMapping选择处理器
Spring中的常用注解有哪些?了解如何实现的吗?
关注微信公众号:两行code,分享后端技术、算法、面经、以及后端场景问题~~