美文网首页
Spring-源码解读之 IOC 与 DI

Spring-源码解读之 IOC 与 DI

作者: miyakee | 来源:发表于2020-03-13 15:40 被阅读0次

    1.IOC/DI

    控制反转/依赖注入

    控制反转:将创建对象的权利返给容器,让容器去控制这个对象的创建
    依赖注入:在需要用到某些对象的时候,将该对象注入到需要的地方

    注入方式:

    1. @authwired
    2. xml配置
    3. 构造器注入 (✔️)
    4. 静态工厂
    5. 实例工厂
      选择 构造器注入的 原因:
      1.提前避免循环依赖 2.确保依赖不为空

    IOC:

    重点总结:在spring内部的生成的bean的实例都是放在一个 concurrentHashmap里面的,初始化之后,会生成非lazy的单例的bean,需要的时候再取出来。

    核心代码
    bean的创建:

    Spring如何注册一个bean
    AbstractApplicationContext类里的refresh() 是bean的生命周期

    prepareRefresh(); //初始化前的准备,检查系统配置的变量
    obtainFreshBeanFactory(); //读取xml
    prepareBeanFactory(beanFactory);//对bean进行功能填充 比如qualifier和autowired的注解
    postProcessBeanFactory(beanFactory);//扩展点
    invokeBeanFactoryPostProcessors(beanFactory);//激活beanfactory的处理器,这里也会进行注册beanDefinition
    registerBeanPostProcessors(beanFactory);//注册拦截bean创建的bean的处理器
    initMessageSource();//国际化处理 为上下文初始化message源
    initApplicationEventMulticaster();//初始化应用消息广播器
    onRefresh();//留给子类初始化其他bean
    registerListeners();// 在所有注册的Bean中查找Listener Bean,注册到消息广播器中
    finishBeanFactoryInitialization(beanFactory);// 初始化剩下的单实例
    finishRefresh();// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent进行通知
    
    

    其中重要的2个阶段:

    一.注册beanDefinition阶段 —— 在 invokeBeanFactoryPostProcessors()里

    1.BeanDefinition接口 里面有一个bean基本上所有的信息,作用域,注解,方法,类名等等
    2.已经注册成功的bean会放在一个map里 beanDefinitionMap
    这个map是一个ConcurrentHashMap
    <String,BeanDeifinition>
    3.判断是否放进去了,没有的话,先判断是否第一次开始bean的创建
    不是第一次创建则对map上锁,然后把当前beanDefinition放入beanDefinitionMap里面去。
    这个时候并没有生成bean的实例
    生成beanDefinition之后,

    二. 初始化单例 的bean ——finishBeanFactoryInitialization

    在doCreateBean里是正式实例化一个bean,单例则是获取。
    调用AbstractAutowireCapableBeanFactory.createBeanInstance方法
    实例化的时候其实是用了BeanUtils.instantiateClass()里下面这段代码的反射的方式,【但是默认使用Cglib生成代理生成】
    ctor.newInstance(args))—— 通过反射获取构造函数去实例化一个类

    return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                        KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
    

    然后把这个不完整的bean包装在BeanWrapper 里 往上抛出。
    在回到doCreateBean里的populateBean()方法里。通过beanDefinition给这个bean设置属性包括【依赖】。通过注解注入的依赖和xml的依赖分别对应不同的地方实现。比如我们加了@autowired 那么就会在

    if (hasInstAwareBpps) {
                if (pvs == null) {
                    pvs = mbd.getPropertyValues();
                }
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            if (filteredPds == null) {
                                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                            }
                            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                            if (pvsToUse == null) {
                                return;
                            }
                        }
                        pvs = pvsToUse;
                    }
                }
            }
    

    这里去找到相关依赖的bean给放进bw.wrappedInstance里面。这个wrapperdInstance就是对应的我们上一层的bean的地址。
    实例化成功之后就放入singletonObjects 里。
    我们通过getBean或者注解拿到bean的时候,如果当前bean是单例且不是 lazy的 那么就是从singletonObjects
    这个currentHashMap一个取出来的过程,如果是lazy则会在取用的时候去实例化bean

    bean的获取

    1.ApplicationContextAware的applicationContext.getBean()(✔️)
    2.通过Spring提供的ContextLoader
    3.通过Spring提供的工具类获取ApplicationContext对象
    ps:关于 ApplicaionContext:
    实现ApplicationContextAware接口,就可以使用ApplicationContext
    ApplicationContext有哪些功能:
    1.applicationContext继承了beanFactory,可以得到beanFactory的功能
    2.可以发布事件/消息发布
    3.提供加载指定资源的方法

    AOP

    面向切面编程
    可以理解成在所有方法的里面加了一个过滤器 ,这个部分和业务逻辑分开,单独实现,可以作用于很多方法里。
    spring代理生成方式:
    1.JDK动态代理
    java动态代理是利用【反射】机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
    2.Cglib动态代理
    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成【子类】来处理。

    • 1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
    • 2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
    • 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    如何强制使用CGLIB实现AOP?
    (1)添加CGLIB库,SPRING_HOME/cglib/*.jar
    (2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

    JDK动态代理和CGLIB字节码生成的区别?
    (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
    (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
    因为是继承,所以该类或方法最好不要声明成final

    spring 实现AOP四种方式
    Spring提供了4种实现AOP的方式:
    1.经典的基于代理的AOP
    实现接口 MethodBeforeAdvice, AfterReturningAdvice + 配置里面加入aop的代理配置
    2.@AspectJ注解驱动的切面
    3.纯POJO切面
    其实就是纯粹通过<aop:config>标签配置
    4.注入式AspectJ切面

    springMVC
    spring的一个子模块

    spring如何实现远程调用:
    1.(主)httpInvoker - Spring httpInvoker使用标准java序列化机制,通过Http暴露业务服务。如果你的参数和返回值是比较复杂的,通过httpInvoker有巨大的优势。
    即调用者与被调用者都必须是使用Spring框架的应用

    2.RMI - RMI服务是典型的面向接口编程,只有在远程接口里定义的方法才会作为远程服务,远程方法的返回值和参数都必须实现Serializable接口,因为远程在网络上传输只能传输字节流,因此,要求参数、返回值都可以转换成字节流-即实现序列化。
    原理:RMI的具体实现,依然是依赖于底层的Socket编程。RMI依赖于TCP/IP传输协议,服务器端skeleton建立ServerSocket监听请求,而客户端建立Socket请求边接。RMI实现网络传输的多线程、IO等底层细节。

    相关文章

      网友评论

          本文标题:Spring-源码解读之 IOC 与 DI

          本文链接:https://www.haomeiwen.com/subject/miqnfftx.html