Spring基础IOC容器及常见注解

Posted 烟锁迷城

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring基础IOC容器及常见注解相关的知识,希望对你有一定的参考价值。

1、IOC基础

1.1、基础认知

IOC是指控制反转,即将创建Bean的权限交给容器,使用Bean的权限交给开发者。

在SpringBoot中,JAVA配置类的方式被广泛使用。

@Configuration 注解可以起到在Spring中XML配置的作用,@Bean注解提示要进行注入的bean。

@Bean注解可以声明注入的Bean在IOC容器中的名字,以进行调用。

@Configuration
public class JavaConfig {

    @Bean
    public User getUser(){
        return new User();
    }

    @Bean({"a","b"})
    public User getTest(){
        return new User();
    }
}

在测试类中,使用AnnotationConfigApplicationContext 调用Bean,在获取User被注入到容器中的实例时,默认的名字是被加了@Bean注解的方法名,如果声明过,则是声明后的名字。你可以在一个@Bean注解中声明多个名字,这些名字将指向同一个bean。

public class TeatMain {

    @Test
    public void test1() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
        System.out.println(context.getBean("getUser", User.class));
        System.out.println(context.getBean("a", User.class));
        System.out.println(context.getBean("b", User.class));
    }
}

1.2、原理解析

从ClassPathXmlApplicationContext获取配置信息,因为传入的this方法中parent参数为空,所以不需要关注super方法,因为super方法内会检测parent是否为空。

this.setConfigLocations(configLocations);方法会替代一些路径上的符号,关键方法是refresh。

ApplicationContext ac = new ClassPathXmlApplicationContext("");

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[]{configLocation}, true, (ApplicationContext)null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
    }
}

public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        this.configLocations = new String[locations.length];

        for(int i = 0; i < locations.length; ++i) {
            this.configLocations[i] = this.resolvePath(locations[i]).trim();
        }
    } else {
        this.configLocations = null;
    }
}

refresh使用模板方法,关键方法是

ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();,进行IOC容器的初始化操作。

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        this.prepareRefresh();
        //IOC容器初始化操作
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (BeansException var10) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
            }

            this.destroyBeans();
            this.cancelRefresh(var10);
            throw var10;
        } finally {
            this.resetCommonCaches();
            contextRefresh.end();
        }

    }
}

obtainFreshBeanFactory()方法中的

this.refreshBeanFactory()方法,刷新IOC容器

this.getBeanFactory();方法,获取Bean Factory对象,这意味着已经完成了IOC的初始化操作

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //刷新IOC容器
    this.refreshBeanFactory();
    //获取Bean Factory对象
    return this.getBeanFactory();
}

在refreshBeanFactory方法中,成功创建DefaultListableBeanFactory对象,然后this.loadBeanDefinitions(beanFactory);方法将有@Bean注解的类加载至BeanFactory中。

​
protected final void refreshBeanFactory() throws BeansException {
    if (this.hasBeanFactory()) {
        this.destroyBeans();
        this.closeBeanFactory();
    }

    try {
        //创建Bean Factory对象,即DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = this.createBeanFactory();
        beanFactory.setSerializationId(this.getId());
        this.customizeBeanFactory(beanFactory);
        //加载Bean Definitions,即加载@Bean注解的代码成为Bean
        this.loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    } catch (IOException var2) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
    }
}

​

