Spring 框架底层原理

1 篇文章 0 订阅
订阅专栏

1、SpringIOC


1、ConfigurableApplicationContext 接口?

设置上下文 ID,设置父应用上下文,添加监听器,刷新容器,关闭,判断是否活跃等方法。
是 SpringBoot 最核心的内容-应用容器。
该接口的核心方法包括设置当前容器环境变量添加BeanFactory后置处理器添加容器监听器加载或者刷新配置持久化代理
该接口是 ApplicationContext 的子类,主要任务就是配置应用程序上下文功能。

2、BeanFactory 是容器最基本的接口?

BeanFactory 负责配置、创建、管理 Bean。
BeanFactory 是 Spring 的心脏,那么 ApplicationContext 就是完整的身躯了。
ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。
ConfigurableApplicationContext作为实现ApplicationContext 的核心接口。 核心方法就是 refresh() 方法实现加载或者刷新配置持久化代理。

2.1、BeanDefinition 接口?

用于保存Bean的相关信息,包括属性、构造方法参数、依赖的Bean名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,存储Bean初始化时的元数据 Spring 就是根据 BeanDefinition 中的信息实例化 Bean。

2.2、单例 DefaultSingletonBeanRegistry ?

维护一个 Map 的单例池存储单例对象,提供一个公开的 getSingleton 方法和一个 保护类型的 addSingleton 方法。

2.3、AbstractBeanFactory 抽象类?
  • 继承 DefaultSingletonBeanRegistry 默认的单例抽象类,同时也具备了使用单例注册类的方法。
  • 重点:实现了接口 BeanFactory 的实现,方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。
  • 那 AbstractBeanFactory 的实现类有哪些?主要包括 AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory 来分别实现对应的 createBean、getBeanDefinition 方法。
2.4、AbstractAutowireCapableBeanFactory 实现类

实现父类 AbstactBeanFactory 的创建实例的方法。
继承抽象类AbstractBeanFactory实现相应的抽象方法,实现其中的createBean方法但是AbstractAutowireCapableBeanFactory 本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承 AbstractAutowireCapableBeanFactory 的类实现。这里就体现了类实现过程中的各司其职。

3、什么是 refresh() 方法?

refresh() 方法实现加载或者刷新配置持久化代理。

3.1、AbstractApplicationContext 类?

抽象类使用到了模板方法模式,定义refresh()方法的调用模板,需要具体的子类去实现抽象方法。

3.2、AbstractRefreshableApplicationContext 抽象类

获取了 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作。
实现热刷新功能,内部存在 DefaultListableBeanFactory 的实例对象。
通过调用子类实现 **AbstractXmlApplicationContext **实现类提供XmlBeanDefinitionReader解析xml文件获取 BeanDefinition 对象。

3.3、DefaultListableBeanFactory 类

DefaultListableBeanFactory 作为BeanFactory的默认实现抽象类,基于BeanDefinition对象,负责Bean注册后的处理。就是一个容器接口,可以独立使用的类。
内部维护一个 BeanDefinition 的 Map 对象作为 Spring 容器。

3.4、XMLBeanDefinitionReader 类

该类主要作用正如名字而言,基于xml文件的解析类。并且将解析后的数据进行封装到 BeanDefinition 对象中注册到 DefaultListableBeanFactory 类维护的 Map 容器中。

3.5、创建实例 createBeanInstance()方法


首先通过反射获取构造方法然后通过遍历进行参数匹配赋值构造器方法。
获取指定的动态代理策略方法来实例化当前的Bean对象。
由于目前还未进行对象的初始化和属性填充所以需要使用代理对象后期进行对象增强。

3.6、applyPropertyValues() 填充属性方法


获取 BeanDefinition 对象中封装的 Bean 的参数进行遍历匹配填充属性。

3.7、initializeBean() 初始化方法


上述的 refresh() 方法中还存在一步骤

所以在初始化 Bean 对象时还需要对对象 Aware 感知类的匹配并且赋值。

  1. 调用 BeanPostProcessor#before() 方法进行增强处理。
    1. before 方法也是调用 BeanPostProcessor 接口的实现类中进行对ApplicationContext设置所属的ApplicationContext 上下文方便后期获取该对象。
  2. 调用代理对象的 invokeInitMethods() 方法进行对象的初始化。
    1. 实现接口 InitializingBean 判断是否实现了初始化接口
    2. 注解配置 init-method {判断是为了避免二次执行初始化}
    3. 获取指定的初始化方法然后调用代理的 invoke 方法
  3. 调用 BeanPostProcessor#after() 方法处理后置增强处理。
    1. after 方法中只是返回了一个 bean 对象未做增强处理。
3.8、销毁方法

实现接口 DisposableBean、配置信息 destroy-method

4、Aware 接口?

  1. BeanFactoryAware
  2. BeanClassLoaderAware
  3. BeanNameAware
  4. ApplicationContextAware
4.1、Aware 接口的作用?

通常使用 Spring Aware 的目的是为了让 Bean 获得 Spring 容器的服务。
bean实现个某某Aware接口,然后这个bean就可以通过实现接口的方法,来接收接口方法传递过来的资源。
面向用户操作,我们不可能把 BeanFactoryPostProcessor 、BeanPostProcessor 这种类提供给用户操作吧,那么我们就需要扩展在这些框架被使用时怎么被调用,就需要提供一种能够感知容器操作的接口,能够获取接口入参中的各类功能。
通过 Aware 机制可以对 Bean 实现的方法进行回调扩展,上面就添加了一个 ApplicationContextAware 的类对象 Bean 进行赋值对象,后期可以通过 ApplicationContextAwareProcessor 中的方法进行回调
可以通过 Aware 的具体实现接口进行 instanceof 判断是否存在该感知类就可以判断是否需要设置该对应的类对象。ApplicationContext 对应 ApplicationContextAwareProcessor 感知类。就和RandomAccess 接口一样,只是为了标识 ArrayList 集合存在随机存储的作用。

/**
 * @ClassName: BeanClassLoaderAware
 * @Author: 小飞
 * @Date: 2023/3/28 17:36
 * @Description: 现此接口,既能感知到所属的 ClassLoader
 */
public interface BeanClassLoaderAware extends Aware{

    void setBeanClassLoader(ClassLoader classLoader);

}
  • 实现此接口,既能感知到所属的 ClassLoader
4.2、ApplicationContextAwareProcessor 类
  • 由于 ApplicationContext 的获取不能直接创建 Bean 的时候就获取到,那么就需要在 refresh 的时候将 ApplicationContext 注册到一个 BeanPostProcessor 中 就可以将其注册到感知类中。

