• Spring笔记-创建Bean


    创建bean:

    1.默认构造函数

        spring.xml  <bean class="com.test.spring.HelloSpring"></bean>

        HelloSpring.java   HelloSpring() {}

    2.指定构造函数

        <bean class="com.test.spring.HelloSpring">

                <constructor-arg index="0" value="zhangsan"></constructor-arg>

                <constructor-arg name="age" value="1"></constructor-arg>

            </bean>

            public HelloSpring(String name, int age) {}

    3.静态工厂方法 factory-method="build"。场景:A/B测试

        spring.xml

        <bean class="com.test.spring.HelloSpring" factory-method="build">

                <constructor-arg name="type" value="A"></constructor-arg>

            </bean>

            HelloSpring.java

            public static HelloSpring build(String type) {

                if("A".equals(type)) {

                    return new HelloSpring("张三",1);

                }else if("B".equals(type)){

                    return new HelloSpring("李四",2);

                }else {

                    throw new IllegalArgumentException("type must be A OR B");

                }

            }

    4.FactoryBean创建。创建的可能并不是类本身的对象,场景:SqlSessionFactory

        <bean id="driver" class="com.test.spring.FactoryBeanSpring">

                <property name="jdbcUrl" value="jdbc:mysql://localhost:3306"></property>

            </bean>

            class FactoryBeanSpring implements FactoryBean{

            private String jdbcUrl;

            public Object getObject() throws Exception {

            return DriverManager.getDriver(jdbcUrl);

            }

            public Class getObjectType() {

            return java.sql.Driver.class;

            }

            public boolean isSingleton() {

            return true;

            }

            }

    依赖注入:

        HelloSpring的成员变量:WorldSpring

    1.set方法注入

        <bean class="com.test.spring.HelloSpring" >

                <property name="worldSpring" ref="world" />

            </bean>

            <bean id="world" class="com.test.spring.WorldSpring" ></bean>

    2.构造方法注入

        <bean class="com.test.spring.HelloSpring" >

                <constructor-arg name="worldSpring">

                    <bean class="com.test.spring.WorldSpring" />

                </constructor-arg>

            </bean>

    3.自动注入:byNamebyType。默认是byName

        <bean class="com.test.spring.HelloSpring" autowire="byName" />

            <bean id="worldSpring" class="com.test.spring.WorldSpring" />

    4.方法注入: lookup-method。场景:一个单例bean依赖一个多例bean.该操作基于动态代理技术。也可以通过实现BeanFactoryAware接口来获取BeanFactory实例,从而直接调用getBean()方法获取新实例.

            <bean class="com.test.spring.LookupMethodSpring" >

                <lookup-method name="getHello" ></lookup-method>

            </bean>

            public abstract class LookupMethodSpring {

            public abstract HelloSpring getHello();

            public void sayHello() {

            getHello().sayHello();

            }

            }

     

    基本特性:

    1.作用范围

    scope=prototype多例

    scope=singleton 单例。单例对象会缓存于IOC容器,在DefaultSingletonBeanRegistry对象中。

    2.生命周期

        创建

        初始化 init-method

        销毁 destory-method  applicationContext关闭时会进行销毁

        3.加载机制

            设置lazy-init,默认为false

                true 懒加载,延迟加载。容器启动会很快

                false 非懒加载,创建即加载。容器启动时能更快的发现错误。

     

    创建、读取bean

        1.关键类

            BeanDefinitionbean定义类。bean信息都保存在该类对象中,与xml bean一对一关系

                继承 AttributeAccessorBeanMetadataElementAttributeAccessor.getAttribute()BeanMetadataElement.getSource()

            BeanDefinitionRegistryBean注册器类,id注册,name是设置别名。

                id作为当前bean的存储key注册到BeanDefinitionRegistry注册器中

                name作为别名key注册到AliasRegistry注册器

            BeanDefinitionReaderBean定义读取类。

                BeanDefinitionReader读取xmlload BeanDefinition装载bean定义,注册到BeanDefinitionRegistry

            BeanFactorybean工厂,创建bean

                getBean(String)

                  基于IDname 获取一个Bean

                <T> T getBean(Class<T> requiredType) 

                 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定 primary=true” 调整优先级来解决该错误 )

                Object getBean(String name, Object... args)

                 基于名称获取一个Bean,并覆盖默认的构造参数

                boolean isTypeMatch(String name, Class<?> typeToMatch)

                 指定Bean与指定Class 是否匹配

     

    BeanFactory

     

    BeanFactory是最顶层的一个接口类,它定义了IOC容器的基本功能规范。

     

    子类ListableBeanFactory:表示这些 Bean 是可列表的,定义了 Bean 的集合;

     

    子类HierarchicalBeanFactory:表示的是这些 Bean 是有继承关系,定义了Bean 之间的关系;

     

    子类AutowireCapableBeanFactory:定义 Bean 的自动装配规则,定义了Bean 行为。

     

    最终的默认实现类是 DefaultListableBeanFactory,实现了以上所有的接口。

     

     

    BeanDefinition

     

    Bean对象在Spring实现中是以BeanDefinition来描述的

     

     

    BeanDefinitionReader

     

    Bean 的解析主要就是对 Spring 配置文件的解析

     

     

     

        2.模拟BeanDefinitionRegistry装载过程

            //创建一个简单注册器

            BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();

            //创建bean定义读取器

            BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);

            // 创建资源读取器、获取资源

            DefaultResourceLoader loader = new DefaultResourceLoader();

            Resource resource = loader.getResource("spring.xml");

            // 装载Bean的定义

            reader.loadBeanDefinitions(resource);

            //通过别名获取

            registry.getAliases("h1");

            //通过id获取

            registry.getBeanDefinition("h1");

            System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));

        3.模拟

            代码:

     

    //注册中心
    
    DefaultListableBeanFactory registry = new DefaultListableBeanFactory();
    
    //读取器
    
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
    
    //读取资源
    
    //装载构建bean的定义
    
    reader.loadBeanDefinitions("spring.xml");
    
    registry.getBean("h1");
    
    System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));
    
    
    分析:
    
    1.DefaultListableBeanFactory既实现了BeanDefinitionRegistry,又实现了BeanFactory。
    
    2.构造函数处打断点,查看调用过程:从下往上看
    
    	at com.test.spring.HelloSpring.<init>(HelloSpring.java:12)
    
    	  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-1)
    
    	  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    
    	  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    
    	  at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    
    	  BeanUtils.instantiateClass(BeanUtils.java:200)
    
    	  SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    
    	  AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312)
    
    	  AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214)
    
    	  AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
    
    	  AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
    
    	  AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
    
    	  AbstractBeanFactory$$Lambda$5.1846406218.getObject(Unknown Source:-1)
    
    	  DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    
    	  - locked <0x58a> (a java.util.concurrent.ConcurrentHashMap)
    
    	  AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
    
    			//先从单例缓存中获取。DefaultListableBeanFactory实现了BeanDefinitionRegistry,所以这里调用的是DefaultSingletonBeanRegistry的getSingleton(String beanName)方法
    
    			Object sharedInstance = this.getSingleton(beanName); //DefaultSingletonBeanRegistry.getSingleton(beanName);
    
    				//如果值不为空,进入下面
    
    					bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);//查看是不是FactoryBean创建自定义bean
    
    				//如果为空,进入下面,从parentBeanFactory里去获取,类似于classLoader里的双亲委派?
    
    					 BeanFactory parentBeanFactory = this.getParentBeanFactory();
    
    					 parentBeanFactory.getBean(nameToLookup, args);
    
    					//如果还是为空
    
    						//如果是单例
    
    						if (mbd.isSingleton()){sharedInstance = this.getSingleton(beanName, objectFactory);} //DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory objectFactory)
    
    							//DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory objectFactory)
    
    							//第一步 加锁
    
    							//判断是否为空,双重检测
    
    							this.beforeSingletonCreation(beanName);//检测这个bean是否正在被创建
    
    							singletonFactory.getObject();//这个地方往回调,实际上调用的是AbstractBeanFactory.doGetBean的189行,这里传过来objectFactory。
    
    								//AbstractBeanFactory.doGetBean的189行
    
    								this.createBean(beanName, mbd, args);//AbstractAutowireCapableBeanFactory.doCreateBean();
    
    							this.afterSingletonCreation(beanName);
    
    							this.addSingleton(beanName, singletonObject);
    
    						//如果是多例
    
    						if (mbd.isPrototype()) {
    
    							this.beforePrototypeCreation(beanName); //写锁
    
    							prototypeInstance = this.createBean(beanName, mbd, args);
    
    							this.afterPrototypeCreation(beanName);//去锁
    
    						}
    
    	  AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    
    	  at com.test.spring.BeanFactoryTest.main(BeanFactoryTest.java:23)
    

    Tips:

    1.ctrl+alt+u查看类和子类(实现类)的结构图

  • 相关阅读:
    阻塞队列整理
    List与Map整理
    2、Redis中的链表
    【观点】从曾成杰案看民间金融的高风险与银行缺失的机制创新
    林权抵押贷款政策出台 将实现林业资源变资本
    从《男生传递微笑给女生的故事》想到的流程梳理与优化
    落实制度靠流程<摘自平安50万人的执行力>
    vue踩坑- 报错npm ERR! cb() never called!
    vue踩坑-This dependency was not found
    vue踩坑- 报错npm ERR! cb() never called!
  • 原文地址:https://www.cnblogs.com/hongyedeboke/p/12779139.html
Copyright © 2020-2023  润新知