reader.register(ClassUtils.toClassArray(this.componentClasses));方法将Bean注册至AnnotatedBeanDefinitionReader之中。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    AnnotatedBeanDefinitionReader reader = this.getAnnotatedBeanDefinitionReader(beanFactory);
    ClassPathBeanDefinitionScanner scanner = this.getClassPathBeanDefinitionScanner(beanFactory);
    BeanNameGenerator beanNameGenerator = this.getBeanNameGenerator();
    if (beanNameGenerator != null) {
        reader.setBeanNameGenerator(beanNameGenerator);
        scanner.setBeanNameGenerator(beanNameGenerator);
        beanFactory.registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", beanNameGenerator);
    }

    ScopeMetadataResolver scopeMetadataResolver = this.getScopeMetadataResolver();
    if (scopeMetadataResolver != null) {
        reader.setScopeMetadataResolver(scopeMetadataResolver);
        scanner.setScopeMetadataResolver(scopeMetadataResolver);
    }

    if (!this.componentClasses.isEmpty()) {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Registering component classes: [" + StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
        }

        reader.register(ClassUtils.toClassArray(this.componentClasses));
    }

    if (!this.basePackages.isEmpty()) {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
        }

        scanner.scan(StringUtils.toStringArray(this.basePackages));
    }

    String[] configLocations = this.getConfigLocations();
    if (configLocations != null) {
        String[] var7 = configLocations;
        int var8 = configLocations.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            String configLocation = var7[var9];

            try {
                Class<?> clazz = ClassUtils.forName(configLocation, this.getClassLoader());
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Registering [" + configLocation + "]");
                }

                reader.register(new Class[]{clazz});
            } catch (ClassNotFoundException var13) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Could not load class for config location [" + configLocation + "] - trying package scan. " + var13);
                }

                int count = scanner.scan(new String[]{configLocation});
                if (count == 0 && this.logger.isDebugEnabled()) {
                    this.logger.debug("No component classes found for specified class/package [" + configLocation + "]");
                }
            }
        }
    }

}

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);为最后的工具方法,将Bean注册其中。

    public void register(Class... componentClasses) {
        Class[] var2 = componentClasses;
        int var3 = componentClasses.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Class<?> componentClass = var2[var4];
            this.registerBean(componentClass);
        }

    }

    public void registerBean(Class<?> beanClass) {
        this.doRegisterBean(beanClass, (String)null, (Class[])null, (Supplier)null, (BeanDefinitionCustomizer[])null);
    }

    private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            abd.setInstanceSupplier(supplier);
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
            String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            int var10;
            int var11;
            if (qualifiers != null) {
                Class[] var9 = qualifiers;
                var10 = qualifiers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    Class<? extends Annotation> qualifier = var9[var11];
                    if (Primary.class == qualifier) {
                        abd.setPrimary(true);
                    } else if (Lazy.class == qualifier) {
                        abd.setLazyInit(true);
                    } else {
                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                    }
                }
            }

            if (customizers != null) {
                BeanDefinitionCustomizer[] var13 = customizers;
                var10 = customizers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    BeanDefinitionCustomizer customizer = var13[var11];
                    customizer.customize(abd);
                }
            }

            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }

这段为注册Bean的方法,主要是registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法。

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }

其中最简单的,单例Bean的实现就是将所有的Bean都放入一个Map<String, BeanDefinition>结构的Map,Key为Bean的名字,Value为BeanDefinition。

其他Bean的实现方式可以自行研究探讨。

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);

    public SimpleBeanDefinitionRegistry() {
    }

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "'beanName' must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

1.3、实例化

实例化的方法核心代码为NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);

    @Nullable
    private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
        NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        } else {
            BeanFactory parent = this.getParentBeanFactory();
            if (parent instanceof DefaultListableBeanFactory) {
                return ((DefaultListableBeanFactory)parent).resolveBean(requiredType, args, nonUniqueAsNull);
            } else if (parent != null) {
                ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
                if (args != null) {
                    return parentProvider.getObject(args);
                } else {
                    return nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable();
                }
            } else {
                return null;
            }
        }
    }

String[] candidateNames = this.getBeanNamesForType(requiredType);方法获取beanDefinitionNames中全部的beanName。

获取到之后,进行循环获取,Object beanInstance = candidates.get(candidateName);方法进行实例化的操作。

    @Nullable
    private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        String[] candidateNames = this.getBeanNamesForType(requiredType);
        String[] var6;
        int var7;
        int var8;
        String beanName;
        if (candidateNames.length > 1) {
            List<String> autowireCandidates = new ArrayList(candidateNames.length);
            var6 = candidateNames;
            var7 = candidateNames.length;

            for(var8 = 0; var8 < var7; ++var8) {
                beanName = var6[var8];
                if (!this.containsBeanDefinition(beanName) || this.getBeanDefinition(beanName).isAutowireCandidate()) {
                    autowireCandidates.add(beanName);
                }
            }

            if (!autowireCandidates.isEmpty()) {
                candidateNames = StringUtils.toStringArray(autowireCandidates);
            }
        }

        if (candidateNames.length == 1) {
            return this.resolveNamedBean(candidateNames[0], requiredType, args);
        } else {
            if (candidateNames.length > 1) {
                Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
                var6 = candidateNames;
                var7 = candidateNames.length;

                for(var8 = 0; var8 < var7; ++var8) {
                    beanName = var6[var8];
                    if (this.containsSingleton(beanName) && args == null) {
                        Object beanInstance = this.getBean(beanName);
                        candidates.put(beanName, beanInstance instanceof NullBean ? null : beanInstance);
                    } else {
                        candidates.put(beanName, this.getType(beanName));
                    }
                }

                String candidateName = this.determinePrimaryCandidate(candidates, requiredType.toClass());
                if (candidateName == null) {
                    candidateName = this.determineHighestPriorityCandidate(candidates, requiredType.toClass());
                }

                if (candidateName != null) {
                    Object beanInstance = candidates.get(candidateName);
                    if (beanInstance == null) {
                        return null;
                    }

                    if (beanInstance instanceof Class) {
                        return this.resolveNamedBean(candidateName, requiredType, args);
                    }

                    return new NamedBeanHolder(candidateName, beanInstance);
                }

                if (!nonUniqueAsNull) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
                }
            }

            return null;
        }
    }

