Spring源码-getBean获取bean实例

实例化Bean

单例bean,并且lazy-init为false(默认是false),则 ApplicationContext在刷新的时候就实例化该Bean,并且将实例化的Bean放到缓存中,下次再使用该Bean的时候, 直接从这个缓存中获取;如果单例bean是懒加载的,即lazy-init为true,则在第一次getBean获取该Bean的时候进行实例化,并放入缓存;scope是prototype的多例bean,每次使用获取Bean的时候都会进行实例化

<bean id="" class="" scope="作用域"/>

1. singleton: 单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
2. prototype: 多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()
3. request: 用于web开发,将Bean放入request范围 , 在同一个request 获得同一个Bean
4. session: 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean 

spring容器默认加载bean为非延迟加载,在容器刷新阶段就会实例化bean对象,设置为延迟加载则当类首次被加载时才会初始化实例,所有bean的实例化都是通过getBean去实现

<!--当前xml中所有的bean-->
<beans default-lazy-init="default | false | true">
<!--指定的bean-->
<bean lazy-init="default | false | true">

使用注解方式

@Lazy
public class Bean {
   }

总结所有bean的生命周期:单例且非延迟加载的bean跟随容器刷新完成实例初始化,之后访问实例从缓存中获取;单例延迟加载的bean在首次访问时通过getBean完成实例化,之后访问从缓存中获取;

Bean实例化的方式

无参数构造器实例化

<bean id="super" name="a1,a2,a3" class="cn.mywork.spring.Super" lazy-init="true"/>

静态工厂方法实例化

//factory-method找到工厂类的静态方法
<bean id="student" class="cn.mywork.spring.StaticFactory" factory-method="getStu"/>

//配置静态工厂类
public class StaticFactory {
   
    //通过配置文件找到静态方法,返回对象为创建的bean
    public static Student getStu(){
   
        return new Student();
    }
}

ApplicationContext context;
Student student = context.getBean("student", Student.class);

实例工厂

//先将工厂bean交给容器管理
<bean id="instanceFactory" name="fc" class="cn.mywork.wms.spring.InstanceFactory"/>
//factory-bean只能是初始化好的bean对象,通过bean工厂对象,获取实例方法初始化bean
<bean id="student" factory-bean="fc" factory-method="getStu"/>

实现FactoryBean接口,通过getObject方法返回目标实例

//实现getObject方法
public class InstanceFactory implements FactoryBean<Student>{
   
    @Override
    public Student getObject() throws Exception {
   
        return new Student();
    }
    @Override
    public Class<?> getObjectType() {
   
        return null;
    }
    @Override
    public boolean isSingleton() {
   
        return false;
    }
}

<bean id="student" class="cn.mywork.spring.InstanceFactory"/>

注解的方式

//注解对应的配置解析
<bean id="super" class="cn.mywork.wms.spring.Super" init-method="init" destroy-method="destory" scope="prototype">
    <!--注入的属性-->
    <property name="sub" ref="sub"/>
</bean>
<bean id="sub" class="cn.mywork.wms.spring.Sub"/>

//默认的为简化的类名,Xml里也同于bean标签的id值
@Component("super")
//作用域:非单例
@Scope("prototype")
public class Super {
   
    private String name;
    //注入Sub初始化的实例
    @Autowired
    private Sub sub;
    //初始化的方法,init-method="init"
    @PostConstruct
    public void init(){
   
    }
    //销毁的方法,destroy-method="destory"
    @PreDestroy
    public void destory(){
   
    }
}

自定义BeanFactory工厂

public class BeanFactoryDemo {
   
    //key为id,value为全限定名
    private static Map<String,String> beanMap = new HashMap<>();
    //bean缓存,延迟加载bean时,genBean之后将bean放入缓存
    private static Map<String,Object> cacheMap = new HashMap<>();

    //解析xml配置文件
    static {
   
        try {
   
            //getClassLoader().getResourceAsStream是加载resources资源路径下的配置文件
            InputStream resource = BeanFactoryDemo.class.getClassLoader().getResourceAsStream("spring.xml");
            initBeanMap(resource);
        }catch (Exception e){
   }
    }

    private static void initBeanMap(InputStream resource) throws Exception {
   
        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
        saxParser.parse(resource,new DefaultHandler(){
   
            //解析后的标签名
            private String tagName;
            @Override
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
   
                this.tagName = qName;
                //获取标签内容
                if ("bean".equals(tagName)){
   
                    //获取id的值
                    String id = attributes.getValue("id");
                    //获取bean的全限定名
                    String beanClassName = attributes.getValue("class");
                    beanMap.put(id,beanClassName);
                }
            }
            @Override
            public void endElement(String uri, String localName, String qName) throws SAXException {
   
                tagName = null;
            }
        });
    }

    //获取bean实例的方法,延迟加载方式
    public static  <T> T getBean(String id,Class<T> beanClass) throws Exception{
   
        //只有map中存在的key值才会继续处理
        if (beanMap.containsKey(id)){
   
            //再判断缓存中是否有该bean
            if (cacheMap.containsKey(id)){
   
                return (T) cacheMap.get(id);
            }
            String beanClassName = beanMap.get(id);
            //加载全限定名,通过反射机制创建bean
            Object instance = Class.forName(beanClassName).newInstance();
            //判断是否为beanClass类型的实例
            if (beanClass.isInstance(instance)){
   
                cacheMap.put(id,instance);
                return (T) instance;
            }
        }
        return null;
    }
}

Student student = BeanFactoryDemo.getBean("student", Student.class);

getBean

refresh执行到finishBeanFactoryInitialization时才开始实例化非延迟加载的bean,主要看其中的preInstantiateSingletons方法

public void preInstantiateSingletons() throws BeansException {
   
    //所有的需要实例化的beanName都在beanDefinitionNames,包括 Aspectj的, 通过注解标识的
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    for (String beanName : beanNames) {
   
        //合并父类BeanDefinition
        //MergedBeanDefinition合并bean定义,XML 配置来注册 bean,会被封装成GenericBeanDefinition;使用注解的方式来注册 bean,会被封装成 ScannedGenericBeanDefinition,最终统一转换成 RootBeanDefinition处理
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        //非抽象,单例,非懒加载三个条件
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
   
            //是 FactoryBean 类型的对象则加上&
            //判断是factoryBean还是普通bean,实现FactoryBean接口的getObject()方法可以定义创建实例对象,比如很多中间件的就是通过这种方式实现
            if (isFactoryBean(beanName)) {
   
                bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                ...
            }
            else {
   
                // 进入到doGetBean执行实例化bean
                bean = getBean(beanName);
            }
        }
    }
}    

容器初始化完成还是在初始化之后动态获取bean都会访问beanFacroty.getBean()方法,进入这个方法发现有很多分支去获取bean,如果不是首次获取bean则直接getSingleton()先从缓存中获取

protected <T> T doGetBean(String name, Class<T> requiredType,Object[] args, boolean typeCheckOnly) throws BeansException {
   
    //去掉FactoryBean的前缀“&”,解析别名返回namespace的beanName
    String beanName = this.transformedBeanName(name);
    //获取缓存中的bean,不涉及创建新的bean实例和解决循环依赖
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    //缓存中如果能获取到
    if (sharedInstance != null && args == null) {
   
        //普通bean直接返回实例,factoryBean继续处理
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
   
        //和singletonsCurrentlyInCreation类似存放正在创建的Prototype实例
        //循环依赖校验:当前原型实例池中有正在创建的对象了,说明这个对象是个原型对象,并且当前线程中这个对象已经处于创建中了,会造成循环依赖
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
   
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值