一、语雀-Spring面试题
1、介绍一下Spring的IOC
2、介绍一下Spring的AOP
1. AOP是如何实现的?
3、为什么Spring不建议使用基于字段的依赖注入?
1. 可能产生NPE
2. Spring支持哪些注入方式
4、Spring Bean的生命周期是怎么样的?
5、Spring Bean的初始化过程是怎么样的?
1. 实例化 Bean(Instantiation)
Spring 容器通过 BeanFactory 或 ApplicationContext 加载配置元数据(如 XML、注解或 Java Config),根据 BeanDefinition 中的信息(如类名、作用域等)通过反射调用构造方法创建 Bean 实例。若 Bean 定义了工厂方法(factory-method),则通过工厂方法实例化。此阶段仅完成对象创建,未进行依赖注入。
2. 填充属性(Population of Properties)
实例化后,Spring 根据 BeanDefinition 的依赖关系,通过依赖注入(DI)为 Bean 的属性赋值。若属性是简单类型(如 int、String),则直接注入值;若是引用类型,则需从容器中查找匹配的 Bean 完成注入。此阶段会处理 @Autowired、@Resource 等注解,或 XML 配置的 <property> 标签。
3. 处理 Aware 接口回调(Aware Callbacks)
若 Bean 实现了特定 Aware 接口(如 BeanNameAware、BeanFactoryAware、ApplicationContextAware),Spring 容器会在初始化前回调对应方法,将容器相关信息(如 Bean 名称、容器引用)注入 Bean。例如:
• setBeanName(String name):传递 Bean 的名称。
• setApplicationContext(ApplicationContext context):传递应用上下文引用。
4. 执行 BeanPostProcessor 的前置处理(Before Initialization)
Spring 容器遍历所有注册的 BeanPostProcessor,执行其 postProcessBeforeInitialization(Object bean, String beanName) 方法。开发者可自定义 BeanPostProcessor 在此处对 Bean 进行修改(如属性加密、代理增强)。典型应用:CommonAnnotationBeanPostProcessor 处理 @PostConstruct。
5. 执行初始化方法(Initialization)
Bean 进入核心初始化阶段:
• 若 Bean 实现了 InitializingBean 接口,调用其 afterPropertiesSet() 方法。
• 若配置了 init-method(XML)或 @Bean(initMethod = "..."),则调用指定方法。
• 若使用注解 @PostConstruct,则触发该方法。
此阶段完成业务逻辑的最终初始化(如数据库连接池初始化)。
6. 执行 BeanPostProcessor 的后置处理(After Initialization)
再次遍历所有 BeanPostProcessor,执行 postProcessAfterInitialization(Object bean, String beanName) 方法。常用于 AOP 代理生成(如 AnnotationAwareAspectJAutoProxyCreator 在此处为目标 Bean 创建动态代理)。
7. Bean 初始化完成(Bean is Ready)
至此,Bean 完成全部初始化流程,被注册到 Spring 容器中,供其他组件通过依赖注入或 getBean() 方法获取。若 Bean 是原型作用域(prototype),每次请求都会新建实例;单例(singleton)则缓存于容器。
8. 总结
Spring Bean 初始化流程可概括为:实例化 → 依赖注入 → Aware 回调 → BeanPostProcessor 前置处理 → 初始化方法 → BeanPostProcessor 后置处理。开发者可通过实现接口或自定义 BeanPostProcessor 扩展各阶段逻辑。
6、@PostConstruct、init-method和afterPropertiesSet执行顺序
✅@PostConstruct、init-method和afterPropertiesSet执行顺序
7、Spring的事务传播机制有哪些?
1. 场景题
8、Autowired和Resource的关系?
1、byName和byType匹配顺序不同
2、作用域,支持方,默认要求不同
9、BeanFactory和FactroyBean的关系?
FactoryBean是Spring中用于创建复杂Bean的工厂接口,其本身是一个Bean,但主要作用是生成并返回由它创建的Bean实例;而BeanFactory是Spring IoC容器的核心接口,负责管理容器中所有Bean的生命周期和依赖注入,是真正管理Bean的工厂。简言之,FactoryBean是生产特定Bean的"专用工厂",而BeanFactory是管理整个Bean生态的"总工厂"。
1. BeanFactory
2. FactoryBean
10、Spring在业务中常见的使用方式
1. 通过IOC实现策略模式
2. 通过AOP实现拦截
很多时候,我们一般是通过注解和AOP相结合。大概的实现思路就是先定义一个注解,然后通过AOP去发现使用过该注解的类,对该类的方法进行代理处理,增加额外的逻辑,譬如参数校验,缓存,日志打印等等,如下代码所示:
11、Spring中如何开启事务?
1. 声明式事务(推荐)
声明式事务通过注解或XML配置实现,无需手动编写事务管理代码,由Spring框架自动代理完成。
• 启用事务管理:在Java配置类中使用@EnableTransactionManagement注解,或在XML配置中添加<tx:annotation-driven/>标签,激活Spring对@Transactional注解的支持。
• 配置事务管理器:根据数据访问技术选择对应的事务管理器(如DataSourceTransactionManager用于JDBC),并通过Spring容器将其注册为Bean,确保事务功能依赖注入。
• 使用@Transactional注解:在Service层的方法或类上添加@Transactional,声明该方法需要事务管理。Spring会自动为该方法开启事务,并在方法成功执行后提交事务,若抛出异常则回滚。
2. 编程式事务(不常用)
编程式事务需要手动编写事务管理逻辑,灵活性高但代码侵入性强,通常用于复杂场景。
• 使用TransactionTemplate:通过注入TransactionTemplate,调用其execute()方法包裹数据库操作,在回调函数中编写具体逻辑。事务的提交或回滚由模板自动处理。
• 使用PlatformTransactionManager:直接通过事务管理器手动控制事务边界,例如调用beginTransaction()、commit()、rollback()方法,适用于需要精细控制事务的场景。
3. 关键注意事项
• 事务生效条件:@Transactional必须标注在public方法上,且方法调用需通过Spring代理(如通过其他Bean注入调用,而非内部直接调用)。
• 事务传播行为:通过propagation属性定义事务传播规则(如REQUIRED表示加入当前事务,REQUIRES_NEW表示新建独立事务),默认值为REQUIRED。
• 回滚规则:默认情况下,仅未检查异常(RuntimeException及其子类)会触发回滚。可通过rollbackFor指定特定异常触发回滚(如rollbackFor=Exception.class),或通过noRollbackFor排除某些异常的回滚。
• 只读事务优化:若方法仅执行查询操作,可设置readOnly=true,数据库可能对这类事务进行性能优化(如MySQL的MVCC机制)。
12、Spring中用到了哪些设计模式
1. 工厂模式
2. 代理模式
3. 单例模式
4. 责任链模式
13、什么是Spring的循环依赖问题?
1. 为什么只支持单例
2. 为什么不支持构造函数注入
在这个例子中,ClassA 的构造器依赖 ClassB,但我们使用了 @Lazy 注解来标记这个依赖。这意味着 ClassB 的实例会在首次被实际使用时才创建,而不是在创建 ClassA 的实例时。这样,Spring容器可以先创建 ClassA 的实例(此时不需要立即创建 ClassB),然后创建 ClassB 的实例,最后解决 ClassA 对 ClassB 的依赖。
二、语雀-MySQL面试题
1、什么是InnoDB的页分裂和页合并
2、数据库乐观锁的过程中,完全没有加任何锁吗?
3、什么是数据库的主从延迟,如何解决?
4、 什么是事务的2阶段提交?
1. 二阶段如何保证一致性
5、介绍下MySQL 5.7中的组提交
6、MyISAM 的索引结构是怎么样的,它存在的问题是什么?
7、MySQL中like的模糊查询如何优化
1. MySQL中LIKE模糊查询的定义与基本用法
LIKE是MySQL中用于模糊匹配字符串的操作符,常用于WHERE子句中筛选符合特定模式的记录。它支持两种通配符:%匹配任意数量字符(包括零个),_匹配单个字符。例如,WHERE name LIKE 'A%'会匹配所有以"A"开头的名称,而WHERE email LIKE '%@example.com'可查找以"@example.com"结尾的邮箱。其核心是通过模式匹配实现非精确查询,适用于需要部分关键词检索的场景。
2. 性能问题的根源
LIKE模糊查询的性能问题主要集中在以%开头的模式(如LIKE '%keyword'),因为这类查询无法利用索引的有序性,导致全表扫描。即使对字段建立了索引,数据库引擎仍需逐行比对数据,当表数据量较大时,查询效率会显著下降。此外,若频繁执行此类查询,还会增加CPU和I/O资源的消耗,影响整体系统性能。
3. 优化策略一:避免前置通配符%
若业务允许,尽量避免在模式开头使用%。例如,将LIKE '%abc'改为LIKE 'abc%',此时索引可被有效利用,查询性能大幅提升。若必须使用前置通配符,可考虑反向存储数据(如将字符串反转后存入新字段),并通过LIKE 'cba%'的形式查询,间接利用索引。
4. 优化策略二:使用全文索引(FULLTEXT)
对于复杂的文本搜索需求,可使用MySQL的全文索引(FULLTEXT)。通过CREATE FULLTEXT INDEX创建索引后,结合MATCH(column) AGAINST('keyword')进行检索,其底层基于倒排索引实现,性能远高于LIKE。但需注意,FULLTEXT对短词(如少于4个字符)或停用词(如“的”“是”)可能失效,且仅支持InnoDB和MyISAM引擎。
5. 优化策略三:覆盖索引与索引选择性
若模糊查询的字段已被索引覆盖(即查询仅需访问索引而不回表),可减少磁盘I/O。例如,对name字段建立索引后,执行SELECT name FROM table WHERE name LIKE 'A%'时,可直接通过索引返回结果。此外,需评估索引的选择性:若字段重复值较多(如性别字段),索引效果有限,此时需权衡是否建立索引。
6. 优化策略四:限制查询范围
通过结合其他条件缩小查询范围,可降低全表扫描的开销。例如,在模糊查询前先通过时间范围(WHERE create_time > '2023-01-01')或精确匹配字段过滤数据,再执行LIKE操作。此方法能有效减少需要扫描的数据量,提升查询效率。
7. 优化策略五:使用外部搜索引擎
对于高并发或海量数据的模糊查询需求,建议采用专业搜索引擎(如Elasticsearch)。它们通过分词技术、倒排索引和分布式架构,支持高效复杂的文本检索,且扩展性强。虽然引入外部系统会增加架构复杂度,但对于性能瓶颈场景是长远解决方案。