在doGetBean方法中,Object sharedInstance = this.getSingleton(beanName);方法为获取单例Bean的方法,显然是核心逻辑。在这个方法中,获取到单例的Bean之后,如果不为空就正常返回,如果为空,则需要进行创建。

prototypeInstance = this.createBean(beanName, mbd, args);方法就是创建方法。

public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    String beanName = this.transformedBeanName(name);
    Object sharedInstance = this.getSingleton(beanName);
    Object beanInstance;
    if (sharedInstance != null && args == null) {
        if (this.logger.isTraceEnabled()) {
            if (this.isSingletonCurrentlyInCreation(beanName)) {
                this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
                this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }

        beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        BeanFactory parentBeanFactory = this.getParentBeanFactory();
        if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            String nameToLookup = this.originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }

            if (args != null) {
                return parentBeanFactory.getBean(nameToLookup, args);
            }

            if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }

            return parentBeanFactory.getBean(nameToLookup);
        }

        if (!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }

        StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);

        try {
            if (requiredType != null) {
                beanCreation.tag("beanType", requiredType::toString);
            }

            RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            String[] dependsOn = mbd.getDependsOn();
            String[] var12;
            if (dependsOn != null) {
                var12 = dependsOn;
                int var13 = dependsOn.length;

                for(int var14 = 0; var14 < var13; ++var14) {
                    String dep = var12[var14];
                    if (this.isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }

                    this.registerDependentBean(dep, beanName);

                    try {
                        this.getBean(dep);
                    } catch (NoSuchBeanDefinitionException var31) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31);
                    }
                }
            }

            if (mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, () -> {
                    try {
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException var5) {
                        this.destroySingleton(beanName);
                        throw var5;
                    }
                });
                beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                var12 = null;

                Object prototypeInstance;
                try {
                    this.beforePrototypeCreation(beanName);
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    this.afterPrototypeCreation(beanName);
                }

                beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                String scopeName = mbd.getScope();
                if (!StringUtils.hasLength(scopeName)) {
                    throw new IllegalStateException("No scope name defined for bean ��" + beanName + "'");
                }

                Scope scope = (Scope)this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }

                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        this.beforePrototypeCreation(beanName);

                        Object var4;
                        try {
                            var4 = this.createBean(beanName, mbd, args);
                        } finally {
                            this.afterPrototypeCreation(beanName);
                        }

                        return var4;
                    });
                    beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                } catch (IllegalStateException var30) {
                    throw new ScopeNotActiveException(beanName, scopeName, var30);
                }
            }
        } catch (BeansException var32) {
            beanCreation.tag("exception", var32.getClass().toString());
            beanCreation.tag("message", String.valueOf(var32.getMessage()));
            this.cleanupAfterBeanCreationFailure(beanName);
            throw var32;
        } finally {
            beanCreation.end();
        }
    }

    return this.adaptBeanInstance(name, beanInstance, requiredType);
}

依然寻找DoGetBean方法进行查看

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Creating instance of bean '" + beanName + "'");
        }

        RootBeanDefinition mbdToUse = mbd;
        Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
            mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException var9) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
        }

        Object beanInstance;
        try {
            beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
            if (beanInstance != null) {
                return beanInstance;
            }
        } catch (Throwable var10) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
        }

        try {
            beanInstance = this.doCreateBean(beanName, mbdToUse, args);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Finished creating instance of bean '" + beanName + "'");
            }

            return beanInstance;
        } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
            throw var7;
        } catch (Throwable var8) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
        }
    }

找到instanceWrapper = this.createBeanInstance(beanName, mbd, args);方法,创建Bean的实例。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }

            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }

                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