5、对象作用域

  • 整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理 FactoryBean 类型对象创建过程中关于获取具体调用对象的 getObject 操作。
  • SCOPE_SINGLETON、SCOPE_PROTOTYPE,对象类型的创建获取方式,主要区分在于 AbstractAutowireCapableBeanFactory#createBean 创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。
  • createBean 执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个 FactoryBean 对象,如果是这样的对象,就需要再继续执行获取 FactoryBean 具体对象中的 getObject 对象了。整个 getBean 过程中都会新增一个单例类型的判断factory.isSingleton(),用于决定是否使用内存存放对象信息。
5.1、FactoryBeanRegistrySupport 抽象类

管理和创建 FactoryBean 产生的单例对象
维护一个 单例FactoryBean 对象Map容器。

  • FactoryBeanRegistrySupport 类主要经济 FactoryBean 对象的创建,可以实现不同的领域只需要负责完成各自需要的功能,避免扩展导致类膨胀。
  • 定义了 缓存操作 factoryBeanObjectCache 用来存放单例类型的对象,避免重复创建。
  • doGetObjectFromFactoryBean 是具体的获取 FactoryBean#getObject() 方法。

6、容器事件和事件监听

  • 在整个功能实现过程中,仍然需要在面向用户的应用上下文 AbstractApplicationContext 中添加相关事件内容,包括:初始化事件发布者、注册事件监听器、发布容器刷新完成事件。
  • 使用观察者模式定义事件类、监听类、发布类,同时还需要完成一个广播器的功能,接收到事件推送时进行分析处理符合监听事件接受者感兴趣的事件,也就是使用 isAssignableFrom 进行判断。
  • isAssignableFrom 和 instanceof 相似,不过 isAssignableFrom 是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来。
6.1、ApplicationEvent 抽象类
/**
 * @ClassName: ApplicationEvent
 * @Author: 小飞
 * @Date: 2023/3/28 22:11
 * @Description: 提供 一套集事件注册、监听、触发为一体的事件实现 监听上下文
 */
public abstract class ApplicationEvent extends EventObject {

    public ApplicationEvent(Object source) {
        super(source);
    }

}
  • 以继承 java.util.EventObject 定义出具备事件功能的抽象类 ApplicationEvent,后续所有事件的类都需要继承这个类。
6.2、ApplicationContextEvent

监听事件应用上下文

6.3、ApplicationEventMulticaster 接口
  • 在事件广播器中定义了添加监听和删除监听的方法以及一个广播事件的方法 multicastEvent 最终推送时间消息也会经过这个接口方法来处理谁该接收事件。
6.4、AbstractApplicationEventMulticaster 抽象类

继承 BeanFactoryAware 就是为了获取 BeanFactory 对象实现了 ApplicationEventMulticaster 接口就是管理事件监听的核心类,存储了全部的监听事件对象同时实现了监听事件的添加、移除、获取全部监听事件、判断当前Bean对象是否设置了监听。
维护了一个事件监听Set集合。

7、动态代理实例化策略

用动态代理来实现含参构造。一个是基于 Java 本身自带的方法 DeclaredConstructor,另外一个是使用 Cglib 来动态创建 Bean 对象。Cglib 是基于字节码框架 ASM 实现,所以你也可以直接通过 ASM 操作指令码来创建对象。

7.1、BeanFactory 接口中重载了多个getBean 方法?
/**
 * @ClassName: BeanFactory
 * @Author: 小飞
 * @Date: 2023/3/25 21:24
 * @Description: BeanFactory是实现IOC容器的核心接口,通过beanName或者beanName+参数获取指定的Bean对象
 * 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
 */
public interface BeanFactory {

    // 空参构造
    Object getBean(String name) throws BeansException;

    // 含参构造
    Object getBean(String name, Object... args) throws BeansException;

}

重载getBean方法增加健壮性 提供含参方法获取Bean对象。

7.2、InstantiationStrategy 接口?

Bean 实例化策略,实例化策略的接口

  • 实例化接口 instantiate 方法中添加必要的入参信息,包括:beanDefinition、 beanName、ctor、args
  • Constructor 的作用就是匹配到符合对应参数的构造函数
  • args 就是一个具体的入参信息,实例化需要使用到参数。
7.3、JDK 实例化?

通过 JDK 的 DeclaredConstructor 来实现含参数构造。

 // 传入的构造器不为空则进行含参构造实例化
if (null != ctor) {
    return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
} else {
    // 如果构造器为空说明是无参构造
    return clazz.getDeclaredConstructor().newInstance();
}
  • 可以通过BeanDefinition对象获取需要的元数据。包括反射类型。
  • 接下来判断 ctor 是否为空,如果为空则是无构造函数实例化,否则就是需要有构造函数的实例化。
7.4、CGLIB 实例化?
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback(new NoOp() {
    @Override
    public int hashCode() {
        return super.hashCode();
    }
});
// 下面也是通过传入的构造函数是否为空来选择实例化方式为含参还是无参
if (null == ctor) return enhancer.create();
return enhancer.create(ctor.getParameterTypes(), args);
  • 这里直接创建 含参或者无参构造器还是比较简单的。

8、文件注册对象解析


我们可以和其他的设计框架一样,规范好配置格式,然后我们再使用策略模式选择对应的解析方式来实现自动解析参数并且注入到对象中

8.1、Resource 接口
  • 在 Spring 框架下创建 core.io 核心包,在这个包中主要用于处理资源加载流。
  • 定义 Resource 接口,提供获取 InputStream 流的方法,接下来再分别实现三种不同的流文件操作:classPath、FileSystem、URL

通过策略模式实现多种解析策略 分别为ClassPathResource、FileSystemResource、UrlResource

8.2、包装资源加载器

按照资源加载的不同方式,资源加载器可以把这些方式集中到统一的类服务下进行处理,外部用户只需要传递资源地址即可,简化使用。

public class DefaultResourceLoader implements ResourceLoader {

    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
        }
        else {
            try {
                URL url = new URL(location);
                return new UrlResource(url);
            } catch (MalformedURLException e) {
                return new FileSystemResource(location);
            }
        }
    }

}
8.3、Bean 解析器接口
  • 这是一个简单的定义BeanDefinition解析器的方法接口,重载三个加载Bean定义的方法。
  • 这里需要注意 getRegistry()、getResourceLoader(),都是用于提供给后面三个方法的工具,加载和注册,这两个方法的实现会包装到抽象类中,以免污染具体的接口实现方法。

