我是靠谱客的博主 柔弱跳跳糖,最近开发中收集的这篇文章主要介绍springIOC容器(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

虽然业务对象可以通过IoC方式声明相应的依赖,但是最终仍然需要通过某种角色或者服务将这些相互依赖的对象绑定到一起,而IoC Service Provider就对应IoC场景中的这一角色。

IoC Service Provider在这里是一个抽象出来的概念:是一种将业务对象绑定到一起的实现方式。它可以是一段代码,也可以是一组相关的类,甚至可以是比较通用的IoC框架或者IoC容器实现

IoC Service Provider 的职责

  1. 业务对象的构建管理:业务对象无需关心所依赖的对象如何构建如何取得,IoC Service Provider需要将对象的构建逻辑从代码中剥离出来,以免创建逻辑侵入业务对象的实现

  2. 业务对象间的依赖绑定:IoC Service Provider最艰巨的最重要的职责,不想在业务对象运行时调用依赖对象方法时报出空指针异常,就需要IoC Service Provider为每一个被注入对象注入恰当的依赖对象,通过结合之前构建和管理的所有业务对象,以及各个业务对象间可以识别的依赖关系,将这些依赖注入关系进行绑定,以保证业务对象在被调用时处于就绪状态

IoC Service Provider 如何管理对象间的依赖关系:需要寻求某种方式来记录诸多对象之间的对应关系

直接编码方式

在容器启动之前,我们就可以通过程序编码的方式将被注入对象和依赖对象注册到容器中,并明确它们相互之间的依赖注入关系

//注册
IoContainer container = ...;
container.register(MyService.class,new MyServiceImpl());
container.register(MyDao.class,new MyDaoImpl());
...
//使用
MyService bean= (MyService)container.get(MyService.class);
bean.doSomething();

配置文件方式

普通文本文件、 properties文件、 XML文件等,都可以成为管理依赖注入关系的载体。常用的是XML文件来管理对象注册和对象间依赖关系

<bean id="myService" class="..MyServiceImpl">
    <property name="myDao">
        <ref bean="myDao"/>
    </property>
</bean>
<bean id="myDao"class="..MyDaoImpl"></bean>

Spring提供了两种容器类型: BeanFactory和ApplicationContext

  1. BeanFactory:基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略( lazy-load)。加载数度快,所需要的资源有限

  2. ApplicationContext:ApplicationContext在BeanFactory的基础上构建,拥有BeanFactory的所有支持,并且提供了比如事件发布、国际化信息支持等高级特性。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。因为要初始化业务对象,相比之下启动较慢,需要占用较多的系统资源

这里写图片描述

BeanFactory

生产Bean的工厂,spring工厂的最高抽象接口,spring提供的BeanFactory实现可以完成作为IoC Service Provider的所有职责,包括业务对象的注册和对象间依赖关系的绑定

其定义了数个接口方法,可归纳为对外提供以下两类服务:
1. bean服务:

boolean containsBean(String name);//判断容器是否已包含某个名称的实bean
String[] getAliases(String name);//根据bean的名称获取它的别名
//多种获取bean的方式
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;//是否多例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;//是否单例
  1. bean类型服务:
Class<?> getType(String name) throws NoSuchBeanDefinitionException;//获取bean的类型
//bean类型判断
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

使用BeanFactory之后

之前我们的系统业务对象需要自己去“拉”( Pull)所依赖的业务对象,有了BeanFactory之类的IoC容器之后,需要依赖什么让BeanFactory为我们推过来( Push)就行了

将”生产图纸”交付给BeanFactory

一般来说我们通过XML配置业务对象之间的依赖关系

<bean id="myService" class="..MyServiceImpl">
    <property name="myDao">
        <ref bean="myDao"/>
    </property>
</bean>
<bean id="myDao"class="..MyDaoImpl"></bean>

使用BeanFactory后,我们直接从容器中获取业务对象,不需要再关注对象的依赖问题

BeanFactory container = 
    new XmlBeanFactory(new ClassPathResource("配置文件路径"));
MyService myService= (MyService)container.getBean("myService");
myService.doSomething();

或者使用ApplicationContext

ApplicationContext container = 
    new ClassPathXmlApplicationContext("配置文件路径");
MyService myService= (MyService)container.getBean("myService");
myService.doSomething();

对象注册与绑定方式

直接编码方式(无论什么方式其实最终都会落实到编码)

public static void main(String[] args){
    DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
    BeanFactory container = (BeanFactory)bindViaCode(beanRegistry);
    MyService myService= (MyService)container.getBean("myService");
    myService.doSomething();
}

//注册绑定
public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){
    //初始化beanDefintion 每个bean对应的管理对象
    AbstractBeanDefinition myService= 
        new RootBeanDefinition(MyServiceImpl.class,
    AutowireCapableBeanFactory.AUTOWIRE_NO,true);
    AbstractBeanDefinition myDao= 
        new RootBeanDefinition(MyDaoImpl.class,
    AutowireCapableBeanFactory.AUTOWIRE_NO,true);

    // 将bean定义注册到容器中
    registry.registerBeanDefinition("myService", myService);
    registry.registerBeanDefinition("myDao", myDao);

    // 指定依赖关系
    // 1. 可以通过构造方法注入方式
    ConstructorArgumentValues argValues = new ConstructorArgumentValues();
    argValues.addIndexedArgumentValue(0, myDao);
    myService.setConstructorArgumentValues(argValues);

    // 2. 或者通过setter方法注入方式
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue(new ropertyValue("myDao",myDao));
    myService.setPropertyValues(propertyValues);
    // 绑定完成 
    return (BeanFactory)registry;
}

