4.7 深入理解Spring

时间:2022-12-27 07:59:59

4.7.1 Spring

4.7.1.1 Spring模块

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

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

4.7 深入理解Spring
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架构原理

4.7 深入理解Spring
IOC流程图

4.7.2.1 Bean初始化状态

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

概念态:

定义态:bean的构造图

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

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

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

4.7 深入理解Spring

4.7.2.2 概念bean 定义bean

BeanDefinition是相当重要的 

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

4.7 深入理解Spring

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

4.7 深入理解Spring

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

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

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

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

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

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

4.7 深入理解Spring

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

4.7 深入理解Spring

之后由registerBeanDefinition将BeanDefinition注册到BeanDefinitionMap中

4.7 深入理解Spring

 之后就是生产bean了。

4.7.2.3 生产bean

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

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

4.7 深入理解Spring

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

4.7 深入理解Spring

答案:是同一个

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

4.7 深入理解Spring

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

4.7 深入理解Spring

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

4.7 深入理解Spring

那么既然都可以作为容器,为什么不直接在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。

4.7 深入理解Spring

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

4.7 深入理解Spring

但是对于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()


@Component
public class FactoryBean_test implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
//这个才是返回的真正的bean
        return new User();
    }
 
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

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

4.7.2.5 属性注入

4.7.2.5.1 循环依赖

4.7 深入理解Spring

4.7.2.6 初始化

4.7.2.6.1 初始化方法

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

4.7 深入理解Spring

 除了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

4.7 深入理解Spring

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

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

4.7.2.8 扩展接口

4.7.2.8.1 BeanFactoryPostProcessor接口

@FunctionalInterface
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory BeanFactory) throws BeansException;
}

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

4.7.2.8.2 BeanDefinitionRegistryPostProcessor

源码定义如下:

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

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

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

4.7 深入理解Spring

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 深入理解Spring

4.7.3.2 详细版本

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

//bean
 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
//如果缓存中不存在,则调用createBeanInstance创建一个BeanWrapper(bean的包装类)
        if (instanceWrapper == null) {
//bean的实例化
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
//初始化bean实例
 Object exposedObject = bean;

//----------------省略-----------
//属性填充
            this.populateBean(beanName, mbd, instanceWrapper);
//初始化bean,如执行aware接口的子类,执行init-method方法,BeanPostProcesso后置增强等
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);


//销毁不在AbstractAutowireCapableBeanFactory 类,在DisposableBeanAdapter类中


}

 initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
//先执行aware的子类
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }

          Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
//执行beanPostProcessor后置处理器的前置方法BeanPostProcessorsBeforeInitialization
                wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
            }
//中间执行init-method
        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }
//最后执行BeanPostProcessorsAfterInitialization
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

 invokeAwareMethods

    private void invokeAwareMethods(String beanName, Object bean) {

        if (bean instanceof Aware) {
//如果bean实现了BeanNameAware,那bean内部可以获取到beanName属性
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }
//其他同理
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }

            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }

    }

 invokeInitMethods

  protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
//InitialalizationBean接口,如果实现了,将会执行InitialalizationBean的afterPropertiesSet()初始化方法
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }

            if (System.getSecurityManager() != null) {
                try {
//执行afterPropertiesSet()
                    AccessController.doPrivileged(() -> {
                        ((InitializingBean)bean).afterPropertiesSet();
                        return null;
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
                ((InitializingBean)bean).afterPropertiesSet();
            }
        }
//用户自定义的初始化方法
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
//用户自定义的方法
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }

    }

 DisposableBeanAdapter

//销毁
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
 public void destroy() {
        if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
            Iterator var1 = this.beanPostProcessors.iterator();

            while(var1.hasNext()) {
//先查看DestructionAwareBeanPostProcessor接口
                DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
//如果实现了,则执行DestructionAwareBeanPostProcessor后置处理器的销毁方法
                processor.postProcessBeforeDestruction(this.bean, this.beanName);
            }
        }
//接着看是否实现了DisposableBean接口
              if (System.getSecurityManager() != null) {
                   AccessController.doPrivileged(() -> {
//如果实现了就调用接口的destroy方法
                       ((DisposableBean)this.bean).destroy();
                            
                }
              }
//最后判断是否有用户自定义的销毁方法
           if (this.destroyMethod != null) {
            this.invokeCustomDestroyMethod(this.destroyMethod);
        } else if (this.destroyMethodName != null) {
            Method methodToInvoke = this.determineDestroyMethod(this.destroyMethodName);
            if (methodToInvoke != null) {
//调用用户自定义的销毁方法
                this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
            }
        }
}

Spring的理解

Spring是什么?

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

容器:管理bean

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

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

4.7.3.3 循环依赖

4.7.3.3.1 循环依赖问题

4.7 深入理解Spring

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等线程同步方法,又会降低系统效率。