Spring面试题

IOC是什么

  1. 控制反转,自己吃饭,告诉仆人自己喜欢吃什么菜,被人喂饭
  2. 本质就是一个工厂模式

IOC的优点

  1. 没有IOC

    • 依赖StudentService,需要自己创建出来

      StudentService studentService = new StudentService();
      
    • 常规的开发中有大量的依赖,手动创建麻烦且不宜管理

  2. 有了IOC

    • 通过配置文件配置所有对象的信息,对象都可以通过加载入IOC来托管

    • 非特殊逻辑的可以使用scan直接扫描包

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="studentService" class="com.vission.service.StudentService" init-method="init" destroy-method="destroy" scope="prototype">
              <constructor-arg name="studentDao" ref="studentDao"/>
          </bean>
          <bean id="studentDao" class="com.vission.dao.StudentDao"/>
      </beans>
      
    • 依赖StudentService,直接从IOC容器里面取

      StudentService studentService = (StudentService)beanFactory.getBean("StudentService");
      
    • 封装对象的一些常用且易冗余的代码

      • 单例模式
      • 生命周期
        • init
        • destory
    • 对象创建时自动注入所需的依赖

  3. 通过上述分析,可以看出,IOC,只要一次配置,剩下可以托管给IOC,开发者再无需关心对象的创建、销毁的细节,也无需担心原型模式浪费内存,甚至所需对象的依赖也可以隐藏在工厂模式下无需关心

什么是依赖注入

  1. 描述所需依赖,无需自己手动创建,由IOC自动创建组装
  2. 告诉仆人喜欢吃的菜需要怎么做

Spring Bean装配

根据依赖关系将Bean通过构造器注入、setter注入进行装配,并放入IOC容器中

Spring Bean自动装配

根据依赖关系,自动搜寻IOC容器中的Bean进行装配,搜寻的方式有两种

  1. ByName
  2. ByType

再通过构造函数或是set注入

@Required的作用

初始化必须setter方法,否则抛出bean初始化异常

已弃用无需深究

自动装配的局限性

不知道,平时都用lombok配合构造函数注入,idea弹警告就很少用这玩意了

依赖注入的方式

  1. 构造器

    • 手动写构造器

    • @lombok

      • @RequiredArgsConstructor
        • final修饰
        • 无初始值
      • @AllArgsConstructor
        • 所有属性的构造函数
    • bean.xml constructor-arg

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="studentService" class="com.vission.service.StudentService">
              <constructor-arg name="studentDao" ref="studentDao"/>
          </bean>
          <bean id="studentDao" class="com.vission.dao.StudentDao"/>
      </beans>
      
  2. setter

    • 手动写Set方法

    • @lombok

      • @Setter
      • @Data
    • bean.xml property

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean id="studentService" class="com.vission.service.StudentService">
              <property name="studentDao" ref="studentDao"/>
          </bean>
          <bean id="studentDao" class="com.vission.dao.StudentDao"/>
      </beans>
      

Spring中常用的IOC容器

  1. BeanFactory
  2. Application

BeanFactory与ApplicationContext的关系

Application继承自BeanFactory且扩展了很多方法,简而言之就是增强版的BeanFactroy

  1. 国际化

Spring IOC实现机制

  1. 工厂模式
    • 隐藏构造细节
  2. 反射
    • 通过全限定路径反射,可以做到弱依赖

JavaBean、POJO、SpringBean区别

  1. POJO
    • 具有所有属性皆为private
    • 所有属性都具有public的get、set方法
    • 无继承、 实现
  2. JavaBean
    • 无参构造函数
    • 实现序列化接口 Serializable
  3. SpringBean
    • SpringIOC管理的对象即为SpringBean

BeanWrapper

  1. SpringFramework提供的一个用于操作JavaBean属性的工具

  2. 提供Spring内部统一使用get,set方法

  3. 更新-拷贝场景

    • 将一个对象存储a的值赋值到另一个对象b,且a中属性为null的不进行赋值
    • BeanUtils#copy方法中可以使用BeanWrapper获取全部的字段并判空过滤
    • Spring提供的copy方法是可以忽略属性为空的字段,将上个步骤处理的结果带入即可
 /**
     * 拷贝source属性覆盖target属性(忽略null)
     *
     * @param <S>    the type parameter
     * @param <T>    the type parameter
     * @param source 源对象
     * @param target 目标对象类型
     */
    public static <S, T> void copyIgnoreNull(S source, T target) {
        try {
            String[] nullPropertyNames = ObjectUtils.getPropertyNamesByValueNull(source).toArray(new String[0]);
            org.springframework.beans.BeanUtils.copyProperties(source, target, nullPropertyNames);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
       }
   
    /**
     * 获取对象为空的属性名集合
     *
     * @param source 对象
     * @return 属性集合 string [ ]
     */
    public static List<String> getPropertyNamesByValueNull(Object source) {
        return ObjectUtils.traverseAllPropertyNames(source, Objects::isNull);
    }
   
    /**
     * 获取对象为空的属性名集合
     *
     * @param source 对象
     * @return 属性集合 string [ ]
     */
    private static List<String> traverseAllPropertyNames(Object source, Function<Object, Boolean> filterStrategy) {
        BeanWrapper beanWrapper = new BeanWrapperImpl(source);
        PropertyDescriptor[] properties = beanWrapper.getPropertyDescriptors();
        return Arrays.stream(properties).map(PropertyDescriptor::getName)
                .map(beanWrapper::getPropertyValue)
                .filter(Objects::nonNull)
                .map(Object::toString)
                .filter(filterStrategy::apply)
                .collect(Collectors.toList());
    }

Spring的配置方式

  1. XML

  2. 注解声明

    • @Controller、@Service、@Component、@Repository…
  3. 基于Java的配置类

    package com.vission.config;
                         
    import com.vission.dao.StudentDao;
    import com.vission.service.StudentService;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
                         
    @Configuration
    public class BeanConfig implements ApplicationContextAware {
                         
        private ApplicationContext context;
                         
        @Bean(name = "studentService")
        public StudentService studentService() {
            return new StudentService((StudentDao) context.getBean("studentDao"));
        }
                         
        @Bean(name = "studentDao")
        public StudentDao studentDao() {
            return new StudentDao();
        }
                         
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            context = applicationContext;
        }
    }
                         
    