this.instantiateBean(beanName, mbd);方法是初始化Bean的方法。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        } else {
            Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
            if (instanceSupplier != null) {
                return this.obtainFromSupplier(instanceSupplier, beanName);
            } else if (mbd.getFactoryMethodName() != null) {
                return this.instantiateUsingFactoryMethod(beanName, mbd, args);
            } else {
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                    synchronized(mbd.constructorArgumentLock) {
                        if (mbd.resolvedConstructorOrFactoryMethod != null) {
                            resolved = true;
                            autowireNecessary = mbd.constructorArgumentsResolved;
                        }
                    }
                }

                if (resolved) {
                    return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
                } else {
                    Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                    if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
                        ctors = mbd.getPreferredConstructors();
                        return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
                    } else {
                        return this.autowireConstructor(beanName, mbd, ctors, args);
                    }
                }
            }
        }
    }

getInstantiationStrategy()显然是一个策略模式,具有三种不同的抽象方法。

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged(() -> {
                    return this.getInstantiationStrategy().instantiate(mbd, beanName, this);
                }, this.getAccessControlContext());
            } else {
                beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
            }

            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            this.initBeanWrapper(bw);
            return bw;
        } catch (Throwable var5) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var5);
        }
    }

其中第一种方法的实现是上段代码中使用过的。

public interface InstantiationStrategy {
    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3) throws BeansException;

    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;

    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, @Nullable Object var4, Method var5, Object... var6) throws BeansException;
}

return BeanUtils.instantiateClass(constructorToUse, new Object[0]);代码代表最终返回的结果为BeanUtils.instantiateClass方法的返回值。

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        if (!bd.hasMethodOverrides()) {
            Constructor constructorToUse;
            synchronized(bd.constructorArgumentLock) {
                constructorToUse = (Constructor)bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }

                    try {
                        if (System.getSecurityManager() != null) {
                            clazz.getClass();
                            constructorToUse = (Constructor)AccessController.doPrivileged(() -> {
                                return clazz.getDeclaredConstructor();
                            });
                        } else {
                            constructorToUse = clazz.getDeclaredConstructor();
                        }

                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    } catch (Throwable var9) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", var9);
                    }
                }
            }

            return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
        } else {
            return this.instantiateWithMethodInjection(bd, beanName, owner);
        }
    }

可以看到,return ctor.newInstance(argsWithDefaultValues);方法最后返回,那么ctor是构造器Constructor<T> ctor。

Constructor的newInstance方法,这个是反射的一种创建实例的方法,也就是说,IOC最终使用了代理来进行实例化。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");

        try {
            ReflectionUtils.makeAccessible(ctor);
            if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
                return BeanUtils.KotlinDelegate.instantiateClass(ctor, args);
            } else {
                Class<?>[] parameterTypes = ctor.getParameterTypes();
                Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
                Object[] argsWithDefaultValues = new Object[args.length];

                for(int i = 0; i < args.length; ++i) {
                    if (args[i] == null) {
                        Class<?> parameterType = parameterTypes[i];
                        argsWithDefaultValues[i] = parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null;
                    } else {
                        argsWithDefaultValues[i] = args[i];
                    }
                }

                return ctor.newInstance(argsWithDefaultValues);
            }
        } catch (InstantiationException var6) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", var6);
        } catch (IllegalAccessException var7) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var7);
        } catch (IllegalArgumentException var8) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var8);
        } catch (InvocationTargetException var9) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", var9.getTargetException());
        }
    }

2、注解

2.1、常用注解

注解名称说明
@Configuration把一个类作为一个IOC容器,在某个方法上如果有@Bean注解,那么就会被作为spring容器的bean
@ComponentScan在配置类上增加@ComponentScan注解,该注解会扫描该类所在的包下所有的配置类,相当于context:component-scan
@Scope用于指定scope作用域的(用在类上)
@Lazy表示延迟初始化
@Import导入外部资源
生命周期控制

@PostConstruct:用于指定初始化方法(用在方法上)

@PreDestory:用于指定销毁方法(用在方法上)

@DependsOn:定义Bean初始化及销毁时的顺序

@ConditionalSpring4开始提供,它的作用是按照一定的条件进行判断,满足条件给容器注册Bean

2.2、Conditional扩展注解

@Conditional扩展注解作用(判断是否满足指定条件)
@ConditionalOnJava系统的java版本是否符合要求
@ConditionalOnBean容器中存在指定的Bean
@ConditionalOnMissingBean容器中不存在指定的Bean
@ConditionalOnExpression满足Spel表达式
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定的资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNotWebApplication当前不是web环境
@ConditionalOnIndiINDI存在指定项

2.3、泛值注解

