Spring核心扩展点底层原理

一、Spring中的Bean的生命周期详解

整体概要流程:

Class--->创建对象--->依赖注入(属性赋值)--->init初始化(before,after)--->awre--->bean--->SpringContext(容器).

1、第一阶段:Class--->创建对象(也就是怎么通过类来创建对象的)?

class---->先扫描---->得到BeanDefinition----->创建对象

1、BeanDefinition:bean的定义,在我们通过一个普通类需要创建对象之前要做的事情,就是怎么定义我们的类,这里面就设计到很多的模块方法,比如:要设置创建是一个单实例的对象还是要创建一个多实例的对象呢?等。

那BeanDefinition是怎么生成的呢,生成的方式有多种,比如@Bean或者利用xml的方式来生成,还有通过包扫描的方式找到,项目在启动的时候会加载我们配置文件,配置文件中就有各种包扫描的路径等。

如图:bean的定义BeanDefinition模块图

2、类的定义好后,将定义的好的信息放入到我们bean工厂里面去也就是我们的BeanFactory。

ApplicationContextapplicationContext=newAnnotationConfigApplicationContext(MainConfig.class);

User user = applicationContext.getBean(User.class);

通过我们getBean跟踪进去,会有多种的bean工厂接口,默认会到我们DefaultListableBeanFactory工厂里面,这里面定义了一个BeanDefinitionMap对象也就是这个ConcurrentHashMap这个map对象

/** Map from serialized id to factory instance:从序列化ID映射到工厂实例 */
	private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
			new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);

ConcurrentHashMap的key就是beanName(bean的名字); value就是我们类定义的信息也就是我们的 BeanDefinition ,这个地方是记录了下当前工厂里面有哪些bean,这个阶段bean还没有生成。

3、拿到BeanDefinition,通过构造方法来实现bean的创建,bean创建完后会放到singletonObjects(ConcurrentHashMap)中来。

4、创建完bean后,创建完怎么去处理这个bean呢?通过我们bean的后置处理器(beanPostProcessor)来处理(如:给bean赋值,依赖注入,bean的初始化等操作)。bean工厂里面有很多的后置处理器,也可以自定义后置处理器。 

bean的后置处理器的定义:生成对象之后所调用的逻辑,执行顺序是先有了工厂-->然后去执行工厂的后置处理器---bean,后置处理器相当于去修改我们的工厂的bean. 

模块图:

细化后的执行流程:

Class--->BeanDefinition->BeanFactory--->BeanFactoryProcessor---->创建对象--->依赖注入(属性赋值)--->init初始化(before,after)--->awre--->bean--->SpringContext(容器).

beanFactory和ApplicationContext这个工厂的区别:

他们两是父子关系,ApplicationContext继承了ListableBeanFactory,ListableBeanFactory继承了beanFactory,而且在ApplicationContext在继承拥有所有beanFactory功能后还继承了其他的组件,如下图分析:

 

二、Spring整合Mybatis底层原理详解

mybatis和Spring整合的目标就是怎么将Dao层的接口注册到Spring容器成为一个bean的问题,从上面的分析要将一个对象注册到spring容器中,必须是类.class才行,很显然Dao层是一个接口,没办法new,肯定不能直接注入进去的,那怎么解决呢这个问题?

1、怎么将一个对象放入到我们的容器中,有多种方式,有@bean、@Import、 xml等方式,还有一种就是通过实现FactoryBean接口的方式去注入bean的,这种就是我们自定义的方式,我们的spring与mybatis的整合就是用这种方式来注册bean的。

实例分析:

package com.tan.util;

import com.tan.bean.Dog;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

//自定实现bean的注册的另一种方式
@Component
public class DemoFactoryBean implements FactoryBean{

    //通过这个方法就可以将一个类放入到我们工厂里面去了
    public Object getObject() throws Exception {
        return new Dog();
    }

    public Class<?> getObjectType() {
        return Dog.class;
    }

    public boolean isSingleton() {
        return false;
    }
}

通过断点调试看bean工厂怎么拿到实现FactoryBean的类的,这个是比较特殊的拿法,一般是到singletonObjects中取拿的,但是这种先从singletonObjects去拿,如果没有再去我们的factoryBeanObjectCache对象中去拿,如下图所示:

这里的FactoryBean与前面说的BeanFactory的区别是什么:

FactoryBean是一个小的工厂,他一次只能生成一个对象,而BeanFactory是一个大的工厂。

因为上面的DemoFactoryBean类通过getObject方法返回的是静态写死的对象,那怎么写活呢?那就通过JDK的代理模式生成一个代理类,实例代码如下:

//自定实现bean的注册的另一种方式
@Component
public class DemoFactoryBean implements FactoryBean{

    private Class mappers;

    public DemoFactoryBean(Class mappers) {
        this.mappers = mappers;
    }

    //通过这个方法就可以将一个类放入到我们工厂里面去了
    //UserDao代理对象--->bean
    public Object getObject() throws Exception {

        Object o = Proxy.newProxyInstance(DemoFactoryBean.class.getClassLoader(), new Class[]{mappers}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
        return o;
    }

    public Class<?> getObjectType() {
        return mappers;
    }

    public boolean isSingleton() {
        return false;
    }
}

上面的构造函数的Class mappers是怎么传进来的呢,也就是怎么扫描dao层的接口,然后将其变成class对象的。。

第一步:

//通过自定义的包扫描直接将bean的定义信息注册到工厂里面去
public class DemoBeanDefinitionRegistarar implements ImportBeanDefinitionRegistrar{

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        //这个地方就是获取我们自定义注解的名字
        MultiValueMap<String, Object> allAnnotationAttributes = importingClassMetadata.getAllAnnotationAttributes(DemoScan.class.getName());
        //获取注解中的value值
        Object o = allAnnotationAttributes.get("value");

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

        beanDefinition.setBeanClass(DemoFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(o);

        registry.registerBeanDefinition(DemoScan.class.getName(), beanDefinition);
    }
}

第二步:自定义注解:

@Import(DemoBeanDefinitionRegistarar.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoScan {

    String value() default "";
}

第三步:全局配置文件中使用自定义的注解进行包扫描

@DemoScan("com.tan.dao")
public class MainConfig {

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值