如何在Spring中启动注解装配

  1. XML

    • annotation-config用的较少,更加专注于@Component注解的类

      • 默认扫描项目所在的根路径比如com.vission.study.*
    • context-component-scan会扫描指定路径下的类,并将使用了@Component注解的类注册为SpringBean,实际上会默认开启了annotation-config,这也是在实际开发中最通用的办法

  2. @ComponentScan(basePackages = “”)

    • @ComponentScan可以不指定路径使用默认路径

SpringBean的Scope

  1. Singleton
    • 单例
  2. Prototype
    • 原型
  3. Request
    • 每次请求产生一个新实例 并且只在此HTTP中生效
  4. Session
    • 每次请求产生一个新示例 并且只在此HTTP Session中生效
  5. Global-session
    • 不太了解chatGPT说不存在这个东西

SpringBean的生命周期

  1. 实例化
  2. 属性注入
    • 依赖注入
  3. 各种回调函数注入
  4. 初始化
    • @PostConstruct注解标注初始方法
    • 实现InitializingBean接口的初始化方法
    • 配置Bean的Init-method
  5. 销毁
    • @PreDestroy注解标注销毁方法
    • 实现DisposableBean接口的销毁方法
    • 配置Bean的destroy-method
  6. 原型类型的Bean无法通过IOC管理销毁,因为他是由JVM管理销毁

Spring中单例Bean是否线程安全

  1. 单例非线程安全
  2. 无状态Bean
    • bean中不存数据
    • 大部分丢给IOC管理的Bean多半是service controller等,这些只是调用方法,对象内部不涉及存储数据的改变,所以不存在考虑线程安全
  3. 有状态Bean
    • bean中存放数据
    • 如果硬要存放数据考虑安全性。需要将作用域改为原型模式,这样每次都会新建实例

Spring支持的事务管理类型

  1. 编程式事务管理
    • 通过使用事务API ,手写事务代码来实现事务功能
    • 业务代码与事务代码耦合
  2. 声明式事务管理
    • 使用@Transaction注解

静态代理与动态代理的区别

  1. 静态代理

    • 手写的代理模式

  2. 动态代理

    • 顾名思义动态生成代理类实现代理模式
    • 动态生成一个proxyXXX.class实现代理的功能
    • 常用的思路有CGLIB,JDK代理,SpringAop也是通过这两种方式实现,具体底层逻辑我也不是很了解

Spring是如何集成MyBatis

  1. 注解配置

    package com.vission.config;
          
    import javax.sql.DataSource;
    import lombok.AllArgsConstructor;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
          
    @Configuration
    @AllArgsConstructor
    @MapperScan("com.vission.mapper")
    public class MyBatisConfig {
          
        private DataSource dataSource;
          
        @Bean(name = "sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSource);
            Resource[] mapperResources = new PathMatchingResourcePatternResolver().getResources(
                    "classpath:mapper/**/*.xml");
            sqlSessionFactoryBean.setMapperLocations(mapperResources);
            sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
            return sqlSessionFactoryBean.getObject();
        }
    }
          
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <setting name="cacheEnabled" value="true"/>
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/>
            <setting name="multipleResultSetsEnabled" value="true"/>
            <setting name="useColumnLabel" value="true"/>
            <setting name="useGeneratedKeys" value="false"/>
            <setting name="autoMappingBehavior" value="PARTIAL"/>
            <setting name="defaultExecutorType" value="SIMPLE"/>
            <setting name="defaultStatementTimeout" value="25000"/>
            <setting name="mapUnderscoreToCamelCase" value="false"/>
        </settings>
    </configuration>
    

Spring如何将Mybatis的mapper扫描成为Bean的

@MapperScan(“com.vission.mapper”)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值