注解名称说明
@Component泛指组件,当组件不好归类的时候,可以使用该注解
@Service用于标注业务层组件
@Controller用于标注控制层组件
@Repository用于标注数据访问组件
@Value普通数据类型赋值
@Autowired默认按类型装配,如果想要按名称装配,可配合@Qualifier注解一起使用
@PropertySource读取配置文件赋值
@Qualifier如存在多个实例,配合使用以锁定某一个
@Primary自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Resource默认按名称装配,当找不到与名称匹配的Bean时才按照类型装配

3、常用注解解析

3.1、@Autowired与@Resource,装配Bean

@Autowired注解的作用是按类型装配,无法按名称装配。如果想要用名称装配,需要配合@Qualifier注解使用。对于@Service等注解,加入容器的Bean的默认名称为类名首字母小写,所以可以这样使用

public class UserController{

    @Autowired()
    @Qualifier("userService")
    private UserService userService;

}

@Service等注解可以不使用默认名称,@Service("service")可以声明指定名称

@Resource的作用与@Autowired相同,但是查找顺序不同,默认按名称装配,当找不到与名称匹配的Bean时才按照类型装配,如果指定名称,则只按照名称寻找。

3.2、@ComponentScan扫描需要加载Bean的目录

@ComponentScan注解的作用是扫描需要加载到容器中的配置类,可指定目录。在未指定时,默认会扫描当前目录及其子目录下的所有的被@Component,@Controller,@Service,@Repository注解修饰的类。

必须要与@Configuration配合使用才能生效。

vlaue:扫描地址

useDefaultFilters:是否使用默认过滤器(即@Component等注解)

excludeFilters:不使用的过滤注解

includeFilters:使用的过滤注解

@Configuration
@ComponentScan(value = {}, 
    useDefaultFilters = false, 
    includeFilters = {@ComponentScan.Filter(Controller.class)})

@ComponentScans注解是可以包含多个@ComponentScan注解的。

@Configuration
@ComponentScans({
    @ComponentScan(
        value = {}, 
        useDefaultFilters = false, 
        includeFilters = {@ComponentScan.Filter(Controller.class)})
})

3.3、@Primary首选项

@Primary注解可以将按照类型匹配时出现的多个符合项排出一个首选项。在有多个符合的匹配结果时,spring将会抛出错误org.springframework.beans.factory.NoUniqueBeanDefinitionException

@Configuration
public class JavaConfig {

    @Bean
    public User getUser() {
        return new User();
    }

    @Bean
    public User getTest() {
        return new User();
    }
}
public class TeatMain {

    @Test
    public void test1() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
        System.out.println(context.getBean(User.class));
    }
}

因为spring无法确定加载哪一个,但是增加@Primary修饰后,这个Bean将被列为首选项,优先加载。

@Configuration
public class JavaConfig {

    @Bean
    public User getUser() {
        return new User();
    }

    @Bean
    @Primary
    public User getTest() {
        return new User();
    }
}

这样名为getTest的bean将被加载。

3.4、@Value赋值

@Value可以为bean的属性注入数值,需要配合@Component等可以加入IOC容器的注解使用。

  1. 普通的数值注入:@Value("yansuomicheng")
  2. 获取系统信息:@Value("#{systemProperties['os.name']}")
  3. 使用java函数获取随机数:@Value("#{T(java.lang.Math).random()*100}")
  4. 使用其他bean中的属性值:@Value("#{getUser.userName}")
  5. 加载配置文件:@Value("classpath:application.yml")
  6. 加载URL:@Value("http://www.baidu.com")
  7. 取得yml配置文件中的数值:@Value("${spring.application.name}")
@Component
public class Person {

    //普通的数值注入
    @Value("yansuomicheng")
    private String name;

    //获取系统信息
    @Value("#{systemProperties['os.name']}")
    private String systemPropertiesName;

    //使用java函数获取随机数
    @Value("#{T(java.lang.Math).random()*100}")
    private double randomNumber;

    //使用其他bean中的属性值
    @Value("#{getUser.userName}")
    private String userName;

    //加载配置文件
    @Value("classpath:application.yml")
    private Resource resourceFile;

    //加载URL
    @Value("http://www.baidu.com")
    private Resource resourceUrl;

    //取得yml配置文件中的数值
    @Value("${spring.application.name}")
    private String applicationName;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSystemPropertiesName() {
        return systemPropertiesName;
    }

    public void setSystemPropertiesName(String systemPropertiesName) {
        this.systemPropertiesName = systemPropertiesName;
    }