子类通过 AbstractBeanDefinitionReader 实现具体的加载方法。

8.4、XmlBeanDefinitionReader 类
  • 在 doLoadBeanDefinitions 方法中,主要是对xml的读取 XmlUtil.readXML(inputStream) 和元素 Element 解析。在解析的过程中通过循环操作,以此获取 Bean 配置以及配置中的 id、name、class、value、ref 信息。
  • XmlBeanDefinitionReader 的核心就是解析xml配置文件 然后将解析的内容封装成PropertyValue对象,最后将PropertyValue 存储到一个PropertyValues集合中 存储到BeanDefinition对象中作为属性进行注入。
  • 最后在获取父类提供的getRegistry() 接口获取Bean的注册类将当前封装的BeanDefinition对象注册到DefaultListableBeanFactory#beanDefinitionMap 中也就是容器中。
8.5、ListableBeanFactory 接口
  • 枚举它们的所有bean信息,而不用一个个通过bean的名称或类型一个个查找。或者通过一种类型返回所有的数据
8.6、AutowireCapableBeanFactory 自动化处理 Bean 配置

为已经实例化的对象装配属性、实例化一个Bean,并自动装配,这些被装配的属性对象都是Spring管理的。

  • 前面定义了 BeanPostProcessor 接口的后置处理方法 自然要用到,通过AbstractAutowireCapableBeanFactory # createBean 创建Bean对象后初始化前后通过调用AutowireCapableBeanFactory 接口中的两个方法来调用所有的 BeanPostProcessor 对象执行。

8.7、ConfigurableBeanFactory 配置化接口
  • 可配置的BeanFactory工厂,定义各种配置能力,巨大的工厂接口。提供 配置 BeanFactory 的各种方法和配置参数等。
  • 增加方法 addBeanPostProcessor 增加到 AbstractBeanFactory#BeanPostProcessorList中

9、应用上下文


BeanFactoryPostProcessorBeanPostProcessor,这两个接口都是 Bean的后置处理器,只不过BeanFactoryPostProcessor 是对于实例化前后的后置处理器而BeanPostProcessor 初始化后置处理器。作用的时间不同,但是作用是差不多,都是扩展内部消息。
同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于
开发 Spring 的上下文操作类(就相当一个控制类,控制Bean对象的创建,实例化,初始化一个周期的执行)
,把相应的 XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。

9.1、BeanFactoryPostProcessor 接口
  • 这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制。
9.2、BeanPostProcessor 接口
  • 提供了修改新实例化 Bean 对象的扩展点,用于在 Bean 对象执行初始化方法之前,执行此方法、postProcessAfterInitialization用于在 Bean 对象执行初始化方法之后,执行此方法。
  • 包含两种方法 BeanPostProcessor#postProcessBeforeInitialization and BeanPostProcessor#postProcessAfterInitialization
9.3、AutowireCapableBeanFactory 接口
  • 自动装配的BeanFactory接口,就是执行 Bean对象中的 BeanPostProcessor 接口中对应的方法。
9.4、ApplicationContext 接口
  • Context 是本次实现应用上下文功能新增的服务包
  • ApplicationContext,继承于 ListableBeanFactory,也就继承了关于 BeanFactory 方法,比如一些 getBean 的方法。另外 ApplicationContext 本身是 Central 接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义。

2、SpringAOP

1、AOP 自动代理时机

在service bean的创建过程中(也就是getBean(“service”)),AOP通过BeanPostProcess后置处理器操作进行介入 分为2种情况:

  • 用户自定义了targetSource,则bean的创建(实例化、填充、初始化)均由用户负责,Spring Ioc不会在管该代理目标对象traget,这种情况基本上不会发生,很多人用了几年Spring可能都不知道有它的存在。
  • 正常情况下都是Spring Ioc完成代理对象target的实例化、填充、初始化。然后在初始化后置处理器中进行介入,对bean也就是service进行代理。


2、解决循环依赖

image.png

3、基于 JDK、CGLIB 实现 AOP 切面

  • 只处理一些需要被拦截的方法。在拦截方法后,执行你对方法的扩展操作。
  • 我们就需要先来实现一个可以代理方法的 Proxy,其实代理方法主要是使用到方法拦截器类处理方法的调用 MethodInterceptor#invoke,而不是直接使用 invoke 方法中的入参 Method method 进行 method.invoke(targetObj, args) 这块是整个使用时的差异。
3.1、Pointcut 切点接口
/**
 * @ClassName: Pointcut
 * @Author: 小飞
 * @Date: 2023/3/29 16:11
 * @Description: 切入点接口,定义用于获取 ClassFilter、MethodMatcher 的两个类,
 * 这两个接口获取都是切点表达式提供的内容
 */
public interface Pointcut {


    /**
     * 获取反射类拦截器(匹配器)
     * @return
     */
    ClassFilter getClassFilter();

    /**
     * 获取方法匹配器
     * @return
     */
    MethodMatcher getMethodMatcher();

}
  • 切入点接口,定义用于获取 ClassFilter、MethodMatcher 的两个类,这两个接口获取都是切点表达式提供的内容。
3.2、ClassFilter 类匹配

定义类匹配类,用于切点找到给定的接口和目标类。

3.3、MethodMatcher 方法匹配

方法匹配,找到表达式范围内匹配下的目标类和方法。在上文的案例中有所体现:methodMatcher.matches(method, targetObj.getClass())

3.4、AspectJExpressionPointcut 切点表达式

切点表达式实现了 Pointcut、ClassFilter、MethodMatcher,三个接口定义方法,同时这个类主要是对 aspectj 包提供的表达式校验方法使用。

3.5、TargetSource 切面通知信息

被代理的目标对象,获取 AOP 调用的当前目标在调用 AOP 代理对象的方法时,在执行完所有的 advice chain 之后,最终会通过反射调用这个目标 target 的方法。

3.6、AdvisedSupport(封装类)
  • AdvisedSupport,主要是用于把代理、拦截、匹配的各项属性包装到一个类中,方便在 Proxy 实现类进行使用。这和你的业务开发中包装入参是一个道理
  • TargetSource,是一个目标对象,在目标对象类中提供 Object 入参属性,以及获取目标类 TargetClass 信息。
  • MethodInterceptor,是一个具体拦截方法实现类,由用户自己实现 MethodInterceptor#invoke 方法,做具体的处理。
