框架篇面试题

一、Springboot中有几种定义Bean的方式

1、@Bean注解

在方法上加上@Bean注解

注意:这个注解要在配置类中使用即@Configuration修饰的类,或者启动类也行,因为启动类也是配置类 。

2、使用 @Component@Service@Controller@Repository 注解

这些注解通常用于自动扫描类并将它们注册为 Spring 容器中的 Bean。通过 @Component 或其特定的派生注解(如 @Service@Controller@Repository)来定义。

注意:是类注册成bean,而不是里面的方法

@Component
public class MyComponent {
    // 业务逻辑
}

@Service
public class MyService {
    // 业务逻辑
}

@Controller
public class MyController {
    // 控制器逻辑
}

@Repository
public class MyRepository {
    // 数据库访问逻辑
}

3、使用 @ConfigurationProperties 注解

@ConfigurationProperties 用于将配置文件中的属性映射到 Java 类中,通常用于外部化配置,并自动将类定义为 Bean。

比如将成员变量的值写到配置文件中 。

@ConfigurationProperties(prefix = "app.config")
public class AppConfig {
    private String name;
    private int timeout;

    // getters and setters
}

注意:单从功能上看,@value也可以完成赋值的操作,只不过@value只能赋值单个
@ConfigurationProperties可以赋值同一前缀的属性

4、使用 @Import 注解

@Import 注解允许将一个或多个配置类导入到 Spring 容器中,从而将这些配置类中定义的 Bean 注册到 Spring 容器中。

比如一个Service类没有加上@Service,但是在配置类中使用@Import导入这个Service类,同样可以将这个类注册成Bean

@Import(AppConfig.class)
public class MainConfig {
    // 其他配置
}

5、使用@ControllerAdvice注解

这个注解一般是用于配置全局异常处理器的。可以搭配自定义异常来实现自定义异常处理

这个注解底层是有@Component,修饰的类可能成为一个bean

下图是其他用法,比如我们可以实现ResposeBodyAdvice接口,重写beforeBodyWrite方法,在Controller的结果写入Respose之前执行我们自己的逻辑。

实现 ResponseBodyAdvice 接口的类通常需要被 @ControllerAdvice 注解修饰。这是因为 @ControllerAdvice 注解用于定义一个全局的控制器增强,使得该类能够影响所有控制器的响应处理,包括对响应体的修改。

注意:底层不是AOP实现的,是执行顺序实现的

  • 当控制器方法返回响应体时,Spring MVC 会首先找到适当的 HttpMessageConverter 将对象转换为适合的 HTTP 响应格式。
  • 在这个过程中,Spring 会检查所有注册的 ResponseBodyAdvice 实现类,调用其 beforeBodyWrite 方法。
  • 这使得你可以在响应体被转换并返回给客户端之前,对其进行修改。

6、使用@Configuration

这个注解就很清楚了,不做过多的解释,可以当成配置类来用

7、BeanDefintion 

这个方法是比较底层的

8、使用<bean/>

这个就很少用了,我们使用的都是springboot,在spring.xml文件中配置相应类为bean

二、springboot的自动配置原理

这位更是重量级,面试就被问到了

在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

其中@EnableAutoConfiguration是实现自动化配置的核心注解。

该注解通过@Import注解导入对应的配置选择器(AutoConfigurationImportSelector)。关键的是内部就是读取了该项目和该项目引用的Jar包的的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。

在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。

一般条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。

当你引入某个依赖时,Maven(或 Gradle)会自动下载相应的 JAR 包,而 Spring Boot 的自动配置 会根据这些依赖判断是否加载对应的自动配置类。当你在项目中引入了对应的 JAR 包,这些 JAR 包中的 class 文件 就会被加载到项目的 类路径(classpath) 中。

总结:1、@SpringBootApplication   >>2、 @EnableAutoConfiguration 

        >>3、@Import 配置选择器AutoConfigurationImportSelector

     >>4、META-INF/spring.factories  里面包含上百个类的全类名

    >>5、@ConditionalOnClass判断是否有对应的class文件,有的话放入容器中

三、@Autowired和@Resource的区别

 @Autowired是先按照类型找,再按照名称找
@Resource是先按照名称找,再按照类型找

@Autowired
private MyService myService;

比如这里的MyService就是类型,myService就是名称


1、对于@Autowired

错误情况:

1、找到多个类型相同,但是名称没有符合的

2、按照类型找没有符合的
《多个没有,没有就真没有》

如果这样注入

@Autowired

private MyService myService;   会报错

因为是先根据类型找,这个时候找到了两个bean,再根据myService这个名称找,发现没有,会直接报错。

@Bean

public MyService myService1 {

}

@Bean

public MyService myService2 {

}

 2、对于@Resource

错误情况:

1、按照名称找没有符合的,再按照类型找多个符合

2、按照名称找多个符合的,但是按照类型找没有符合的
《没有多个,多个没有》

如果这样注入

@Resouce

private MyService myService;   会报错

因为是根据名称找没找到,再根据类型找,没有找到。就会报错
 

@Bean

public MyService myService1 {

}

@Bean

