zoukankan      html  css  js  c++  java
  • 面试总结-Spring


    一、Spring IOC的注入方式

    • xml配置申明注册:setter、构造器、工厂方法注入;
    • 注解方式申明注册:注解方式注
      参考

    1.构造器注入

    构造器单个参数
    <bean id="" class="">
    	<constructor-arg ref="beanId"></constructor-arg>
    </bean>
    构造器多个参数,下面写法是按照顺序注入到构造器中的
    <bean id="" class="">
    	<constructor-arg ref="beanId"></constructor-arg>
            <constructor-arg ref="beanId"></constructor-arg>
    </bean>
    构造器多个参数,当加上name属性,则与顺序无关
    <bean id="" class="">
    	<constructor-arg name="" ref="beanId"></constructor-arg>
            <constructor-arg name="" ref="beanId"></constructor-arg>
    </bean>
    

    2.set注入(三级缓存解决循环依赖)

    spring会将name值全部转成大写,然后在前面拼接上"set",然后去对应类找到该方法,通过反射调用实现注入。
    坑1:name属性值与类成员变量名无关系,但是和对应的set方法有关。
    坑2:通过set注入,会通过调用默认空参构造器。
    <!-- 注册userService -->
    <bean id="userService" class="com.lyu.spring.service.impl.UserService">
    	<!-- 写法一 -->
    	<!-- <property name="UserDao" ref="userDao"></property> -->
    	<!-- 写法二 -->
    	<property name="userDao" ref="userDao"></property>
    </bean>
    
    <!-- 注册dao -->
    <bean id="userDao" class="com.muyer.dao.UserDao"></bean>
    

    3.工厂注入(FactoryBean)

    public interface FactoryBean<T> {
    
        //返回的对象实例
        T getObject() throws Exception;
        //Bean的类型
        Class<?> getObjectType();
        //true是单例,false是非单例  在Spring5.0中此方法利用了JDK1.8的新特性变成了default方法,返回true
        boolean isSingleton();
    }
    

    4.注解注入
    @Component/@Service/@Controller/@Repository/@Autowire

    二、BeanFactory和ApplicationContext

    • BeanFactory:最底层的接口,提供两个功能:实例化对象和拿对象
    • ApplicationContext:继承BeanFactory,提供更多功能:国际化、AOP、访问资源文件、载入多个上下文等...
    • 对比不同之处:
      BeanFactory是延迟实例化Bean
      ApplicationContext启动把所有Bean全都实例化,当然也可以通过lazy-init=true实现beaan的延迟实例化

    三、BeanFactory和FactoryBean

    • BeanFactory是IOC底层最的接口,提供了实例化对象和拿对象,DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
    public interface BeanFactory {
        //下面几个getBean的作用:
        //注册的bean实例。
        //根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常
        Object getBean(String var1) throws BeansException;
        <T> T getBean(String var1, Class<T> var2) throws BeansException;
        Object getBean(String var1, Object... var2) throws BeansException;
        <T> T getBean(Class<T> var1) throws BeansException;
        <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
        //判断工厂中是否包含给定名称的bean定义,若有则返回true
        boolean containsBean(String var1);
        //判断给定名称的bean定义是否为单例
        boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
        //判断给定名称的bean定义是否为多例
        boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
        //返回给定bean名称的所有别名 
        String[] getAliases(String var1);
    }
    
    • FactoryBean在IOC容器的基础上加上了简单工厂模式和装饰模式。可以getObject()方法中灵活配置。
      我们可以在再FactoryBean#getObject()中组装我们需要的bean,当调用getObject的时候,即可返回一个bean

    四、Spring IOC具体怎么实现的?

    • IOC和DI:
      IOC中文意思是控制反转,是一种思想:把对对象的控制权交给IOC容器,容器中对象通过DI(依赖注入)来实现
    • IOC底层实现:
      xml+dom4j+工厂+单例?????

    五、循环依赖如何解决?循环依赖会报什么错?什么时候出现这个异常?是启动还是调用的时候?

    参考

    1. 概念
      循环依赖就是循环引用,例如A依赖B,B依赖C,C依赖A形成了一个闭环。
    2. 种类
      • 构造器循环依赖
      • 属性注入循环依赖
    3. 现象
      • 构造器循环依赖启动的时候就失败,报错:项目启动失败,发现了一个cycle
      • 属性循环依赖(singleton),没有报错
      • 属性循环依赖(prototype),报错:项目启动失败,发现了一个cycle
    4. 分析现象
    • 单例的设值注入bean是如何解决循环依赖问题呢?如果A中注入了B,那么他们初始化的顺序是什么样子的?
    本质就是三级缓存发挥作用,解决了循环;
    简单来说就是:未等bean创建完就先将实例曝光出去,方便其他bean的引用。最先曝光到第三级缓存singletonFactories中。
    
    • 为什么prototype类型的和构造器类型的Spring无法解决循环依赖呢?
     prototype类型属性循环依赖:
          对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。 
    构造器类型循环依赖:
          构造器循环依赖Spring无法直接解决。但是可以[通过@Lazy解决构造器循环依赖](https://blog.csdn.net/qq271859852/article/details/105181422/)
          通过在构造器参数中标识@Lazy注解,Spring 生成并返回了一个代理对象,因此注入并非真实对象而是其代理;
    
    • 三级缓存
    一级缓存:
    /** 保存所有的singletonBean的实例 */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
    
    二级缓存:
    /** 保存所有早期创建的Bean对象,这个Bean还没有完成依赖注入 */
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    三级缓存:
    /** singletonBean的生产工厂*/
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
     
    /** 保存所有已经完成初始化的Bean的名字(name) */
    private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
     
    /** 标识指定name的Bean对象是否处于创建状态  这个状态非常重要 */
    private final Set<String> singletonsCurrentlyInCreation =
    	Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
    

    六、Spring Bean为什么默认是单例?

    1. 好处
      • 可以从缓存中快速获取bean,其中Spring 单例bean的循环依赖就是通过三级缓存解决的
      • 减少创建性能提升(池化技术)
      • 减少jvm回收(单例bean作为GC Root对象不会被回收)
    2. 坏处
      • 多线程并发安全问题,prototype就不会出现这种情况

    七、Spring事务声明式注解如何实现、传播行为、失效场景?编程事务设计模式?自己定义个注解?

    1. 声明事务
    • 实现
    step1.配置事务管理器、连接池:
          DataSourceTransactionManager
    step2.开启事务注解:
          <tx:annotation-driven transaction-manager="transactionManager"/>
    step3.在业务类上加上@Transactional
    
    • 传播行为

      传播行为:事务在多个方法中如何传递的
      传播的类型:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER

    //如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
    @Transactional(propagation=Propagation.REQUIRED)
    //如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行
    @Transactional(propagation=Propagation.SUPPORTS)
    //如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
    @Transactional(propagation=Propagation.MANDATORY)
    /不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    //以非事务的方式运行,如果当前存在事务,暂停当前的事务。
    @Transactional(propagation=Propagation.NOT_SUPPORTED)
    //必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
    @Transactional(propagation=Propagation.NEVER)
    //如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。
    Propagation.NESTED
    
    • 失效场景
    相应的bean没有被Spring管理
    mysql的引擎是MyISAM失效,因为MyISAM不支持事务
    注到了非public方法、或者非接口方法了
    异常被捕获了
    事务传播行为设置错误了,比如设置成never
    
    1. 编程事务
      编程事务:显式调用 beginTransaction()、commit()、rollback() 等事务管理相关的方法
      设计模式:用到了模板方法的设计模式

    2. 自己定义个注解
      step1、定义注解:@interface+元注解(@Target/@Retention)
      step2、标注
      step3、反射读取,实现逻辑
      注意:Spring定义注解,第三步怎么实现的?建议写个小demo,日志注解

    七、销毁bean的方式

    八、Spring中的设计模式?

    单例模式,单例注册表,ConcurrentHashMap来管理这个注册表,核心方法getSingleton,类型DCL检查是否实例化
    模板方法:xxxxTemplate,模板方法最大的好处,解决代码的复用,固定算法都封装到模板,自定义方法

    九、Spring生命周期初始化的方式?几种自定义Spring生命周期的初始化和销毁方法?

    https://www.cnblogs.com/bigshark/p/11296917.html

  • 相关阅读:
    eclipse—Maven项目打包成exe
    netty+proto使用简要记录
    使用Kotlin开发第一个Android应用
    Android——调用高德地图API前期准备
    AndroidStudio更改包名
    Android Studio —— java.lang.VerifyError: Verifier rejected class 问题解决
    Android studio Error occurred during initialization of VM 问题解决
    AndroidStudio下使用 RecyclerView xml文件不显示预览条目并报错类似:NoClassDefFoundError 问题解决
    Genymotion模拟器安装问题及解决(启动失败,模拟器不能联网)
    华为荣耀畅玩5C NEM-UL10 ROOT那些事儿(亲测成功)
  • 原文地址:https://www.cnblogs.com/yejiang/p/13511849.html
Copyright © 2011-2022 走看看