3.7、Cglib2AopProxy 实现类
  • 基于 Cglib 使用Enhancer代理的类可以在运行期间为接口使用ASM字节码增强处理对象生成。
  • 扩展进去的用户拦截方法使用Enhancer#setCallback 中处理,用户自己的新增的拦截处理。
3.8、JdkDynamicAopProxy 实现类
  • 基于 JDK 实现的代理类,实现 AopProxy、InvocationHandler 就可以将代理对象 getProxy 和反射调用方法 invoke 隔离处理。
  • invoke 方法中主要处理匹配的方法后,使用用户自己提供的方法拦截实现,做反射调用 methodInterceptor.invoke 。
  • ReflectiveMethodInvocation,其他它就是一个入参的包装信息,提供了入参对象:目标对象、方法、入参。

4、将AOP融合Bean生命周期

我们不可能把底层的方法提供给用户使用,首先操作逻辑太复杂,然后底层提供用户会不安全性。所以我们需要将 AOP 代理的对象融入到Bean周期中,在生成AOP对象的时候一样通过配置对应的spring.xml信息来封装,在createBean方法中判断AOP 对象会特定实现了某个对象,选择其他的实例化方式。

4.1、Advice 拦截链
  1. 定义前置通知 BeforeAdvice 通知链,在目标对象被执行前被调用,通知类型。

MethodBeforeAdvice

4.2、Advisor 访问者

用于把一个Advice和一个Pointcut组合起来。 访问者Advisor是Spring AOP的顶层抽象,用来管理Advice和Pointcut(PointcutAdvisor和切点有关,但IntroductionAdvisor和切点无关)
子类接口 PointcutAdvisor 承担了 Pointcut 和 Advice 的组合,Pointcut 用于获取 JoinPoint,而 Advice 决定于 JoinPoint 执行什么操作。

4.3、AdvisedSupport (封装类)

添加了动态代理类型的配置信息
要是用于把代理、拦截、匹配的各项属性包装到一个类中,方便在 Proxy 实现类进行使用。AOP代理配置管理器的基类。 它封装了AOP中对通知 (Advice)和通知器 (Advisor)的相关操作, 这些操作对于不同的AOP的代理对象的生成都是一样的,但对于具体的AOP代理对象的创建,AdvisedSupport把它交给子类去实现。

4.4、ProxyFactory

代理工厂
image.png
通过AdvisedSupport中的配置信息 创建对应类型的动态代理对象。(默认是JDK代理

4.5、InstantiationAwareBeanPostProcessor

实例化前后感知类 作为扩展类接口
postProcessBeforeInstantiation 接口方法作用:提供给用户的扩展接口 如果自定义的代理类则直接返回Bean 不需要执行Spring容器的流程

4.6、DefaultAdvisorAutoProxyCreator

默认将bean容器中所有的 Advisor 都取到,如果有能够匹配某一个bean的 Advisor 存在,则会基于能够匹配该bean的所有 Advisor 创建对应的代理对象。

  • 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInstantiation 方法中,从通过 beanFactory.getBeansOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,之后返回代理对象即可。
  • 那么现在调用方获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。
4.7、AbstractAutowireCapableBeanFactory

继承 AbstractBeanFactory 类的抽象方法,实现对应的 createBean 方法,在第一步判断是否需要返回代理的 Bean 对象

调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法
而该类被 AdvicedSupport 继承进行包装成 AdvisedSupport 对象传入到 ProxyFactory 返回一个代理对象。

5、自动扫描 Bean 对象注册

5.1、PropertyPlaceholderConfigurer 类

资源属性的配置器
依赖于 BeanFactoryPostProcessor 在 Bean 生命周期的属性,可以在 Bean 对象实例化之前,改变属性信息。

5.2、ClassPathScanningCandidateComponentProvider
  • 这里先要提供一个可以通过配置路径 basePackage=cn.wen.springframework.test.bean,解析出 classes 信息的工具方法 findCandidateComponents,通过这个方法就可以扫描到所有 @Component 注解的 Bean 对象了。

6、注解注入属性信息

自动扫描包注册 Bean 对象之后,就需要把原来在配置文件中通过 property name=“token” 配置属性和Bean的操作,也改为可以自动注入。这就像我们使用 Spring 框架中 @Autowired、@Value 注解一样,完成我们对属性和对象的注入操作。

  • 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性 applyPropertyValues 填充之前 ,把属性信息写入到 PropertyValues 的集合中去。这一步的操作相当于是解决了以前在 spring.xml 配置属性的过程。
  • 还有一个是关于 @Autowired 对于对象的注入,其实这一个和属性注入的唯一区别是对于对象的获取 beanFactory.getBean(fieldType),其他就没有什么差一点了。
6.1、StringValueResolver

接口 StringValueResolver 是一个解析字符串操作的接口

  • 在解析属性配置的类 PropertyPlaceholderConfigurer 中,最主要的其实就是这行代码的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 这是把属性值写入到了 AbstractBeanFactory 的 embeddedValueResolvers 中。

将解析后的StringValue列表存储到 AbstractBeanFactory 抽象类的List集合中。

6.2、InstantiationAwareBeanPostProcessor

添加postProcessPropertyValues的方法来实现 Bean 对象执行初始化之前,执行该方法。

6.3、AutowiredAnnotationBeanPostProcessor

处理 @Value、@Autowired,注解的 BeanPostProcessor

  • AutowiredAnnotationBeanPostProcessor 是实现接口 InstantiationAwareBeanPostProcessor 的一个用于在 Bean 对象实例化完成后,设置属性操作前的处理属性信息的类和操作方法。
  • 核心方法 postProcessPropertyValues,主要用于处理类含有 @Value、@Autowired 注解的属性,进行属性信息的提取和设置。
/**
 * @ClassName: ClassPathBeanDefinitionScanner
 * @Author: 小飞
 * @Date: 2023/3/30 14:26
 * @Description: 扫描指定路径的注解并且解析到BeanDefinition对象中
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void doScan(String... basePackages) {
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidates) {
                // 解析 Bean 的作用域 singleton、prototype
                String beanScope = resolveBeanScope(beanDefinition);
                if (StrUtil.isNotEmpty(beanScope)) {
                    beanDefinition.setScope(beanScope);
                }
                registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);
            }
        }
        // 注册处理注解的 BeanPostProcessor(@Autowired、@Value)
        registry.registerBeanDefinition("cn.wen.springframework.context.annotation.internalAutowiredAnnotationProcessor", new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
    }

    /**
     * 扫描 Scope 注解并且返回内容
     * @param beanDefinition
     * @return
     */
    private String resolveBeanScope(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Scope scope = beanClass.getAnnotation(Scope.class);
        if (null != scope) return scope.value();
        return StrUtil.EMPTY;
    }

    /**
     * 扫描 Component 注解并且返回 Value
     * @param beanDefinition
     * @return
     */
    private String determineBeanName(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Component component = beanClass.getAnnotation(Component.class);
        String value = component.value();
        if (StrUtil.isEmpty(value)) {
            value = StrUtil.lowerFirst(beanClass.getSimpleName());
        }
        return value;
    }


}