public MyService myService2 {

}

四、#{}${}的区别

1. #{} 占位符

#{}预编译时的占位符,它的作用是将传入的参数作为参数值,而不是作为 SQL 字符串的一部分。这种占位符使用预编译机制,能够防止 SQL 注入。

  • 使用场景:一般用于 MyBatis 中处理 SQL 参数绑定。
  • 预编译#{} 占位符会在预编译时自动转换为占位符 (?),并将参数安全地绑定到 SQL 语句中。
  • SQL 安全:由于 MyBatis 在执行 SQL 语句时,会使用预编译语句,所以能防止 SQL 注入。

示例

// MyBatis SQL 查询

SELECT * FROM users WHERE id = #{id}

假设 id 是用户传入的值为 5,则最终执行的 SQL 语句会是:

SELECT * FROM users WHERE id = ?

并且 MyBatis 会安全地将 id5 绑定到 ? 处。

2、${} 占位符

${}字符串替换的占位符,它会将传入的参数直接嵌入到 SQL 语句中,不会进行预编译。由于是直接拼接在 SQL 语句中,因此存在 SQL 注入的风险。

  • 使用场景:适用于 MyBatis 或 Spring 的动态拼接场景,但要小心 SQL 注入风险。
  • 动态 SQL 拼接${} 会在运行时将参数直接替换为对应的值,用于拼接 SQL 语句。
// MyBatis SQL 查询
SELECT * FROM ${tableName}


转化为
SELECT * FROM users

五、mybatisplus相比于mybatis有什么优势

MyBatis-Plus 相比 MyBatis 具有以下几个明显的优势:

1. 简化的 CRUD 操作

  • MyBatis:需要手动编写 SQL 语句,定义复杂的 XML 映射文件,手动映射结果集与实体类,工作量较大。
  • MyBatis-Plus:提供了内置的基础 CRUD 方法,如 insertdeleteupdateselect 等操作,减少了大量的重复代码,开发效率更高。只需继承 BaseMapper 接口即可实现常见的数据库操作,无需编写 SQL。

2. 内置分页功能

  • MyBatis:分页需要自己编写 SQL,或者通过分页插件(如 PageHelper)来实现,操作步骤较为繁琐。
  • MyBatis-Plus:提供了分页插件,只需要简单配置即可使用内置的分页功能,配合 IPage 接口,分页变得更加简单。

3. 代码生成器

  • MyBatis:需要手动编写实体类、Mapper 接口、Mapper XML 文件,工作量大,容易出错。
  • MyBatis-Plus:提供代码生成器工具,可以根据数据库表自动生成实体类、Mapper、Service 等代码,极大提高开发效率,减少出错的可能。

4. Lambda 表达式支持

  • MyBatis:如果查询条件较多,SQL 复杂度增加,维护 SQL 变得困难。
  • MyBatis-Plus:支持 Lambda 表达式编写查询条件,避免了直接拼接字符串的风险,使代码更加简洁和安全,尤其适合动态条件查询的场景。

5. 条件构造器

  • MyBatis:动态条件查询时需要自己拼接 SQL 或使用脚本标签,如 <if><where> 标签。
  • MyBatis-Plus:提供 Wrapper 条件构造器,通过链式调用可以轻松构建复杂查询条件,简化了代码,避免了手动拼接 SQL 出现的各种问题。

6. 乐观锁和逻辑删除

  • MyBatis:实现乐观锁和逻辑删除需要手动编写 SQL 和处理逻辑,容易遗漏和出错。
  • MyBatis-Plus:内置了乐观锁和逻辑删除的实现,只需在实体类中配置相应的注解,即可自动支持这些功能,减少了额外的开发工作。

7. 多租户支持

  • MyBatis:多租户架构下的 SQL 处理需要开发者自行处理,难度较大。
  • MyBatis-Plus:内置多租户插件,能够在 SQL 层面支持多租户架构,减少开发者的工作量。

8. 插件扩展机制

  • MyBatis:虽然支持插件,但 MyBatis-Plus 的插件机制更为丰富。
  • MyBatis-Plus:支持非常灵活的插件机制,官方提供了很多有用的插件,如性能分析插件、SQL 执行分析插件等,开发者也可以自定义插件以满足特殊需求。

9. 更加活跃的社区和文档支持

  • MyBatis-Plus 拥有丰富的文档、教程和活跃的社区,相比 MyBatis 来说,开发者在遇到问题时可以更容易地找到帮助和解决方案。

六、ApplicationContext和beanFacrtory有什么区别

ApplicationContextBeanFactory 是 Spring 框架中用于管理和配置 beans 的两种容器,它们的区别主要体现在功能和使用场景上:

1. 功能差异

  • BeanFactory:是 Spring 容器的基础接口,只提供最基本的依赖注入功能。它主要负责创建和管理 beans 的实例。BeanFactory 在加载配置文件时并不会立即实例化所有的 bean,只有在首次使用(延迟加载,Lazy Initialization)时才会创建实例。
  • ApplicationContextBeanFactory 的子接口,扩展了它的功能。除了具备 BeanFactory 的所有功能外,ApplicationContext 还提供了更多面向企业级应用的特性,例如:
    • 事件机制:允许发布和监听应用事件(如上下文刷新事件)。
    • 国际化支持:提供消息资源处理(国际化,I18N 支持)。
    • 统一的资源加载:支持从各种不同的资源(如文件系统、类路径、URL)中加载配置文件。
    • 自动 bean 初始化ApplicationContext 启动时会立即实例化所有的单例 bean,而不是等到它们第一次被使用时再进行实例化(即预加载)。

2. 加载时机

  • BeanFactory:通常采用 Lazy Initialization 的方式加载 bean,只有当应用代码通过 getBean() 方法请求 bean 时,才会创建该 bean 的实例。这种方式节省了内存,但如果某个 bean 在启动时就有问题,直到使用时才会发现。
  • ApplicationContext:在容器启动时即加载并实例化所有单例 bean(预加载)。这样做的好处是可以在容器启动时发现配置错误或依赖问题,有利于提早排查问题。

3. 额外特性

  • BeanFactory:相对轻量,没有像 ApplicationContext 那样提供事件、国际化、资源文件等扩展特性。如果应用程序只需要基本的 IOC 功能,BeanFactory 足够使用,但它不支持更复杂的企业级功能。
  • ApplicationContext
    • 事件机制:支持发布和监听 ApplicationEvent,如上下文启动、停止、刷新等事件。
    • 国际化:支持 MessageSource 接口,方便开发多语言环境下的应用。
    • AOPApplicationContext 更好地支持 AOP(面向切面编程),如基于注解的事务管理。

4. 使用场景

  • BeanFactory:适用于资源有限的场景,或者简单的应用程序,比如在移动设备上或需要节省内存的情况下。由于它没有预加载单例 bean 的功能,启动开销较小。
  • ApplicationContext:在现代 Spring 应用中更为常用,特别是复杂的、企业级的应用。ApplicationContext 提供了更多功能和易用性,适合大部分开发场景。

5. 常见实现类

  • BeanFactory:其常见的实现类是 XmlBeanFactory,不过它在较新的 Spring 版本中已经被弃用,推荐使用 ApplicationContext
  • ApplicationContext:常用的实现类有:
    • ClassPathXmlApplicationContext:从类路径下的 XML 配置文件加载 bean 定义。
    • FileSystemXmlApplicationContext:从文件系统中的 XML 配置文件加载 bean 定义。
    • AnnotationConfigApplicationContext:通过注解加载配置类(常用于无 XML 配置的 Java 配置模式)。

七、springboot中配置文件的加载顺序是怎么样的

在 Spring Boot 中,配置文件的加载顺序按照以下优先级进行。较高优先级的配置会覆盖较低优先级的配置:

  1. application.propertiesapplication.yml 文件

    • /config 子目录下的文件(如:config/application.propertiesconfig/application.yml)具有比根目录下的配置文件更高的优先级。
    • 根目录下的文件(如:application.propertiesapplication.yml)。
  2. 命令行参数

    • 可以通过命令行传递的配置参数,例如 --server.port=8081
  3. @TestPropertySource 注解

    • 如果使用了该注解来为测试类指定额外的属性,则这些属性会覆盖其他源的配置。
  4. @PropertySource 注解

    • 在类中使用该注解加载的属性文件具有较高的优先级。
  5. 操作系统环境变量

    • 通过操作系统环境变量提供的配置值,优先级高于大多数配置文件。
  6. Java 系统属性

    • 使用 JVM 参数传递的属性(例如:-Dserver.port=8081)优先级高于默认配置文件。
  7. random.* 属性

    • 例如 random.uuid,Spring Boot 提供了生成随机数、随机UUID等属性的能力,优先级高于配置文件中的默认值。
  8. application.propertiesapplication.yml 文件中定义的默认配置

  9. Spring Boot 默认配置

    • 例如默认的端口是 8080,日志级别是 INFO

配置文件的加载顺序总结:

  • 命令行参数 > 测试类配置 > 类级别注解配置 > 环境变量 > Java系统属性 > /config 子目录的配置文件 > 根目录的配置文件 > Spring Boot 默认配置

通过这种机制,Spring Boot 允许你根据不同的运行环境和需求灵活地配置和覆盖默认值。

补充:springcloud的几个配置文件执行规则

加载顺序

  • bootstrap.yml / bootstrap.properties
    • 这个文件首先被加载,通常用于加载与 Spring Cloud 相关的设置,如服务发现、配置中心等。
  • application.yml / application.properties
    • bootstrap 文件加载后,application 文件被加载,主要用于应用的常规配置。
  • Nacos 配置
    • 从 Nacos 加载的配置会在 application.yml 加载之后进行,此时可以覆盖 application.yml 中的同名配置项。

后面的覆盖前面

示例

假设有以下配置:

  • bootstrap.yml: app.name: BootstrapApp
  • application.yml: app.name: ApplicationApp
  • Nacos 配置: app.name: NacosApp
  • 命令行参数: --app.name=CommandLineApp

最终的应用配置将是:

  • app.name = CommandLineApp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值