DefaultListableBeanFactory是一个比较通用的BeanFactory实现类,除了间接地实BeanFactor接口,还实现了BeanDefinitionRegistry接口,该接口才是在BeanFactory的实现中担当Bean注册管理的角色

BeanFactory接口只定义如何访问容器内管理的Bean的方法,各个BeanFactory的具体实现类负责具体Bean的注册以及管理工作

BeanDefinitionRegistry就像图书馆的书架,所有的书是放在书架上的。虽然你还书或者借书都是跟图书馆(也就是BeanFactory,或许BookFactory可能更好些)打交道,但书架才是图书馆存放各类图书的地方。

这里写图片描述

BeanDefinition

每一个受管的对象,在容器中都会有一个BeanDefinition的实例( instance)与之相对应,该
BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象
类、构造方法参数以及其他属性等。

RootBeanDefinition和 ChildBeanDefinition是BeanDefinition的两个主要实现类

查阅DefaultListableBeanFactory.getBean(Class type)方法

    @SuppressWarnings("unchecked")
    private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        String[] candidateNames = getBeanNamesForType(requiredType);

        if (candidateNames.length > 1) {
            List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
            for (String beanName : candidateNames) {
                if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
                    autowireCandidates.add(beanName);
                }
            }
            if (!autowireCandidates.isEmpty()) {
                candidateNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
            }
        }

        if (candidateNames.length == 1) {
            String beanName = candidateNames[0];
            return new NamedBeanHolder<>(beanName, getBean(beanName, requiredType, args));
        }
        else if (candidateNames.length > 1) {
            Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
            for (String beanName : candidateNames) {
                if (containsSingleton(beanName)) {
                    candidates.put(beanName, getBean(beanName, requiredType, args));
                }
                else {
                    candidates.put(beanName, getType(beanName));
                }
            }
            String candidateName = determinePrimaryCandidate(candidates, requiredType);
            if (candidateName == null) {
                candidateName = determineHighestPriorityCandidate(candidates, requiredType);
            }
            if (candidateName != null) {
                Object beanInstance = candidates.get(candidateName);
                if (beanInstance instanceof Class) {
                    beanInstance = getBean(candidateName, requiredType, args);
                }
                return new NamedBeanHolder<>(candidateName, (T) beanInstance);
            }
            throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
        }

        return null;
    }