    public double getRandomNumber() {
        return randomNumber;
    }

    public void setRandomNumber(double randomNumber) {
        this.randomNumber = randomNumber;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Resource getResourceFile() {
        return resourceFile;
    }

    public void setResourceFile(Resource resourceFile) {
        this.resourceFile = resourceFile;
    }

    public Resource getResourceUrl() {
        return resourceUrl;
    }

    public void setResourceUrl(Resource resourceUrl) {
        this.resourceUrl = resourceUrl;
    }

    public String getApplicationName() {
        return applicationName;
    }

    public void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\\'' +
                ", systemPropertiesName='" + systemPropertiesName + '\\'' +
                ", randomNumber=" + randomNumber +
                ", userName='" + userName + '\\'' +
                ", resourceFile=" + resourceFile +
                ", resourceUrl=" + resourceUrl +
                ", applicationName='" + applicationName + '\\'' +
                '}';
    }
}

3.5、@PropertySource读取配置文件

@PropertySource主要作用是读取配置文件赋值,即上一个注解@Value想要读取配置文件中的数值时,需要增加这个注解才能确定需要读取到的配置文件

@Configuration
@PropertySource({"classpath:application.properties"})
public class JavaConfig {

    @Bean
    public User getUser() {
        User user = new User();
        user.setUserName("anyone");
        return user;
    }

    @Bean
    public Person getPerson() {
        return new Person();
    }
}

3.6、@Lazy延迟加载

@Lazy注解作用是延迟加载,当一个Bean增加了这个注解,在不被其他bean使用时,这个bean将不会被加载,直到它被使用。该注解可以减轻服务启动压力。

3.7、@PostConstruct系统初始化方法

@PostConstruct注解,用于指定在系统启动后开始执行的初始化方法,用在方法上。

3.8、@PreDestory系统关闭回调方法

@PreDestory注解,用于指定销毁方法,在系统结束时执行,

3.9、@DependsOn顺序指定

@DependsOn注解,定义Bean初始化及销毁时的顺序,可以放置多个,代表配置的Bean优先于当前Bean加载。

@DependsOn({"user"})

3.10、@Import

将类型加入到IOC容器的方法:

  1. 基于XML文件的方式<Bean>
  2. 基于XML文件的方式context:Component-Scan+@Component
  3. 基于java配置类@Bean
  4. 基于java配置类@ComponentScan+@Component
  5. FactoryBean+getObject方法
  6. @Import

@Import可以显式的引入需要的类型,可以以列表形式引入。

@Configuration
@Import({User.class,Person.class})
public class JavaConfig {
}

为更加灵活的引用,可以通过实现ImportSelector接口的方式动态引入

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{User.class.getName(), Person.class.getName()};
    }
}

@Configuration
@Import(MyImportSelector.class)
public class JavaConfig {
}

也可以通过实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法来实现

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition user = new RootBeanDefinition(User.class);
        RootBeanDefinition person = new RootBeanDefinition(Person.class);
        registry.registerBeanDefinition("user",user);
        registry.registerBeanDefinition("person",person);
    }
}

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class JavaConfig {
}

3.11、@Conditional加载条件

条件判定,用来决定IOC是否加载这个类。通过实现condition接口实现matches方法,返回为true代表加载,false为不加载

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ConditionalOnBean implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}
import com.example.demo.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JavaConfig {

    @Bean
    @Conditional(ConditionalOnBean.class)
    public User user() {
        return new User();
    }
}

3.12、@Profile多环境解决方案

@Profile是@Condition注解的一种实现,可以选择加载某一个bean。

@Configuration
public class JavaConfig {

    @Bean
    @Profile("user")
    public User user() {
        return new User();
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("user");
context.register(JavaConfig.class);
context.refresh();
System.out.println(context.getBean(User.class));

3.13、@Scope决定Bean的作用域

  1. singleton:单例,在整个IOC中保持只有一个Bean。
  2. prototype:原型,在整个IOC中,每次调用都会创造一个新的Bean。
  3. request:在一次请求中,bean的生命周期与request同步。
  4. session:bean的生命周期与Session同步。
  5. 默认:即不使用时,单例。

以上是关于Spring基础IOC容器及常见注解的主要内容,如果未能解决你的问题,请参考以下文章

Spring学习笔记IOC容器及Spring配置详解

基于注解实现简单Spring框架:完成IOC容器和声明式事务控制

Spring核心容器

Spring核心容器

Spring核心容器

谈谈Spring IOC容器的注入方式