Spring面试题及详细答案 125道(16-25) -- 核心概念与基础2

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

一、本文面试题目录

16. 什么是Spring的自动装配?有哪些自动装配模式?

  • 定义:Spring的自动装配是指容器在创建Bean时,根据特定规则自动识别并注入该Bean所依赖的其他Bean,无需开发者在配置中显式声明依赖关系,从而减少配置工作量。
  • 自动装配模式
    • no(默认):不启用自动装配,需手动通过<property>@Autowired等方式配置依赖。
    • byName:根据属性名自动匹配容器中同名的Bean(如属性名为userDao,则匹配id="userDao"的Bean)。
      <bean id="userService" class="com.example.UserService" autowire="byName"/>
      <bean id="userDao" class="com.example.UserDao"/> <!-- 与属性名匹配 -->
      
    • byType:根据属性类型自动匹配容器中同类型的Bean,若存在多个同类型Bean会抛出异常。
      <bean id="userService" class="com.example.UserService" autowire="byType"/>
      <bean class="com.example.UserDao"/> <!-- 与属性类型匹配 -->
      
    • constructor:类似byType,但用于构造器参数,根据参数类型匹配依赖的Bean。
    • autodetect(已过时):优先尝试constructor,失败则使用byType

17. 如何禁用Spring的自动装配?

  • XML配置:在<bean>标签中显式设置autowire="no"(默认值),或全局禁用自动装配:
    <!-- 单个Bean禁用 -->
    <bean id="userService" class="com.example.UserService" autowire="no"/>
    
    <!-- 全局禁用(仅适用于Spring旧版本) -->
    <beans default-autowire="no">...</beans>
    
  • 注解配置
    • 不使用@Autowired@Resource等自动装配注解,手动通过@Bean方法参数注入依赖。
    • 对类添加@Autowired(required = false)并结合@Qualifier强制指定依赖(本质是控制装配而非禁用)。
  • Java配置类:通过@Bean方法显式声明依赖,不依赖容器自动注入:
    @Configuration
    public class AppConfig {
        @Bean
        public UserService userService() {
            UserService service = new UserService();
            service.setUserDao(userDao()); // 手动注入
            return service;
        }
        
        @Bean
        public UserDao userDao() {
            return new UserDao();
        }
    }
    

18. Spring中的@Qualifier注解的作用是什么?

  • 作用:当容器中存在多个同类型的Bean时,@Qualifier用于指定具体要注入的Bean名称,解决@Autowired按类型自动装配的歧义问题。
  • 使用场景:配合@Autowired使用,明确依赖的Bean标识。
    @Service
    public class UserService {
        // 容器中存在多个UserDao类型的Bean(如userDaoImpl1、userDaoImpl2)
        @Autowired
        @Qualifier("userDaoImpl1") // 指定注入id为userDaoImpl1的Bean
        private UserDao userDao;
    }
    
  • XML配置对应方式:通过<qualifier>标签指定:
    <bean id="userService" class="com.example.UserService">
        <property name="userDao">
            <qualifier value="userDaoImpl1"/>
        </property>
    </bean>
    

19. 什么是Spring的事件机制?请举例说明。

  • 定义:Spring的事件机制基于观察者模式,允许Bean通过发布事件(Event)和监听事件(Listener)实现松耦合通信。核心组件包括:
    • ApplicationEvent:事件基类,自定义事件需继承此类。
    • ApplicationListener:事件监听器接口,或使用@EventListener注解。
    • ApplicationEventPublisher:事件发布器,由容器自动注入。
  • 示例
    1. 定义自定义事件
      public class OrderCreatedEvent extends ApplicationEvent {
          private String orderId;
          
          public OrderCreatedEvent(Object source, String orderId) {
              super(source);
              this.orderId = orderId;
          }
          
          public String getOrderId() {
              return orderId;
          }
      }
      
    2. 创建事件监听器
      @Component
      public class OrderListener {
          // 方式1:实现ApplicationListener接口
          @Component
          public static class OrderCreatedListener implements ApplicationListener<OrderCreatedEvent> {
              @Override
              public void onApplicationEvent(OrderCreatedEvent event) {
                  System.out.println("监听订单创建:" + event.getOrderId());
              }
          }
          
          // 方式2:使用@EventListener注解(推荐)
          @EventListener
          public void handleOrderEvent(OrderCreatedEvent event) {
              System.out.println("处理订单:" + event.getOrderId());
          }
      }
      
    3. 发布事件
      @Service
      public class OrderService {
          @Autowired
          private ApplicationEventPublisher publisher;
          
          public void createOrder(String orderId) {
              // 业务逻辑...
              publisher.publishEvent(new OrderCreatedEvent(this, orderId));
          }
      }
      

