面试总结-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

posted @ 2020-08-16 11:11  木叶小寒江  阅读(143)  评论(0编辑  收藏  举报