美文网首页java学习笔记
Spring学习笔记(1):Spring基础及Bean注册

Spring学习笔记(1):Spring基础及Bean注册

作者: 小飞飞6号 | 来源:发表于2020-03-04 01:51 被阅读0次

    Spring体系结构

    1. spring为什么流行:
        a. spring专注于做两件事情 IOC( 控制反转) 和 AOP(面向切面)
        b. spring的原则是不重新造轮子,通过对现有的比较好的解决方案提供支持和接入。
        c. spring的扩展思想都是通过实现提供的接口,然后把这些接口注册到bean容器中,然后spring就会根据这些bean实现的接口去扩展某些spring的功能。例如我们经常使用的SpringContextUtils
    2. Spting 7 大模块 
        a. Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性
        b. Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口
        c. Spring Web:它提供Web应用开发的支持
        d. Spring MVC:它针对Web应用中MVC思想的实现
        e. Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
        f. Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等等。
        g. Spring AOP:AOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现
    

    Spring入门使用

    1. 上下文
        a. ClassPathXmlApplicationContext 加载xml配置文件
        b. AnnotationConfigApplicationContext 加载注解配置类 手动使用的时候整个spring都是从这里开始(有空再研究tomcat启动war包的时候的启动点)
    

    @Configuration

    1. @ComponentScan 对指定路径下的文件进行注解配置扫描
        a. Value="包名"
        b. includeFilter={数组项1,数组项2},需要在同级别里同时设置useDefaultFilters=false
            i. 每一个数组项是@Filter(type=xxx,,classes={xxx,xxx})
                1) 当type=FilterType.CUSTOM,代表自定义类,该自定义类需要实现TypeFilter接口,可以在match方法中根据一些java逻辑去判断类要不要进行加载(见右图1)
        c. excludeFilter={数组项1,数组项2},需要设置useDefaultFilters=true
            i. 数组项同上
        d. useDefaultFilters:默认true为全集,false为空集,全集时exclude,空集时include
    2. @Scope 指定bean为例与多例,默认单例
    3. @Lazy 例子在cap4 懒加载在获取bean的时候才初始化(那标记在@Autowired注入呢?)
    
    图1

    类注册

    1. @Bean 
        a. 默认id为方法名
    2. @Component以及其扩展
        a. 默认id为完整包类名
    3.  @Conditional条件注册bean,使用在@Bean的注解上,代表对该Bean进行一次判断
        a. 选择性地注入一些bean,例如区分linux和win平台
            i. Filter的type=CUSTOM应该也能做到同样的事情,但是控制的粒度不一样
        b. 使用方法@Conditional(实现Conditional接口的类.class)
        c. 使用-Dos.name=linux 可以把os.name=linux覆盖虚拟机的环境变量中
    4. @Import 快速给容器导入一个组件(区别于@Bean和@Component)
        a. @Import({Xxx.class}) 加载一个类,可包括第三方类
            i. 那只能使用默认构造器?
            ii. 这么想不还是@Bean更好用吗
        b. 与@Bean的区别
            i. @Import导入的类的默认id是类全称,@Bena为方法名
        c. 当@Import中注册的类实现了ImportSelector接口时,这个接口返回的String[]里包含对应的类也会被当成bean注注册,数组的内容为需要注册的类的全类名。
        d. 当@Import中注册的类实现了ImportBeanDefinitonRegistrar接口:
            i. 可以在处理的时候,通过registry对象获取已经注册的bean,可以更加灵活地通过条件判断来注册bean,例如想要判断同时有猫跟狗的时候才注册老鼠bean。
            ii. 当判断好需要注册的时候,也是通过registry.registerBeanDefinition("bienID",RootBeanDefinition类型的封装类)主动放入到bean的容器中(Spring的IOC容器本质上就是一个map<String,RootBeanDefinition>),通过主动实例化再封装成RootBeanDefinition包装类,再给ImportBeanDefinitonRegistrar注册
    5. FactoryBean 一个泛形接口,也可以灵活地控制任意一个类的创建过程
        a. 可以把java实例通过FactoryBean注入到容器中,实现以下方法
            i. getObject
            ii. getObjectType
            iii. isSingleton
        b. 实现这个接口以后,要把这个实现类也当作一个普通bean注册到容器中,当我们获取bean时,Spring会判断取出的bean是否为FactoryBean子类,若true则使用该BeanFactory的getObject(),构造一个类型为getObjectType的bean,并缓存且赶回该bean(关键方法:org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean)。换言之就是使用FactoryBean生成的Bean,替代了原来Factory的位置。这时候使用id获取bean后得到的就是与泛型一致的实例。
        c. 想要获取FactoryBean的实例本身,需要在beanID前面加上符号“&”
        d. 很重要的一个类,与aop和processor相关
    6. FactoryBean 和 BeanFactory有什么区别(这个定义好像有点疑问)
        a. FactoryBean是一种注册机制,可以把Bean通过FactoryBean注入到容器中
        b. BeanFactory 从我们的容器中获取实例化后的Bean
    

    关于最后的FactoryBean,其实Spring的源码中就有很多类似这样的注解来引导我们读懂spring,挺好的。


    image

    能力有限,如果我的笔记中有问题,请大佬不吝指出,加油!

    最后上点源码

    org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance

    /**
         * Get the object for the given bean instance, either the bean
         * instance itself or its created object in case of a FactoryBean.
         * @param beanInstance the shared bean instance
         * @param name name that may include factory dereference prefix
         * @param beanName the canonical bean name
         * @param mbd the merged bean definition
         * @return the object to expose for the bean
         */
        protected Object getObjectForBeanInstance(
                Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
            // Don't let calling code try to dereference the factory if the bean isn't a factory.
            if (BeanFactoryUtils.isFactoryDereference(name)) {
                if (beanInstance instanceof NullBean) {
                    return beanInstance;
                }
                if (!(beanInstance instanceof FactoryBean)) {
                    throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
                }
                if (mbd != null) {
                    mbd.isFactoryBean = true;
                }
                return beanInstance;
            }
    
            // Now we have the bean instance, which may be a normal bean or a FactoryBean.
            // If it's a FactoryBean, we use it to create a bean instance, unless the
            // caller actually wants a reference to the factory.
            if (!(beanInstance instanceof FactoryBean)) {
                return beanInstance;
            }
    
            Object object = null;
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            else {
                object = getCachedObjectForFactoryBean(beanName);
            }
            if (object == null) {
                // Return bean instance from factory.
                FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
                // Caches object obtained from FactoryBean if it is a singleton.
                if (mbd == null && containsBeanDefinition(beanName)) {
                    mbd = getMergedLocalBeanDefinition(beanName);
                }
                boolean synthetic = (mbd != null && mbd.isSynthetic());
                object = getObjectFromFactoryBean(factory, beanName, !synthetic);
            }
            return object;
        }
    

    org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean

    /**
        /**
         * Obtain an object to expose from the given FactoryBean.
         * @param factory the FactoryBean instance
         * @param beanName the name of the bean
         * @param shouldPostProcess whether the bean is subject to post-processing
         * @return the object obtained from the FactoryBean
         * @throws BeanCreationException if FactoryBean object creation failed
         * @see org.springframework.beans.factory.FactoryBean#getObject()
         */
        protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
            if (factory.isSingleton() && containsSingleton(beanName)) {
                synchronized (getSingletonMutex()) {
                    Object object = this.factoryBeanObjectCache.get(beanName);
                    if (object == null) {
                        object = doGetObjectFromFactoryBean(factory, beanName);
                        // Only post-process and store if not put there already during getObject() call above
                        // (e.g. because of circular reference processing triggered by custom getBean calls)
                        Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                        if (alreadyThere != null) {
                            object = alreadyThere;
                        }
                        else {
                            if (shouldPostProcess) {
                                if (isSingletonCurrentlyInCreation(beanName)) {
                                    // Temporarily return non-post-processed object, not storing it yet..
                                    return object;
                                }
                                beforeSingletonCreation(beanName);
                                try {
                                    object = postProcessObjectFromFactoryBean(object, beanName);
                                }
                                catch (Throwable ex) {
                                    throw new BeanCreationException(beanName,
                                            "Post-processing of FactoryBean's singleton object failed", ex);
                                }
                                finally {
                                    afterSingletonCreation(beanName);
                                }
                            }
                            if (containsSingleton(beanName)) {
                                this.factoryBeanObjectCache.put(beanName, object);
                            }
                        }
                    }
                    return object;
                }
            }
            else {
                Object object = doGetObjectFromFactoryBean(factory, beanName);
                if (shouldPostProcess) {
                    try {
                        object = postProcessObjectFromFactoryBean(object, beanName);
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                    }
                }
                return object;
            }
        }
    

    相关文章

      网友评论

        本文标题:Spring学习笔记(1):Spring基础及Bean注册

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