Spring经典概念、混淆点

如果你正打算深入学习Spring,但是不知从何学起,那么我强烈推荐你可以按照这个系列做一遍。本系列将Spring框架的各个部分从它庞杂的代码体系中抽取出来,然后对每一个部分进行讲解,并最终搭建成简易版Spring。我以人格保证:如果你可以坚持做下来,那么你对Spring这块的知识就基本都掌握清楚了! 附上该系列地址:https://blog.csdn.net/zhang_qing_yun/article/details/120084497

Spring经典概念、混淆点

线程安全

Spring并没有保证Bean的线程安全,需要由开发者自己编写解决线程安全问题的代码。但是大部分的Bean都是无状态的,天然就是线程安全的;同时对于作用域为原型模式的,每一次getBean都会去创建新的Bean对象,自然也不存在线程安全问题。

尽量不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的。如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

Bean的作用域

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
  • prototype : 每次getBean请求都会创建一个新的 bean 实例。
  • request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
  • session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

BeanFactory和FactoryBean区别

BeanFactory是个Factory,也就是IOC容器或对象工厂,Spring中所有的Bean都是由BeanFactory来进行管理的。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

FactoryBean为IOC容器中Bean的实现提供了更加灵活的方式,使得一个Bean可以按照我们自己的创建逻辑来创建,而不是Spring中Bean生命周期的创建逻辑,但是却可以将我们创建出来的Bean也交给Spring来管理。FactoryBean具有两层身份,首先它是一个Spring中的Bean,它会按照普通Bean的逻辑创建出来并且由Spring来管理;其次,它是一个特殊的Bean(所以在容器中它的beanName会被默认加上“&”),我们还可以把他看作是一个工厂,通过调用它的getObject()方法就可以按照我们自己的创建对象的逻辑来创建出一个对象并且交由Spring来管理。Spring在初始化一个FactoryBean时会去调用两次getBean函数,第一次将其当作普通Bean创建出来,第二次是将其当作工厂来生产出我们想要的对象。

BeanFactory和ApplicationContext区别

  1. BeanFactory是Spring里面最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。
  2. ApplicationContext应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能。如国际化,访问资源,载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,消息发送、响应机制,AOP等。
  3. BeanFactory在启动的时候不会去实例化Bean,有从容器中拿Bean的时候才会去实例化。ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true或@Lazy来让Bean延迟实例化。

自动装配

Spring在启动时向容器中注入了一个非常重要的组件AutowiredAnnotationBeanPostProcessor,这个组件是专门用来解决@Autowire自动注入的。

在实例化Bean时,会去调用AutowiredAnnotationBeanPostProcessor的determineConstructorsFromBeanPostProcessors函数来找到所有加了@Autowire注解的构造器,然后通过参数类型去进行匹配,然后使用匹配到的构造器通过反射来创建对象。

在进行属性填充之前,会去执行AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,作用就是对使用了 @Autowire 注解的属性进行自动注入,具体来说就是从容器中去获取所依赖的Bean,然后通过反射的方式将依赖的 bean 赋值给对应的属性。

多个Bean满足注入条件

Spring中可以使用byName的方式来完成注入,如@Resource(name="") 或者是@Autowired与@Qualifier(value="")搭配使用,这种情况下都是通过getBean(beanName)来递归地创建该beanName对应的Bean,然后注入。

还有一种是根据类型byType的自动注入,这时就会出现一个接口有多个实现类同时存在的情况即有多个可选择的Bean,此时注入需要满足以下条件:

  1. 如果满足的bean列表中存在bean有@Primary注解,将注入该bean。但是如果同时有两个及以上的bean有@Primary注解,则会抛出异常。
  2. 如果满足的bean列表中存在bean带有javax.annotation.Priority注解,将以注解中value值中最小(优先级最高)的bean注入。但是如果有两个bean的优先级相同且都是最高,则会抛出异常。
  3. 如果满足的bean列表中存在bean的beanName与要注入的属性名一样,则注入该Bean。(在使用@Component申明Bean时默认的beanName为类名首字母小写)
  4. 上面条件都不满足,但是如果需要的注入的field上的注解为@Autowired(required=false)则返回null,不会抛出异常。
  5. 此时,会抛出异常。

Guess you like

Origin blog.csdn.net/zhang_qing_yun/article/details/120236376