ClassPathBeanDefinitionScanner#doScan 方法中注册扫描方法。

6.4、注册到Bean的生命周期

在设置 Bean 属性注入之前,允许 BeanPostProcessor 修改属性值
AbstractAutowireCapableBeanFactory#createBean 方法中 Bean 实例化之后 Bean属性填充之前调用该方法。

  1. bean = createBeanInstance(beanDefinition, beanName, args);
  2. applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
  3. applyPropertyValues(beanName, bean, beanDefinition);

7、代理对象填充属性

因为之前的Aop动态代理是融入了Bean的生命周期,创建动态代理是在整个创建Bean对象之前的,并不能执行Spring容器的创建Bean 初始化的执行流程,需要将动态代理的的逻辑迁移到 Bean 对象执行初始化之前,实例化之后。

7.1、Bean 生命周期插入

  • 在 AbstractAutowireCapableBeanFactory#createBean 方法中,其实关注点就在于initializeBean -> applyBeanPostProcessorsAfterInitialization 这一块逻辑的调用,最终完成 AOP 代理对象的创建操作。
  • applyBeanPostProcessorsAfterInstantiation 方法的作用就是给用户提供扩展的接口,用户实现 接口InstantiationAwareBeanPostProcessor 同时重写postProcessAfterInstantiation 方法配置是否需要注入到spring容器中,可以实现定制化注入操作。

这一段代码是Spring用来提供给程序员扩展使用的, 如果我们不希望一个bean参与到属性注入, 自动装配的流。程中, 那么就可以创建一个InstantiationAwareBeanPostProcessor后置处理器的实现类, 重写其 postProcessAfterInstantiation方法, 如果该方法返回false, 那么continueWithPropertyPopulation这个变量会被置为false, 而这个变量被置为false, 在下面我们可以看到直接就return了, 从而Spring就不会对属性进行注入。

8、循环依赖

循环依赖主要分为这三种,自身依赖于自身、互相循环依赖、多组循环依赖。
所以需要 Spring 提供了除了构造函数注入和原型注入外的,setter 循环依赖注入 。
就是用于解决循环依赖就必须是三级缓存呢,二级行吗?一级可以不?其实都能解决,只不过 Spring 框架的实现要保证几个事情,如只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。另外 Spring 的两大特性中不仅有 IOC 还有 AOP,也就是基于字节码增强后的方法,该存放到哪,而三级缓存最主要,要解决的循环依赖就是对 AOP 的处理,但如果把 AOP 代理对象的创建提前,那么二级缓存也一样可以解决。但是,这就违背了 Spring 创建对象的原则,Spring 更喜欢把所有的普通 Bean 都初始化完成,在处理代理对象的初始化。
不过,没关系我们可以先尝试仅适用一级缓存来解决循环依赖,通过这样的方式从中学习到处理循环依赖的最核心原来,也就是那 20%的地方。

  • 如果仅以一级缓存解决循环依赖,那么在实现上可以通过在 A 对象 newInstance 创建且未填充属性后,直接放入缓存中。
  • 在 A 对象的属性填充 B 对象时,如果缓存中不能获取到 B 对象,则开始创建 B 对象,同样创建完成后,把 B 对象填充到缓存中去。
  • 接下来就开始对 B 对象的属性进行填充,恰好这会可以从缓存中拿到半成品的 A 对象,那么这个时候 B 对象的属性就填充完了。
  • 最后返回来继续完成 A 对象的属性填充,把实例化后并填充了属性的 B 对象赋值给 A 对象的 b 属性,这样就完成了一个循环依赖操作。


在创建对象的 AbstractAutowireCapableBeanFactory#doCreateBean 方法中,提前暴露对象以后,就可以通过接下来的流程,getSingleton 从三个缓存中以此寻找对象,一级、二级如果有则直接取走,如果对象是三级缓存中则会从三级缓存中获取后并删掉工厂对象,把实际对象放到二级缓存中。

8.1、DefaultSingletonBeanRegistry


提供三级缓存的容器:

  1. singletonObjects(普通对象):存储完全初始化好的 Bean 对象,可直接使用
  2. earlySingletonObjects(二级缓存):提前暴漏对象,没有完全实例化的对象
  3. singletonFactories(三级缓存):存放代理对象


  • 在用于提供单例对象注册的操作的 DefaultSingletonBeanRegistry 类中,共有三个缓存对象的属性;singletonObjects、earlySingletonObjects、singletonFactories,如它们的名字一样,用于存放不同类型的对象(单例对象、早期的半成品单例对象、单例工厂对象)。
  • 紧接着在这三个缓存对象下提供了获取、添加和注册不同对象的方法,包括:getSingleton、registerSingleton、addSingletonFactory,其实后面这两个方法都较简单,主要是 getSingleton 的操作,它是在一层层处理不同时期的单例对象,直至拿到有效的对象。
  • 一级缓存:在最上层的缓存singletonObjects中,缓存的是完整的单例bean,这里面拿到的bean是已经实例化好和初始化好的bean,可以直接使用的bean。如果没有取到,则进入2处
  • 二级缓存:在二级缓存earlySingletonObjects中,查找bean。二级缓存主要缓存的分成两种情况,只要看这个bean是否被AOP切面处理:
    • 否:保存半成品的bean原始实例,属性未填充
    • 是:保存的是代理的bean,即proxyBean,目标bean还是未填充属性的半成品
  • 三级缓存:如果在二级缓存中,还是没有找到,则在三级缓存中查找对应的工厂对象,利用拿到的工厂对象(工厂中有3个field,一个是beanName,一个是RootBeanDefinition,一个是已经创建好的,但是还没有注入属性的bean)去获取包装后的bean,或者说,代理后的bean。


主要功能就是通过ObjectFactory 的一个内部类来获取一个单例代理对象,需要添加到三级缓存中,三级缓存就是存放的一个Bean对象的 ObjectFactory 对象。

8.2、三级缓存解决循环依赖

我们以这样一个示例:

  • AService -> BService
  • BService -> AService

