飞道的博客

4.7 深入理解Spring

278人阅读  评论(0)

4.7.1 Spring

4.7.1.1 Spring模块

Spring 由七大模块组成,分别是

  • 数据模块(Data Access / Integration
  • Web模块
  • 切面模块(AopAspects
  • 工具模块(Instrumentation)
  • 消息模块
  • 核心模块
  • 测试模块

Spring模块

4.7.1.1.1 数据模块

数据访问与集成模块,分为以下小模块:

  • JDBC (Java Database Connectivity),Java数据库连接
  • ORM (Object Relational Mapping), 对象关系映射
  • OXM (Object XML Mapping), 对象XML映射
  • JMS (Java Message Service),Java消息服务
  • Transactions ,事务

4.7.1.1.2 Web模块

Web有以下小模块:

  • Web
  • WebMVC
  • WebSocket
  • WebFlux

Web 模块:提供了核心部分,如 编解码,过滤器,序列化,国际化,跨域,转换器,客户端和服务端等。

WebMVC 模块:即我们平时用的 SpringMVC

WebSocket 模块: 用来支持这个 全双工通信

WebFlux模块: 就是这个响应式Web编程模块

4.7.1.1.3 切面模块

包括AOP、Aspect两个模块。

AOP:基于代理的 Aop 框架

Aspect:定义了五种类型的切面

  • beans.factory.aspectj
  • cache.aspectj
  • context.annotation.aspectj
  • scheduling.aspectj
  • transaction.aspectj

4.7.1.1.4 工具模块

 Instrumentation , 这个是 Java 的一个接口,用于

  • 监控代理
  • 事件日志记录
  • 代码覆盖率

4.7.1.1.5 消息模块

Spring-messaging 模块提供了一种基于 WebSocket 的 STOMP 协议实现
STOMP (Simple Text Oriented Messaging Protocol) 是一种 流文本定向消息协议,也是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议
常见的这几个MQ都支持该协议,比如 RocketMQRabbitMQActiveMQ。

待更新

Spring的这七大模块你了解吗? - 知乎

4.7.1.1.6 核心模块

分为四个核心模块:

  • Beans
  • Core
  • Context
  • Expression

该核心模块为重点,

4.7.1.1.7 测试模块

主要是测试用,如Junit等。


4.7.1.2 核心模块 

4.7.2 SpringIOC架构原理

IOC流程图

4.7.2.1 Bean初始化状态

我们可以将bean概念态、定义态、纯静态、成熟态

概念态:

定义态:bean的构造图

纯静态:循环依赖中体现纯静态的作用

成熟态:最终在应用中使用的bean

其中在ApplicationContext()中隐藏了另外两种状态

4.7.2.2 概念bean 定义bean

BeanDefinition是相当重要的 

BeanDefinition:封装了bean的定义信息,决定一个bean是怎么生产的,一个bean对应一个BeanDefinition

那么这个BeanDefinition是怎么来的呢?

当我们new ApplicationContext时会传入一个xml文件。不同的sapring上下文会传入不同的,读取bean定义的过程是有些不同的,但也有相同的地方。


  
  1. 方式一: ClassPathXmlApplicationContext(xml);
  2. 方式二: AnnotationConfigApplicationContext(配置类);

无论是ClassPathXmlApplicationContext(xml)还是AnnotationConfigApplicationContext(配置类)都有一个统一的接口ApplicationContext,因此它们会将公共的部分抽取出来,我们来研究这些公共的部分。

虽然有不同的spring上下文,但是都是由BeanDefinitionReader接口读取配置信息

读取之后怎么解析注解呢?

用扫描器ClassPathBeanDefinitionScanner,比如,我们定义了

它会扫描包下的.class,里面有component注解,将这个类注册为BeanDefinition。由于每个类都会有BenaDefinition,所以用beanDefinitionMap容器保存。

之后由registerBeanDefinition将BeanDefinition注册到BeanDefinitionMap中

 之后就是生产bean了。

4.7.2.3 生产bean

 这里涉及到很重要的知识点:BeanFactory接口

BeanFactory负责生产,在BeanFactory中提供了getBean方法用来生产bean。

提出一个小问题,这里Spring容器调用的getBean和BeanFactory里的getBean是同一个方法吗?

答案:是同一个

我们进入applicationContext.getBean(),会发现这里的getBean是门面方法,没有具体,而是交给BeanFactory去生产。

 当已存在bean就直接返回给spring,如果没有就生产后返回。

既然ApplicationContext和BeanFactory都可以获取bean,也就是说二者均可作为容器去使用。

那么既然都可以作为容器,为什么不直接在spring中书写BeanFactroy,非要再整个ApplicationContext的门面方法,不多此一举么?

看完上面的继承图,我们发现ApplicationContext实现了BeanFactroy,这就好比,我们要买车,我们可以选择去4S店,也可以选择直接去汽车工厂。ApplicationContext就好比4S店,4S店有很多的服务,我们只需要提需求,4S店都能完成。BeanFactroy就是汽车工厂,工厂的职责就一个:生产汽车。基本上我们和4S店比较熟悉,打交道比较多,同样我们开发人员和ApplicationContext打交道比较多。我们只需要把配置给ApplicationContext,它就能初始化。

但是BeanFactroy不行,它只实现了简单工厂,功能单一化,只能根据BeanDefinition去生产bean。

通过ApplicationContext,我们只需要getBean(car),就可以得到我们想要的bean,但是,如果注释了ApplicationContext,我们再直接用beanFactory.get(car),就会报错BeanDefinitionException。

因为像xml、配置类的信息,都是由ApplicationContext(Spring 上下文)帮我们做了,ApplicationContext调用了BeanFactory来生产bean。

但是对于BeanFactory,我们必须手动将BenaDefinition传给BeanFactory,才能生产bean。

但是BeanFactory内存更小,可以用于嵌入式开发。

4.7.2.4 实例化bean

实例化bean的方式:

  1. 反射
  2. 工厂方法
  3. 工厂类:FactoryBean

4.7.2.4.1 反射

@Component

将类读取到beanClass中,spring利用反射实例化bean

4.7.2.4.2 工厂方法

注解形式

public class StaticFactoryBean {

   @Bean
    public static UserService createUserService(){    
            return new UserServiceImpl();
    }
}

 会将被标注的方法读取到factoryMethodName

xml形式

而<bean id="" factory-bean="StaticFactoryBean全限定名" factory-method=" UserService"/>

在factory-method=" "中指定一个工厂方法,且这个工厂方法是静态的,会将方法读取到factoryMethodName 

4.7.2.4.3 工厂类

注意FactoryBean本身也是一个bean

 类实例化FactoryBean接口,并重写getObject()、getObjectType()


  
  1. @Component
  2. public class FactoryBean_test implements FactoryBean {
  3. @Override
  4. public Object getObject() throws Exception {
  5. //这个才是返回的真正的bean
  6. return new User();
  7. }
  8. @Override
  9. public Class<?> getObjectType( ) {
  10. return User. class;
  11. }

工厂方法基于方法,而工厂类基于类

4.7.2.5 属性注入

4.7.2.5.1 循环依赖

4.7.2.6 初始化

4.7.2.6.1 初始化方法

属性注入之后,进行初始化,初始化时会调用init_Method()

 除了init-Method()外

还可以用注解@PostConstruct声明一个初始化方法

以及利用InitializingBean接口,实现一个InitializingBean,重写afterPropertiesSet()

4.7.2.6.2 aware扩展接口

检查aware接口设置相关依赖

在spring容器中,我们可以把对象按照使用者分为两类:自定义对象、容器使用的对象

  • 自定义对象:就是我们开发人员定义的Student、Taecher等对象
  • 容器使用的对象:BeanPostProcessor、BeanFactory等,这些都是由容器自己创建、自己调用。

但是如果我们自定义对象需要使用、调用这些容器所使用的对象时,怎么办?

你可以把这些容器所使用的对象当成一个普通属性,如果是属性,我肯定要调用属性的set方法,往里面赋值。但是,对象的创建都交由容器来管理了,set方法调用肯定还是由容器管理,而且容器又不知道什么时候调用。

所以这里设置了统一的入口——aware接口。

所有调用容器对象设置的地方都会实现aware接口,如BeanFactoryAware、BeanNameAware等。

总的来说就是通过aware的具体实现子类,我们可以设置bean的一系列操作。

4.7.2.7 创建Bean

  创建好的bean会放入Map(单例池/一级缓存)中

context.getBean("bean的名字");时,会到一级缓存中查询,有就返回,没有就生产。

4.7.2.8 扩展接口

4.7.2.8.1 BeanFactoryPostProcessor接口


  
  1. @FunctionalInterface
  2. public interface BeanFactoryPostProcessor {
  3. void postProcessBeanFactory (ConfigurableListableBeanFactory BeanFactory) throws BeansException;
  4. }

 BeanFactoryPostProcessor中的postProcessBeanFactory()方法,直接传来一个

4.7.2.8.2 BeanDefinitionRegistryPostProcessor

源码定义如下:


  
  1. public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
  2. void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry var1) throws BeansException;
  3. }

BeanDefinitionRegistryPostProcessor的作用是注册BeanDefinition,也就是注册了Bean

Spring-MyBatis中的Mapper是接口,动态代理

4.7.2.8.3 BeanPostProcessor

 BeanPostProcessor(bean的后置处理器)主要用在初始化前后

BeanPostProcessor有很多子接口

4.7.3 Bean生命周期

4.7.3.1 简化版本

1、实例化bean,当客户向容器请求一个尚未初始化的bean时,容器就会调用doCreateBean()方法进行实例化,实际上就是利用反射来创建一个bean对象

2、当bean对象创建出来后就对bean对象进行属性填充,也就是注入这个bean依赖的其他对象

3、属性填充完成后,进行初始化bean操作

         a、执行Aware接口方法,Spring会检查该bean对象是否实现了xxxAware接口,通过Aware类型的接口,我们可以拿到spring容器的一些资源,如实现了BeanNameAware接口就可以获取BeanName等等

        b、执行BeanPostProcessor的前置处理方法postProcessBeforeInitialization(),对Bean进行一些自定义的前置处理

        c、判断bean是否实现了InitialalizationBean接口,如果实现了,将会执行InitialalizationBean的afterPropertiesSet()初始化方法

        d、执行用户自定义的初始化方法,如init-method等

        e、执行BeanPostProcessor的后置处理方法postProcessAfterInitialization()

4、销毁

        a、首先判断Bean是否实现了DestructionAwareBeanPostProcessor接口,如果实现了,则执行DestructionAwareBeanPostProcessor后置处理器的销毁方法

        b、其次判断Bean是否实现了DisposableBean接口,如果实现了就会调用其实现的destroy()方法

        c、最后判断Bean是否配置了destroy-method方法,如果有就调用其配置的销毁方法

4.7.3.2 详细版本


  
  1. public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
  2. //bean
  3. protected Object doCreateBean( String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
  4. BeanWrapper instanceWrapper = null;
  5. if (mbd.isSingleton()) {
  6. instanceWrapper = ( BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);
  7. }
  8. //如果缓存中不存在,则调用createBeanInstance创建一个BeanWrapper(bean的包装类)
  9. if (instanceWrapper == null) {
  10. //bean的实例化
  11. instanceWrapper = this.createBeanInstance(beanName, mbd, args);
  12. }
  13. //初始化bean实例
  14. Object exposedObject = bean;
  15. //----------------省略-----------
  16. //属性填充
  17. this.populateBean(beanName, mbd, instanceWrapper);
  18. //初始化bean,如执行aware接口的子类,执行init-method方法,BeanPostProcesso后置增强等
  19. exposedObject = this.initializeBean(beanName, exposedObject, mbd);
  20. //销毁不在AbstractAutowireCapableBeanFactory 类,在DisposableBeanAdapter类中
  21. }

 initializeBean


  
  1. protected Object initializeBean( String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  2. if ( System. getSecurityManager() != null) {
  3. AccessController. doPrivileged(() -> {
  4. //先执行aware的子类
  5. this. invokeAwareMethods(beanName, bean);
  6. return null;
  7. }, this. getAccessControlContext());
  8. } else {
  9. this. invokeAwareMethods(beanName, bean);
  10. }
  11. Object wrappedBean = bean;
  12. if (mbd == null || !mbd. isSynthetic()) {
  13. //执行beanPostProcessor后置处理器的前置方法BeanPostProcessorsBeforeInitialization
  14. wrappedBean = this. applyBeanPostProcessorsBeforeInitialization(bean, beanName);
  15. }
  16. //中间执行init-method
  17. try {
  18. this. invokeInitMethods(beanName, wrappedBean, mbd);
  19. } catch ( Throwable var6) {
  20. throw new BeanCreationException(mbd != null ? mbd. getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
  21. }
  22. //最后执行BeanPostProcessorsAfterInitialization
  23. if (mbd == null || !mbd. isSynthetic()) {
  24. wrappedBean = this. applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  25. }

 invokeAwareMethods


  
  1. private void invokeAwareMethods( String beanName, Object bean) {
  2. if (bean instanceof Aware) {
  3. //如果bean实现了BeanNameAware,那bean内部可以获取到beanName属性
  4. if (bean instanceof BeanNameAware) {
  5. (( BeanNameAware)bean). setBeanName(beanName);
  6. }
  7. //其他同理
  8. if (bean instanceof BeanClassLoaderAware) {
  9. ClassLoader bcl = this. getBeanClassLoader();
  10. if (bcl != null) {
  11. (( BeanClassLoaderAware)bean). setBeanClassLoader(bcl);
  12. }
  13. }
  14. if (bean instanceof BeanFactoryAware) {
  15. (( BeanFactoryAware)bean). setBeanFactory( this);
  16. }
  17. }
  18. }

 invokeInitMethods


  
  1. protected void invokeInitMethods( String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
  2. //InitialalizationBean接口,如果实现了,将会执行InitialalizationBean的afterPropertiesSet()初始化方法
  3. boolean isInitializingBean = bean instanceof InitializingBean;
  4. if (isInitializingBean && (mbd == null || !mbd. isExternallyManagedInitMethod( "afterPropertiesSet"))) {
  5. if ( this. logger. isTraceEnabled()) {
  6. this. logger. trace( "Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
  7. }
  8. if ( System. getSecurityManager() != null) {
  9. try {
  10. //执行afterPropertiesSet()
  11. AccessController. doPrivileged(() -> {
  12. (( InitializingBean)bean). afterPropertiesSet();
  13. return null;
  14. }, this. getAccessControlContext());
  15. } catch ( PrivilegedActionException var6) {
  16. throw var6. getException();
  17. }
  18. } else {
  19. (( InitializingBean)bean). afterPropertiesSet();
  20. }
  21. }
  22. //用户自定义的初始化方法
  23. if (mbd != null && bean. getClass() != NullBean. class) {
  24. String initMethodName = mbd. getInitMethodName();
  25. if ( StringUtils. hasLength(initMethodName) && (!isInitializingBean || ! "afterPropertiesSet". equals(initMethodName)) && !mbd. isExternallyManagedInitMethod(initMethodName)) {
  26. //用户自定义的方法
  27. this. invokeCustomInitMethod(beanName, bean, mbd);
  28. }
  29. }
  30. }

 DisposableBeanAdapter


  
  1. //销毁
  2. class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
  3. public void destroy() {
  4. if (!CollectionUtils.isEmpty( this.beanPostProcessors)) {
  5. Iterator var1 = this.beanPostProcessors.iterator();
  6. while(var1.hasNext()) {
  7. //先查看DestructionAwareBeanPostProcessor接口
  8. DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
  9. //如果实现了,则执行DestructionAwareBeanPostProcessor后置处理器的销毁方法
  10. processor.postProcessBeforeDestruction( this.bean, this.beanName);
  11. }
  12. }
  13. //接着看是否实现了DisposableBean接口
  14. if (System.getSecurityManager() != null) {
  15. AccessController.doPrivileged(() -> {
  16. //如果实现了就调用接口的destroy方法
  17. ((DisposableBean) this.bean).destroy();
  18. }
  19. }
  20. //最后判断是否有用户自定义的销毁方法
  21. if ( this.destroyMethod != null) {
  22. this.invokeCustomDestroyMethod( this.destroyMethod);
  23. } else if ( this.destroyMethodName != null) {
  24. Method methodToInvoke = this.determineDestroyMethod( this.destroyMethodName);
  25. if (methodToInvoke != null) {
  26. //调用用户自定义的销毁方法
  27. this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
  28. }
  29. }
  30. }

Spring的理解

Spring是什么?

框架:方便开发,整合其他框架

容器:管理bean

生态:目前主流的Java开发,都会用到Java全家桶。Springboot、Springcloud等框架都是对Spring的扩展实现。

11张流程图搞定 Spring Bean 生命周期 - 知乎

4.7.3.3 循环依赖

4.7.3.3.1 循环依赖问题

4.7.3.3.2 解决方案:三级缓存

singletonObject(一级缓存):存放实例化 -> 代理 -> 属性注入 ->初始化后的对象

earlySingletonObjects(二级缓存):存放实例化 -> 代理 -> 属性注入 ->初始化后的对象

singletonFactories(三级缓存):存放对象工厂,可以从对象工厂中拿到还未属性注入的对象(对象工厂便于创建代理对象)

4.7.3.3.3 流程

当getBean(),获取bean时,spring会先到一级缓存中找,没有再去二级缓存,若二级缓存还没有就会创建一个对应的工厂对象

4.7.4 AOP

单例bean

Spring中的Bean对象默认是单例的,框架并没有对Bean进行多线程封装处理

单例bean是指IOC容器中就只有这么一个bean,是全局共享的。分为有状态bean和无状态bean。

有状态的bean

就是有实例变量的对象,可以保存数据(有状态就是有数据存储功能),是线程不安全的。每个用户都有自己特有的实例,在用户的生命周期中,bean保存了用户的信息,即为“偶状态”;一旦用户衰亡(调用结束),bean的生命周期也随之结束。即每个用户最初都会得到一个初始的bean。

无状态的bean

就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

 实例变量

java类的成员变量有俩种:一种是被static关键字修饰的变量,叫类变量或者静态变量;另一种没有static修饰,为实例变量。

class Car{

private name;   //这就是实例变量

public void 方法(){};

}

当一个对象被实例化之后,每个实例变量的值就跟着确定;

实例变量在对象创建的时候创建,在对象被销毁的时候销毁;

如果Bean是有状态的,那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的安全了。

无状态就是不会存储数据,试想controller,service和dao本身并不是线程安全的,只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制遍历,这是自己线程的工作内存,是最安全的。因此在进行使用的时候,不要在bean中声明任何有状态的实例变量或者类变量,如果必须如此,也推荐大家使用ThreadLocal把变量变成线程私有,如果bean的实例变量或者类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、cas等这些实现线程同步的方法。但是一旦使用了synchronized、lock等线程同步方法,又会降低系统效率。


转载:https://blog.csdn.net/qq_43757965/article/details/128066080
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场