20. Spring中的BeanPostProcessor有什么作用?如何使用?

  • 作用BeanPostProcessor是Spring的后置处理器接口,用于在Bean初始化前后对其进行增强或修改,是AOP实现的基础机制之一。
  • 核心方法
    • postProcessBeforeInitialization:在Bean初始化方法(如@PostConstructafterPropertiesSet)执行前调用。
    • postProcessAfterInitialization:在Bean初始化方法执行后调用。
  • 使用示例:对Bean进行属性加密处理
    @Component
    public class EncryptBeanPostProcessor implements BeanPostProcessor {
        // 初始化前处理
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof User) {
                User user = (User) bean;
                user.setPassword(encrypt(user.getPassword())); // 加密密码
            }
            return bean;
        }
        
        // 初始化后处理(可返回代理对象实现AOP)
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
        
        private String encrypt(String password) {
            // 加密逻辑...
            return password + "_encrypted";
        }
    }
    
  • 注意BeanPostProcessor会作用于容器中所有Bean,可通过beanName或类型判断进行针对性处理。

21. Spring中的FactoryBean和BeanFactory有什么区别?请举例说明FactoryBean的应用场景。

  • 区别

    特性FactoryBeanBeanFactory
    本质是一个Bean,用于创建复杂对象是IoC容器接口,管理所有Bean
    作用自定义Bean的创建逻辑负责Bean的注册、实例化、依赖注入
    接口方法getObject()返回实际对象getBean()获取容器中的Bean
  • FactoryBean示例:创建数据库连接池(复杂对象)

    public class DataSourceFactoryBean implements FactoryBean<DataSource> {
        private String url;
        private String username;
        private String password;
        
        // 设置配置参数
        public void setUrl(String url) { this.url = url; }
        public void setUsername(String username) { this.username = username; }
        public void setPassword(String password) { this.password = password; }
        
        // 自定义对象创建逻辑
        @Override
        public DataSource getObject() throws Exception {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
        
        @Override
        public Class<?> getObjectType() {
            return DataSource.class;
        }
    }
    
  • 配置与使用

    <bean id="dataSource" class="com.example.DataSourceFactoryBean">
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
    // 获取的是FactoryBean创建的DataSource对象,而非FactoryBean本身
    DataSource dataSource = context.getBean("dataSource", DataSource.class);
    
  • 应用场景

    • 创建复杂对象(如连接池、线程池、MyBatis的SqlSessionFactory)。
    • 隐藏对象创建细节,简化配置。
    • 动态生成代理对象(如AOP代理)。

22. 什么是Spring的占位符配置(如${})?如何解析?

  • 定义:占位符配置(${key})允许在Spring配置中使用外部化参数(如配置文件、环境变量),实现配置与代码分离,便于多环境部署。
  • 解析方式
    1. 基于XML配置:通过PropertyPlaceholderConfigurercontext:property-placeholder标签:
      <!-- 引入配置文件 -->
      <context:property-placeholder location="classpath:db.properties"/>
      
      <!-- 使用占位符 -->
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
          <property name="url" value="${db.url}"/>
          <property name="username" value="${db.username}"/>
      </bean>
      
    2. 基于注解配置:结合@PropertySource@Value
      @Configuration
      @PropertySource("classpath:db.properties") // 加载配置文件
      public class DataSourceConfig {
          @Value("${db.url}")
          private String url;
          
          @Value("${db.username}")
          private String username;
          
          @Bean
          public DataSource dataSource() {
              DruidDataSource dataSource = new DruidDataSource();
              dataSource.setUrl(url);
              dataSource.setUsername(username);
              return dataSource;
          }
      }
      
    3. Spring Boot自动解析:默认加载application.propertiesapplication.yml,直接使用@Value("${key}")注入。
  • 注意:若占位符未找到对应值,可通过default-value设置默认值:${db.url:jdbc:mysql://localhost:3306/test}

23. Spring中如何处理循环依赖?三级缓存的作用是什么?

  • 循环依赖:指两个或多个Bean相互依赖(如A依赖B,B依赖A)。Spring通过三级缓存解决单例Bean的循环依赖,原型Bean无法解决(会抛出异常)。
  • 三级缓存
    1. 一级缓存(singletonObjects):存储完全初始化完成的单例Bean。
    2. 二级缓存(earlySingletonObjects):存储提前暴露的未完全初始化的Bean实例(原始对象或代理对象)。
    3. 三级缓存(singletonFactories):存储Bean的工厂对象(ObjectFactory),用于延迟创建代理对象。
  • 处理流程
    1. 创建A时,先将A的工厂对象放入三级缓存,再注入依赖B。
    2. 创建B时,注入依赖A,此时从三级缓存获取A的工厂,生成A的早期实例(放入二级缓存),并注入B。
    3. B初始化完成后,注入A,A继续完成初始化,最终放入一级缓存。
  • 代码验证
    @Service
    public class A {
        @Autowired
        private B b; // A依赖B
    }
    
    @Service
    public class B {
        @Autowired
        private A a; // B依赖A
    }
    
    上述代码可正常运行,Spring通过三级缓存解决了循环依赖。
  • 注意:构造器注入的循环依赖无法解决(因构造器执行前无法暴露实例),需改为setter注入。

24. @Value注解的作用是什么?如何使用它注入配置文件中的值?

  • 作用@Value注解用于将外部值(配置文件、系统变量、SpEL表达式等)注入到Bean的字段或方法参数中。
  • 使用方式
    1. 注入配置文件值
      # application.properties
      app.name=MyApp
      app.version=1.0.0
      
      @Component
      public class AppConfig {
          @Value("${app.name}")
          private String appName;
          
          @Value("${app.version:2.0.0}") // 设默认值
          private String appVersion;
      }
      
    2. 注入系统变量或环境变量
      @Value("${user.home}") // 系统变量
      private String userHome;
      
      @Value("${JAVA_HOME}") // 环境变量
      private String javaHome;
      
    3. 注入SpEL表达式结果
      @Value("#{T(java.lang.Math).random() * 100}") // 随机数
      private double randomValue;
      
      @Value("#{systemProperties['os.name']}") // 系统属性
      private String osName;
      
    4. 注入Bean的属性
      @Component
      public class User {
          private String username = "admin";
          // getter
      }
      
      @Component
      public class UserService {
          @Value("#{user.username}") // 注入其他Bean的属性
          private String username;
      }
      

25. Spring中的@Profile注解有什么作用?如何通过它实现环境隔离?

  • 作用@Profile注解用于标识Bean在特定环境(如开发、测试、生产)下才会被注册到容器中,实现不同环境的配置隔离。
  • 使用方式
    1. 标记Bean或配置类
      // 开发环境的数据源
      @Configuration
      @Profile("dev")
      public class DevDataSourceConfig {
          @Bean
          public DataSource dataSource() {
              return new HikariDataSource(...); // 开发环境配置
          }
      }
      
      // 生产环境的数据源
      @Configuration
      @Profile("prod")
      public class ProdDataSourceConfig {
          @Bean
          public DataSource dataSource() {
              return new HikariDataSource(...); // 生产环境配置
          }
      }
      
    2. 激活环境
      • XML配置<context:property-placeholder profile="dev"/>
      • Java启动参数-Dspring.profiles.active=dev
      • 代码激活
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("dev"); // 激活dev环境
        context.register(AppConfig.class);
        context.refresh();
        
    3. 默认环境:使用@Profile("default")标识默认激活的Bean,当未指定环境时生效。
  • 优势:避免在不同环境切换时修改配置文件,通过激活不同Profile即可加载对应环境的Bean。

二、125道Spring面试题目录列表

文章序号Spring面试题125道
1Spring面试题及详细答案125道(01-15)
2Spring面试题及详细答案125道(16-25)
3Spring面试题及详细答案125道(26-45)
4Spring面试题及详细答案125道(46-65)
5Spring面试题及详细答案125道(66-75)
6Spring面试题及详细答案125道(76-90)
7Spring面试题及详细答案125道(91-110)
8Spring面试题及详细答案125道(111-125)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还是大剑师兰特

打赏一杯可口可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值