根据请求类型获取该类型候选者的名称
String[] candidateNames = getBeanNamesForType(requiredType);

    public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
            return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
        }
        Map<Class<?>, String[]> cache =
                (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
        String[] resolvedBeanNames = cache.get(type);
        if (resolvedBeanNames != null) {
            return resolvedBeanNames;
        }
        resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
        if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
            cache.put(type, resolvedBeanNames);
        }
        return resolvedBeanNames;
    }

进入doGetBeanNamesForType()

    private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        List<String> result = new ArrayList<>();

        // Check all bean definitions.
        for (String beanName : this.beanDefinitionNames) {
            // Only consider bean as eligible if the bean name
            // is not defined as alias for some other bean.
            if (!isAlias(beanName)) {
                try {
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    // Only check bean definition if it is complete.
                    if (!mbd.isAbstract() && (allowEagerInit ||
                            ((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
                                    !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                        // In case of FactoryBean, match object created by FactoryBean.
                        boolean isFactoryBean = isFactoryBean(beanName, mbd);
                        boolean matchFound = (allowEagerInit || !isFactoryBean ||
                                (mbd.getDecoratedDefinition() != null && !mbd.isLazyInit()) ||
                                containsSingleton(beanName)) &&
                                (includeNonSingletons || isSingleton(beanName)) &&
                                isTypeMatch(beanName, type);
                        if (!matchFound && isFactoryBean) {
                            // In case of FactoryBean, try to match FactoryBean instance itself next.
                            beanName = FACTORY_BEAN_PREFIX + beanName;
                            matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
                        }
                        if (matchFound) {
                            result.add(beanName);
                        }
                    }
                }
                catch (CannotLoadBeanClassException ex) {
                    if (allowEagerInit) {
                        throw ex;
                    }
                    // Probably contains a placeholder: let's ignore it for type matching purposes.
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);
                    }
                    onSuppressedException(ex);
                }
                catch (BeanDefinitionStoreException ex) {
                    if (allowEagerInit) {
                        throw ex;
                    }
                    // Probably contains a placeholder: let's ignore it for type matching purposes.
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);
                    }
                    onSuppressedException(ex);
                }
            }
        }

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
该方法会从父类私有字段获取已注册的RootBeanDefinition。

private final Map<String, RootBeanDefinition> mergedBeanDefinitions

然后根据判断是否是抽象,是否懒加载等条件来筛选符合要求的bean name值,添加进集合,返回resolveNamedBean()方法

该方法,通过返回的bean name集合进行一系列操作:
根据beanName,获取bean

    Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
    for (String beanName : candidateNames) {
        if (containsSingleton(beanName)) {
            candidates.put(beanName, getBean(beanName, requiredType, args));
        }
        else {
            candidates.put(beanName, getType(beanName));
        }
    }

获取主要的一组bean和beanName映射,找到多个则抛出NoUniqueBeanDefinitionException

String candidateName = determinePrimaryCandidate(candidates, requiredType);

否则获取最优先级的一组bean和beanName映射,找到多个则抛出NoUniqueBeanDefinitionException

if (candidateName == null) {
        candidateName =determineHighestPriorityCandidate(candidates, requiredType);
}

找到唯一一组映射后实例化NamedBeanHolder对象返回否则抛出NoUniqueBeanDefinitionException

由此可见
DefaultListableBeanFactory 作为 BeanDefinitionRegistry,进行具体的对象注册和相关依赖管理,然后通过BeanDefinitionRegistry取得需要的对象
获取对象的时候,通过父类方法查找已注册的BeanDefinition信息,根据BeanDefinition提供的额外信息判断筛选符合条件的bean,最后返回这个bean

最后

以上就是柔弱跳跳糖为你收集整理的springIOC容器(二)的全部内容,希望文章能够帮你解决springIOC容器(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部