AService依赖BService,BService也依赖AService,加入在getBean(aService)的时候,进入doCreateBean:
Spring首先是加个三级缓存,里面存的不是具体的bean,而是一个工厂对象,是可以拿到代理的bean的
在上述的doCreateBean中有一段如下代码:

private Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
    Object bean = null;
    try {
        // 实例化 bean
        bean = createBeanInstance(beanDefinition, beanName, args);

        // 处理循环依赖,将实例化后的Bean对象提前放入缓存中暴露出来
        // 为避免后期循环依赖, 可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
        if (beanDefinition.isSingleton()) {
            Object finalBean = bean;
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
        }

    }
}

这里new了一个ObjectFactory,然后会存入到如下的第三级缓存中:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory){
    if (!this.singletonObjects.containsKey(beanName)) {
        // 存储到三级缓存 然后再将二级缓存中的记录删除
        this.singletonFactories.put(beanName, singletonFactory);
        this.earlySingletonObjects.remove(beanName);
    }
}
  • 虽然我们的 AService 不能再一级缓存中命中,但是我们在创建AService时已经将AService的ObjectFactory 存入到三级缓存中,在三级缓存中命中了 AService 的ObjectFactory 可以获取到 AService的代理对象只是还未属性注入而已。通过三级缓存拿到其ObjectFactory,然后getObject()方法获取到其代理对象。这个getObject就是上文中提到的匿名内部类getEarlyBeanReference获取的对象,即代理对象AService
  • 此时BService完成AService的注入,BService变成一个完整的对象,且是经过BeanPostProcessor改变后的代理对象。并存放到了一级缓存中。

继续走AService的属性注入流程,此时BService的代理对象已经创建完成并返回,AService注入BService时BService其实是一个完整的代理对象。AService注入并放入一级缓存,这样就完美的解决了循环依赖的问题。
最后我们总结一下上面的创建流程:

  • AService首先实例化,实例化通过ObjectFactory半成品暴露在三级缓存中
  • 填充属性BService,发现BService还未进行加载,就会先去加载BService
  • 在加载BService过程中,实例化,通过ObjectFactory半成品暴露在三级缓存中
  • 填充属性AService的时候,这时候能够从三级缓存中拿到半成品的ObjectFactory
  • 拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法,此方法最终会调用到getEarlyBeanReference()方法,这个方法主要逻辑是如果bean被AOP切面代理则返回的是proxyBean,如果未被代理则返回的是原始originBean。
  • 此时拿到AService的半成品代理bean,然后从三级缓存中移除,放到二级缓存earlySingletonObjects中,此时BService注入的AService其实是一个半成品的AService代理对象(原始对象),最终BService完成的创建,
  • 回来继续走AService的属性填充,最终完成的BService会被注入进去,AService完成创建
  • 最终BService的属性AService也是一个完整的对象,因为他们是同一个对象
8.3、二级缓存解决不了?

其实到这里,很多人想为什么不用二级缓存,而非得用三级缓存才能解决循环依赖呢。
二级缓存有两种组合方式:

  • singletonObjects和earlySingletonObjects
  • singletonObjects和singletonFactories

不管哪种组合方式,我们看上面的示例(AService依赖BService,BService同样依赖AService)能否走通就可以了。

singletonObjects和earlySingletonObjects组合

我们直接看流程:

  1. AService创建,放入早期的earlySingletonObjects缓存,缓存的是半成品AService对象。走到属性注入BService
  2. 发现BService没有创建,开始创建BService
  3. 创建BService,属性注入AService,首先从缓存中获取AService,能获取到半成品的AService,进行注入到BService的字段中,BService完成创建并返回。删除earlySingletonObjects并添加singletonObjects缓存
  4. 继续走AService注入属性的流程,拿到完整的BService对象,注入到对象中去。然后删除earlySingletonObjects缓存并添加singletonObjects缓存
  5. 此时BService拿到的AService对象是一个完整的对象,因为他们是同一个对象

singletonObjects和singletonFactories组合

同样,我们也直接看流程

  1. AService创建,拿到ObjectFactory放入singletonFactories缓存中,缓存的同样是半成品的AService的ObjectFactory,走到属性注入BService
  2. 发现BService没有创建,开始创建BService
  3. 创建BService,属性注入AService,首先从缓存中singletonFactories能获取到AService的ObjectFactory,然后调用其getObject函数拿到AService,此时AService同样是个半成品的,注入到BService的字段中,BService完成创建并返回。删除singletonFactories并添加singletonObjects缓存
  4. 继续走AService注入属性的流程,拿到完成的BService对象,注入到对象中去,然后删除singletonFactories缓存并添加singletonObjects缓存
  5. 此时BService拿到的AService对象是一个完整的对象,因为他们是同一个对象

不管是哪一种组合,我们看这个流程似乎都没有问题,也确实,这种流程走下来确实是没有问题的。但是我们忽略了一个重要的特性:AOP。

存在AOP的情况(singletonObjects和singletonFactories)

我们都知道AOP其实是通过BeanPostProcessor的postProcessAfterInitialization织入的,并且我们在存在AOP代理的情况下,ObjectFactory.getObject()最终调用的是getEarlyBeanReference方法:
getEarlyBeanReference方法,我们看其父类AbstractAutoProxyCreator的方法:
image.png
我们可以看到先生成缓存key,再存入缓存,最后调用wrapIfNecessary方法,wrapIfNecessary这个方法我们似乎很熟悉,在AOP的一章节中,发现AOP的postProcessAfterInitialization调用的就是这个方法,具体实现是在AbstractAutoProxyCreator中:
是的,他们最终走到的都是wrapIfNecessary方法,但是整个加载流程只会走一次,因为这里有一个缓存key。现在理解这个缓存的作用了。
那么我们继续看,拿到的ObjectFactory其实是一个匿名内部类,内部类的bean是AOP代理的bean。每次getObject的时候其实是走AOP代理的逻辑,那么这里就有问题了,如果每次都ObjectFactory.getObject()都是一个新的对象,前后无法关联,最终导致BService注入的AService并不是一个完整的AService。所以,此时我们可以否定singletonObjects和singletonFactories的组合了。

存在AOP的singletonObjects和earlySingletonObjects

注意,这里是关键,我们直接将三级缓存去掉,而是直接调用singletonFactory.getObject()存放缓存。而这个ObjectFactory我们知道是从getEarlyBeanReference获取到的匿名内部类。所以存进去的二级缓存直接是早期的未填充属性的对象。

结论就是二级缓存(singletonObjects和earlySingletonObjects)可以解决循环依赖

  1. 问题就在于调用getEarlyReference,这一步在很多时候其实是没有必要的,在没有循环依赖的时候,这个方法是不会被调用。也就是说,我们为了解决系统中那百分之一的可能,而让99%的bean创建的时候都走上一圈。效率上说不过去
  2. Spring官方建议我们使用构造器方式注入,而使用构造器注入我们知道是无法解决循环依赖问题的。这么看的话其实不是Spring的自相矛盾吗?所以猜测Spring是不希望我们使用Spring的循环依赖的,因为能在项目启动中就爆出问题远远比在项目运行后不知道什么时候爆出问题的严重程度要小。
  3. 方便后续的扩展

如果创建的Bean有对应的aop代理,那其他对象注入时,注入的应该是对应的代理对象;「但是Spring无法提前知道这个对象是不是有循环依赖的情况」,而正常情况下(没有循环依赖情况),Spring都是在对象初始化后才创建对应的代理。这时候Spring有两个选择:

  1. 不管有没有循环依赖,实例化后就直接创建好代理对象,并将代理对象放入缓存,出现循环依赖时,其他对象直接就可以取到代理对象并注入(只需要2级缓存,singletonObjects和earlySingletonObjects即可)
  2. 「不提前创建好代理对象,在出现循环依赖被其他对象注入时,才提前生成代理对象(此时只完成了实例化)。这样在没有循环依赖的情况下,Bean还是在初始化完成才生成代理对象」(需要3级缓存)

所以说,从功能上来说,完全可以使用二级缓存(singletonObjects和earlySingletonObjects)解决循环依赖的问题,但是出于效率性和扩展性来说,Spring采用了三级缓存解决这个问题。
image.png

Spring框架】一篇文章带你彻底搞懂Spring解决循环依赖的底层原理
小七的博客
09-04 6877
史上最全的Spring循环依赖源码详解,一篇文章带你彻底搞懂Spring解决循环依赖的底层原理,横扫面试场。
一步步深入理解Spring内部原理-带源码
11-10
用一个小项目模拟出一个微型的spring项目,实现spring的核心功能-aop,ioc和自动注入,帮助初学者了解spring的运行原理,以后面试再也不怕碰到问spring原理的问题了
Spring底层篇
最新发布
m0_69912089的博客
08-20 847
3、request:为每个request请求创建一个实例,请求完成后失效。有状态表示示例是有属性对象,可以保存数据,是线程不安全的, 比如 pojo.1> 对于prototype作用域,每次都是生成一个新的对象,所以不存在线程安全问。是无状态的,不需要保证线程安全。在发现有循环依赖时,1、 sington 2、prototype: 为每个Bean请求创建给实例。无状态表示这个实例没有属性对象, 不能保存数据,是不变的类。循环依赖: 多个对象之间存在循环的引用关系,在初始化过程当中,就会出现"先有。
Spring框架底层原理- AOP
ONESTARの博客
01-09 931
一、概述 1. 什么是AOP AOP(Aspect Oriented Programming):面向切面编程,指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的操作。如:性能监控、日志记录、权限控制等,通过AOP解决代码耦合问题,让职责更加单一。 AOP技术它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少
spring底层原理
weixin_44235759的博客
03-21 774
bean的生命周期 UserService.class —> 无参构造 —> 对象 —> 依赖注入 —> Bean对象 依赖注入底层原理 找到对象中添加了@Autowired的属性 给属性设置值 单例bean Map<beanName,Bean对象> 单例池 getbean首先会去单例池中找,如果找不到创建并放入单例池 UserService.class —> 无参构造 —> 对象 —> 依赖注入 —> 放入Map(单例池) —> Be.
Spring框架(一) 底层核心原理解析
热门推荐
刘跃辉的博客
06-13 10万+
本系列文章以spring-framework-5.3.10为例 , 本篇文章的目的就是使各位读者能在使用Spring的基础上对Spring的一些比较核心的内容有一个大概的认识,并不是特别全面,会在后续的文章中一一讲解,不仅仅是停留在Spring简单的使用 , 而是方便后面源码的阅读以及实现方式的理解 , 文章仅是作者自己在学习Spring过程中的案例演示以及知识总结 , 如果表达不当 , 还请及时指教首先我们来看一段代码 APPConfig代码 从代码实现方式不难看出 , ClassPathXmlAppl
Spring底层原理
weixin_43730516的博客
03-04 417
关于什么是Ioc这篇博客说的很清楚了,但也有一些不足的地方,就是Spring的IoC容器是使用了反射机制和工厂模式。 Ioc的概念以及理解 再理解Ioc具体原理之前,先理解一下Java反射机制. 通过反射机制可以实现上层类对下层类的"控制"(无论是函数、私有的属性都可以访问)。 使用反射机制来实现Controller层访问Service层 Controller层 public class UserController { private UserService userService;.
超详细的SpringCloud底层原理
青藤的博客
05-24 9097
先来个简单的介绍吧! SpringCloud框架 针对这个架构图我分层介绍一下: 1、是web服务器的选型,这个我选择的是nginx+keepalived,haproxy也是一个选择,但是haproxy在反向代理处理跨域访问的时候问题很多。所以我们nginx有些地方做了keep-alive模式处理,减少了三次握手的次数,提高了连接效率。keepalived做nginx的负载,虚拟一个vip对外,两个nginx做高可用,nginx本身反向代理zuul集群。 2、api gateway,这里的zuu
spring 事物底层原理分析1
08-08
Spring 事务底层原理分析】 在软件开发中,Spring 框架提供了强大的事务管理功能,使得开发者能够方便地在应用程序中控制事务。本篇主要分析 Spring 事务的底层实现原理,包括数据库事务的基本特性、Spring 对...
简单了解SPRINGIOC的底层原理演变过程
08-25
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它使得开发者不再需要手动管理对象的创建和依赖关系,而是由Spring容器来负责这些工作。在本文中,我们将探讨Spring IOC的底层原理及其...
SpringBoot学习代码模拟SpringBoot框架底层原理源代码
06-16
SpringBoot的学习过程中,理解其底层原理是非常重要的,这有助于我们更高效地开发和优化应用。通过模拟SpringBoot框架的源代码,我们可以深入探究其内部机制。 首先,让我们来探讨SpringBoot的核心特性: 1. **...
spring security原理和机制 | Spring Boot 35
学Java,找哪吒
06-25 5万+
一、SpringSecurity 框架简介 Spring 是非常流行和成功的 Java 应用开发框架Spring Security 正是 Spring 家族中的 成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方 案。 正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控 制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权 (Authorization)两个部分,这两点也是 Spring
SpringSpring底层核心原理解析
haohaoxuexiyai的博客
02-18 3654
本文内容索引: 1.Bean的生命周期底层原理 2.依赖注入底层原理 3.初始化底层原理 4.推断构造方法底层原理 5.AOP底层原理 6.Spring事务底层原理 ​但都只是大致流程,后续会针对每个流程详细深入的分析源码实现。 先来看看入门使用Spring的代码: ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (Use
通俗易懂话spring底层原理
alizhuana的博客
03-04 1814
spring是目前java开发必须熟练掌握的框架,面试的时候spring也是必问的问题之一。下面将以Q&amp;A的方式回答面试中可能出现的spring框架问题。其中重点将会以不同的颜色标识出来。 1.Q:什么是spring? A:Spring是一个轻量级的,用来装javabean的,控制反转(IoC)和面向切面(AoP)的容器框架,它可以使得开发者更专注于应用程序的开发。从简单性、可测...
spring入门--Spring框架底层原理
weixin_30497527的博客
02-19 60
上一篇的博客,我们可以看出来,spring可以维护各个bean (对象),并向其中注入属性值。那么,如果们要把一个对象的引用注入另外一个对象呢?应该怎么处理呢?    我们知道,对于对象中的属性来说,我们注入属性的方式为:在配置文件中使用property标签。   <property name="对象属性名称" >   <value>要注入的内容...
Spring底层实现原理
qq_36235282的博客
11-05 475
Spring底层实现原理 spring说到底其实离不开IOC和AOP IOC: 传统开发中创建对象用new,这样导致的后果是耦合度太高,不符合java编程思想,ioc就是让sprin给你创建对象。 原理是: 先加载xml文件,通过dom4j进行解析,通过工厂模式和反射创建对象。实现了高内聚低耦合·。 AOP: 比如一个家庭日常可能有许多事务,比如买菜做饭,看电视等等,这些都是我们可以控制的,AOP就是比如我们日常用电,需要电表来记电费,这个电费不需要我们手动去记但是它又出现在我们日常生活的很多事件中,所以我
Spring的基本底层原理
nice_good_boy的博客
03-30 388
Spring 核心:ioc和aop IOC:控制反转,把创建对象过程交给Spring进行管理 AOP:面向切面:不修改源代码进行功能增强 特点: 1.方便解耦,简化开发 2.AOP编程支持 3.方便程序的测试 4.方便和其他框架进行整合 5.方便进行事务操作 6.降低API开发 spring使用的基本步骤 1.配置xml文件 2.加载spring配置文件 3.获取配置创建的对象 IOC容器 把对象的创建和对象之间的调用过程,交给Spring进行管理,这样可以降低了对象之间的耦合度 IOC底层原理 1.
spring框架底层原理
大连赵哥的博客
04-12 307
spring框架底层原理
SpringCloud微服务架构底层原理详解
本文将深入探讨SpringCloud的底层原理,重点关注其核心组件:Eureka、Feign、Ribbon、Hystrix和Zuul。 首先,我们通过一个业务场景——电商网站的支付订单流程,来理解微服务架构的应用。在这个场景中,多个服务...
写文章

热门文章

  • RSA & ECDHE 算法 2420
  • 了解JWT(跨域) 2050
  • 你能区分这几种Java集合类型? 1759
  • 什么是Nginx? 1637
  • Spring 框架底层原理 1143

分类专栏

  • Java 9篇
  • Spring 3篇
  • nginx
  • 运维 1篇
  • JVM 1篇
  • 前端
  • 算法
  • Mybatis 1篇
  • Spring 框架 1篇
  • 计算机网络 1篇
  • 笔记

最新评论

  • 如何实现布隆过滤器?

    普 通 用 户: 这篇博客让我受益匪浅。作者通过自己的经验和见解,给我们提供了很多有价值的信息,非常感谢!

  • Spring MVC底层分析

    Kwan的解忧杂货铺@新空间代码工作室: 博主的文章一直都是我的学习圣经,内容详实,通俗易懂,希望博主能一如既往地分享知识,帮助更多人成长。你的博文总是给予我新的思考和启发,真的很感谢你一直以来的辛勤付出。每篇博客都是知识的瑰宝,我真的很喜欢你的风格,期待你的下一次精彩分享。

  • RSA & ECDHE 算法

    CSDN-Ada助手: 恭喜您撰写了第10篇博客!标题“RSA & ECDHE 算法”听起来非常引人注目。您对密码学算法的深入探索令人印象深刻。我很欣赏您对这些复杂主题的解释和分享。 在接下来的创作中,我建议您可以考虑探索更多与这两种算法相关的实际应用案例,如数据加密、数字签名等方面。这将进一步拓宽读者的知识领域,并激发更多的讨论和思考。 请继续保持博客创作的势头,我期待着您未来更多的精彩内容!

大家在看

  • 单片机通过AT指令控制ESP8266+TCP 实现收发数据
  • STM32--JQ8900语音模块
  • 论文 Python 实现WOA-CNN-BiGRU-Attention数据分类预测 64
  • 手环押金原路退回系统——足浴店——东方仙盟

最新文章

  • 如何实现布隆过滤器?
  • 你了解Java异常?
  • Spring MVC底层分析
2024年9篇
2023年7篇
2022年1篇
2021年4篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家保山市玻璃钢雕塑价格西安动物玻璃钢雕塑池州创意玻璃钢雕塑订做价格商场整体氛围美陈晋中玻璃钢广场雕塑价格玻璃钢鹿雕塑收费玻璃钢雕塑模型怎么上色商场铺位门前美陈房山区景区绿化玻璃钢花盆如皋玻璃钢雕塑联系方式长宁区玻璃钢雕塑中山玻璃钢孔雀雕塑安徽知名玻璃钢雕塑按需定制平顶山玻璃钢卡通雕塑玻璃钢鹿子雕塑甘肃仿真人物玻璃钢雕塑安装河南秋季商场美陈采购红腹锦鸡玻璃钢雕塑广东小区装饰玻璃钢美陈雕塑大型商场店庆美陈商场女装美陈南宁学校玻璃钢雕塑订做价格石家庄佛像玻璃钢雕塑玻璃钢恐龙雕塑该怎么做玻璃钢雕塑设计新颖玻璃钢动漫人物雕塑时代广场玻璃钢雕塑信誉好的大型玻璃钢雕塑深圳玻璃钢雕塑有哪些威海玻璃钢雕塑多少钱香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化