精华内容
下载资源
问答
  • 1.SpringBootBean的自动注入 我们在使用Springboot时,最为常用的bean注入方式莫过于自动注入了吧,通过在springboot项目中加各种注解即 可使用自动注入,步骤(相对简洁,不过很粗暴)demo如下: 启动类上...

    1.SpringBoot中Bean的自动注入

        我们在使用Springboot时,最为常用的bean的注入方式莫过于自动注入了吧,通过在springboot项目中加各种注解即
    可使用自动注入,步骤(相对简洁,不过很粗暴)demo如下:     
    
    1. 启动类上加@SpringBootApplication
    	@SpringBootApplication
    	public class Application {
      	 	 public static void main(String[] args) {
           		 SpringApplication.run(Application .class, args);
        	 }
    	}
    
    1. Controller类上加@RestController
    	//controller层
    	@RestController
    	public class TestController {
    
       		 @Autowired
        	 private TestService testService;
    
       		 @RequestMapping("/test")
        	 public String testDemo(String talk){
            	 return testService.talk(talk);
        	 }
    	}
    
    1. Service接口类上加@Service
    	//service层
    	public interface TestService {
     	     String talk(String talk);
    	}
    
    	//serviceImpl
    	@Service
    	public class TestServiceImpl implements TestService {
    
      		@Resource
       	    private TestMapper testMapper;
    	
       	    @Override
            public String talk(String talk){
                return testMapper.talk();
            }
        }
    
    1. Mapper类上加@Mapper(启动类上加@MapperScan(basePackages = {“mapper文件所在的路径”})也行)
    	//持久层
    	@Mapper
    	public interface TestMapper {
      	 	 String talk(@Param("talk") String talk);
    	}
    
       当然再牛叉的技术都是不会十全十美的,当你引用一些其他技术到项目中时,有些可能会导致自动注入出现注入失败的情况,
    这时候就延申到我们第二种方式啦
    

    2.SpringBoot中Bean的非自动注入

    2.1 首先创建一个SpringContextHolder类,放入到项目中

    @Component
    @SuppressWarnings("all")
    public class SpringContextHolder implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
    
        public SpringContextHolder() {
        }
    
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            SpringContextHolder.applicationContext = applicationContext;
        }
    
        public static ApplicationContext getApplicationContext() {
            assertApplicationContext();
            return applicationContext;
        }
    
        public static <T> T getBean(String beanName) {
            assertApplicationContext();
            return (T) applicationContext.getBean(beanName);
        }
    
        public static <T> T getBean(Class<T> requiredType) {
            assertApplicationContext();
            return applicationContext.getBean(requiredType);
        }
    
        public static <T> List<T> getBeanOfType(Class<T> requiredType) {
            assertApplicationContext();
            Map<String, T> map = applicationContext.getBeansOfType(requiredType);
            return map == null ? null : new ArrayList(map.values());
        }
    
        public static void autowireBean(Object bean) {
            applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);
        }
    
        private static void assertApplicationContext() {
            if (applicationContext == null) {
                throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
            }
        }
    }
    

    2.2在实体类中给主键字段添加注解

    	@Data
    	public class Test{
    	
        	@TableId(type = IdType.AUTO)
        	private Integer id;
        	
       		private String talk;
    	}
    

    2.3在使用对应的bean的时候,用一下代码进行创建

    	//获取Service
    	 TestService testService = SpringContextHolder.getBean(TestService.class);
    	//获取Mapper
    	 TestMapper testMapper = SpringContextHolder.getBean(TestMapper.class);
    
    到此,我们就已经可以使用我们想要的Bean啦,原理什么的,我看着也很烦,就不在这里说了,CV大法帮助你,哈哈
    

    PS: 内容较为简介,不过稍微一看就能看懂啦,小伙伴们加油哦

    展开全文
  • SpringbootBean的加载过程

    千次阅读 2020-12-02 22:56:31
    下面这张图根据Springboot启动调用链的顺序,画了这三个关键步骤被触发的时间点: 1、springboot怎么根据package扫描出需要被管理的类? springboot是通过启动类上的@ComponentScan注解所指定的包路径来进行扫描的...

    加载和实例化bean分以下几个重要步骤:

    1、根据package扫描出需要被管理的类
    2、将这些类封装成BeanDefinition并注册到BeanFactory容器
    3、实例化所有扫描到的BeanDefinition,其中包括解决循环依赖、延迟加载问题

    下面这张图根据Springboot启动调用链的顺序,画了这三个关键步骤被触发的时间点:
    在这里插入图片描述

    1、根据package扫描出需要被管理的类

    springboot是通过启动类上的@ComponentScan注解所指定的包路径来进行扫描的,如果没有标注这个注解,则默认从启动类所在的包路径开始扫描,会根据类的注解来判断是否需要被容器进行管理,具体代码在ConfigurationClassParser的parse方法里,从上图能看到这个方法的调用栈是SpringApplication#run()->refreshContext(context)->invokeBeanFactoryPostProcessors(beanFactory);->ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)->ConfigurationClassParser#parse,debug图如下:

    下面看parse方法的代码:

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
    		for (BeanDefinitionHolder holder : configCandidates) {
    			BeanDefinition bd = holder.getBeanDefinition();
    			try {
    				if (bd instanceof AnnotatedBeanDefinition) {
    				// parse方法里的逻辑看后面的解析,核心步骤1.1到1.8逻辑
    					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    				}
    				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
    				}
    				else {
    					parse(bd.getBeanClassName(), holder.getBeanName());
    				}
    			}
    			catch (BeanDefinitionStoreException ex) {
    				throw ex;
    			}
    			catch (Throwable ex) {
    				throw new BeanDefinitionStoreException(
    						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
    			}
    		}
        // 核心步骤 1.9
    		this.deferredImportSelectorHandler.process();
    	}
    

    parse方法会调到下面这个方法:

    在这里插入图片描述

    核心步骤如下:

    • 1.1:如果该类被@Component标注(即使被@Component标注的注解标注也算,比如@Configuration注解被@Component标注了,如果该类被@Configuration标注,那么也就被@Component标注),那么先处理这个类里定义的一些内部类,对这些内部类递归调用processConfigurationClass(ConfigurationClass configClass)方法,先解析内部类,再解析外层类

    • 1.2:判断是否有被@PropertySource标注,如果有这个注解,则将该注解的property配置文件里的key和value解析到Context的Environment对象里供后续使用

    • 1.3:判断是否被@ComponentScans标注(这个注解就是告知Spring容器遍历那些包路径来加载bean),根据配置的包路径来扫描所有的类,对需要被Spring容器管理的类(被@Component注解的类)会递归调用下面这个方法,直到这类上的@ComponentScans注解里指定的包路径下的所有类都被扫描并解析到Spring容器里(这里如果没有配置包路径,默认为该类所在的包路径),这个扫描是由ClassPathBeanDefinitionScanner类的doScan方法来实现的。debug图如下:
      在这里插入图片描述

    • 1.4:开始解析@Import注解,这个注解可以指定某些类由Spring容器管理

    • 1.5:扫描这个类是否有被@ImportResource标注,如果有这个注解,则解析该注解,这个注解作用就是引进一xml配置,比如以前Spring项目里写了很多配置bean信息的xml文件,通过这个注解将这些bean配置文件加载进来,加载这些文件里的配置信息

    • 1.6:解析类里被@Bean标注的方法

    • 1.7:解析当前类的接口里的default方法,这里可以看出可以在接口的default方法上使用@Bean注解

    • 1.8:查看该类是否有父类和父接口,如果有的话则递归调用processConfigurationClass()方法来解析

    • 1.9:最后执行前几步中扫描出来的DeferredImportSelector类,比如我们自动加载的@EnableAutoConfiguration注解里@Import引入的用于加载自动组件的AutoConfigurationImportSelector类(原理是这个类的selectImports方法会去查看META-INF/spring.factory下找到EnableAutoConfiguration的配置里的一些自动加载的组件查找spring.factory的源码解析看这里),这个接口类放在最后执行是因为这些自动加载的类很多都用到了@Conditional相关条件注解,比如@ConditionalOnMissingBean,所以需要等到其他bean已经扫描完后再执行这个类的逻辑

    1.1到1.8的代码如下:

    /**
    	 * Apply processing and build a complete {@link ConfigurationClass} by reading the
    	 * annotations, members and methods from the source class. This method can be called
    	 * multiple times as relevant sources are discovered.
    	 * @param configClass the configuration class being build
    	 * @param sourceClass a source class
    	 * @return the superclass, or {@code null} if none found or previously processed
    	 */
    	@Nullable
    	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    			throws IOException {
        // 1.1
    		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    			// Recursively process any member (nested) classes first
    			processMemberClasses(configClass, sourceClass);
    		}
        // 1.2
    		// Process any @PropertySource annotations
    		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
    				sourceClass.getMetadata(), PropertySources.class,
    				org.springframework.context.annotation.PropertySource.class)) {
    			if (this.environment instanceof ConfigurableEnvironment) {
    				processPropertySource(propertySource);
    			}
    			else {
    				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
    						"]. Reason: Environment must implement ConfigurableEnvironment");
    			}
    		}
        // 1.3
    		// Process any @ComponentScan annotations
    		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
    				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    		if (!componentScans.isEmpty() &&
    				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
    			for (AnnotationAttributes componentScan : componentScans) {
    				// The config class is annotated with @ComponentScan -> perform the scan immediately
    				Set<BeanDefinitionHolder> scannedBeanDefinitions =
    						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    				// Check the set of scanned definitions for any further config classes and parse recursively if needed
    				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
    					if (bdCand == null) {
    						bdCand = holder.getBeanDefinition();
    					}
    					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
    						parse(bdCand.getBeanClassName(), holder.getBeanName());
    					}
    				}
    			}
    		}
        // 1.4
    		// Process any @Import annotations
    		processImports(configClass, sourceClass, getImports(sourceClass), true);
        // 1.5
    		// Process any @ImportResource annotations
    		AnnotationAttributes importResource =
    				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    		if (importResource != null) {
    			String[] resources = importResource.getStringArray("locations");
    			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
    			for (String resource : resources) {
    				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
    				configClass.addImportedResource(resolvedResource, readerClass);
    			}
    		}
        // 1.6
    		// Process individual @Bean methods
    		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    		for (MethodMetadata methodMetadata : beanMethods) {
    			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    		}
        // 1.7
    		// Process default methods on interfaces
    		processInterfaces(configClass, sourceClass);
        // 1.8
    		// Process superclass, if any
    		if (sourceClass.getMetadata().hasSuperClass()) {
    			String superclass = sourceClass.getMetadata().getSuperClassName();
    			if (superclass != null && !superclass.startsWith("java") &&
    					!this.knownSuperclasses.containsKey(superclass)) {
    				this.knownSuperclasses.put(superclass, configClass);
    				// Superclass found, return its annotation metadata and recurse
    				return sourceClass.getSuperClass();
    			}
    		}
    
    		// No superclass -> processing is complete
    		return null;
    	}
    

    2、将扫描到的类封装成BeanDefinition并注册到BeanFactory容器

    通过ConfigurationClassBeanDefinitionReader来解析第三步中parser放到configurationClasses的Map里的ConfigurationClass,并解析成BeanDefinition注册到容器中,debug图如下:
    在这里插入图片描述

    /**
    	 * Read a particular {@link ConfigurationClass}, registering bean definitions
    	 * for the class itself and all of its {@link Bean} methods.
    	 */
    	private void loadBeanDefinitionsForConfigurationClass(
    			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        // 先判断是否有@Conditional注解,有的话,校验条件是否满足,不满足条件,则从容器中删除
    		if (trackedConditionEvaluator.shouldSkip(configClass)) {
    			String beanName = configClass.getBeanName();
    			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
    				this.registry.removeBeanDefinition(beanName);
    			}
    			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
    			return;
    		}
        // 将通过@Import注解引入的类封装成beanDefinition,注册到容器内
    		if (configClass.isImported()) {
    			registerBeanDefinitionForImportedConfigurationClass(configClass);
    		}
    		// 将通过@Bean标注的方法封装成BeanDefinition注册到容器内
    		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    			loadBeanDefinitionsForBeanMethod(beanMethod);
    		}
        // 加载@ImportResource指定的配置文件里的信息,加载配置文件里的beanDefinition
    		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    		// 执行引入的ImportBeanDefinitionRegistrar类的registerBeanDefinitions方法,比如@EnableConfigurationProperties注解上的EnableConfigurationPropertiesRegistrar.class
    		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    	}
    

    这里的TrackedConditionEvaluator类就是解析@Conditional注解的,比如@ConditionalOnClass、@ConditionalOnBean等注解,原理就是这些注解上都会指定一个Condition接口的实现类,通过这个类的matches方法来判断是否符合条件,比如@ConditionalOnClass注解如下图:
    在这里插入图片描述

    而OnClassCondition类图如下:
    在这里插入图片描述

    而这里有个逻辑就是像@ConditionalOnBean这个注解的条件是必须已经加载了某个bean,在调用这个注解的matches方法时,需要等到所有的bean都扫描后,所以这里还有个阶段的概念,指定当前的matches方法是在哪个阶段做匹配,比如OnBeanCondition就指定只在注册阶段匹配:
    在这里插入图片描述

    而这个阶段的枚举有两个:
    在这里插入图片描述

    PARSE_CONFIGURATION:指的是在上面的parser的parse阶段,即:在扫描包路径并封装成ConfigurationClass阶段
    REGISTER_BEAN:指的就是当前这一步的reader的loadBeanDefinitionsForConfigurationClass阶段,即:将ConfigurationClass转成beanDefinition注册到容器阶段

    3、实例化所有的BeanDefinition,其中包括解决循环依赖、延迟加载问题

    而bean的真正实例化就是通过BeanFactory容器的getBean方法来实现的,先看下BeanFactory的类图:
    在这里插入图片描述

    这里提供了通过bean名字以及类型信息来获取bean的方法,根据开头的调用链的图,我们debug进finishBeanFactoryInitialization(beanFactory)方法的beanFactory.preInstantiateSingletons()方法里,代码如下:

    @Override
    	public void preInstantiateSingletons() throws BeansException {
    		if (logger.isTraceEnabled()) {
    			logger.trace("Pre-instantiating singletons in " + this);
    		}
    
    		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
    		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
    		// Trigger initialization of all non-lazy singleton beans...
    		for (String beanName : beanNames) {
    			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    				if (isFactoryBean(beanName)) {
    					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    					if (bean instanceof FactoryBean) {
    						final FactoryBean<?> factory = (FactoryBean<?>) bean;
    						boolean isEagerInit;
    						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
    											((SmartFactoryBean<?>) factory)::isEagerInit,
    									getAccessControlContext());
    						}
    						else {
    							isEagerInit = (factory instanceof SmartFactoryBean &&
    									((SmartFactoryBean<?>) factory).isEagerInit());
    						}
    						if (isEagerInit) {
    							getBean(beanName);
    						}
    					}
    				}
    				else {
    					getBean(beanName);
    				}
    			}
    		}
    
    		// Trigger post-initialization callback for all applicable beans...
    		for (String beanName : beanNames) {
    			Object singletonInstance = getSingleton(beanName);
    			if (singletonInstance instanceof SmartInitializingSingleton) {
    				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    				if (System.getSecurityManager() != null) {
    					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    						smartSingleton.afterSingletonsInstantiated();
    						return null;
    					}, getAccessControlContext());
    				}
    				else {
    					smartSingleton.afterSingletonsInstantiated();
    				}
    			}
    		}
    	}
    

    这段代码作用就是:
    1、通过getBean(beanName)方法 实例化所有非延迟加载的bean(延迟加载的bean会在给bean做注入时生成一个代理类的方法来实现)
    2、遍历出所有已经实例化的SmartInitializingSingleton类,并调用这个类的afterSingletonsInstantiated()方法

    getBean(beanName)源码分析:

    在bean的实例化过程中,Spring将这个过程分成两个阶段:

    • 实例化阶段,Spring通过反射调用这个类的构造器得到的一个空对象,这时这个对象里的依赖都是null(除非该属性是通过构造器注入),在这个阶段完成后,就将这个空对象的引用放到一个Map中暴露出去,如果出现循环依赖时,会在这个Map中拿到引用,从而注入这个引用来解决循环依赖问题,后面会详细将这个循环依赖的解决过程,我后面称这种对象为【半实例化bean】
    • 依赖注入阶段,对空对象进行依赖注入,如果发现Spring容器内还没有所依赖的bean,则开始实例化这个所依赖的bean。我后面称这种完成注入的bean为【完全实例化bean】

    核心步骤如下:

    • 检查singletonObjects这个Map(存储已经完全实例化的bean)是否存在已经存在
    • 检查earlySingletonObjects这个Map(存储提前暴露的半实例化的bean,解决循环依赖)
    • 检查singletonFactories这个Map(存储提前暴露的半实例化的bean,解决循环依赖),如果存在则将调用这个Factory的getObject方法获取bean,然后将这个bean放到earlySingletonObjects里
    • 如果上面三步中存在已经创建的bean,则检查这个bean是否是FactoryBean,是的话,则调用这个FactoryBean的getObject方法获取bean
    • 如果不存在已经创建的bean,则需要新实例化bean,首先检查是否存在非单例bean(比如scope="prototype")循环依赖问题,如果存在,则直接报错,非单例bean的循环依赖是无法解决的,因为每次都要重新new对象,每次都是一个新的引用,已经无法通过将引用提前暴露出去的方式来解决了
    • 检查是否存在父BeanFactory,如果存在,则调用父BeanFactory的getBean来进行实例化
    • 标记bean已经创建,即:在alreadyCreated这个set中加入这个bean的beanName
    • 重新合并这个beanDefinition,这个合并的意思是指如果这个bean有父bean,则需要将父bean的beanDefinition和当前这个bean的beanDefinition合并成一个BeanDefinition,比如这种定义的bean,在实例化son的时候,需要将father的beanDefinition合并到一起,因为父bean里也可能会定义一些spring的特性(比如注入一些属性等),所以需要一起实例化,否则被son继承的father里的一些注入属性会为null
    • 查看当前bean有没有被@DependsOn注解标注,该注解的意思是标注当前bean在实例化前需要依赖的其他bean,需要先实例化@DependsOn注解中指定的依赖的类
    • 检查当前bean是否是单例bean(即:只生成一个对象),单例bean走单例bean的逻辑,详见后面单例bean分析
    • 检查当前bean是否是原型bean(即:每次都生成一个新的对象),原型bean走原型bean的逻辑,详见后面分析
    • 即非单例bean也非原型bean,则走其他Scope的逻辑,详见后面分析
    • 如果最后生成的bean类型不匹配,则进行类型转换
    /**
    	 * Return an instance, which may be shared or independent, of the specified bean.
    	 * @param name the name of the bean to retrieve
    	 * @param requiredType the required type of the bean to retrieve
    	 * @param args arguments to use when creating a bean instance using explicit arguments
    	 * (only applied when creating a new instance as opposed to retrieving an existing one)
    	 * @param typeCheckOnly whether the instance is obtained for a type check,
    	 * not for actual use
    	 * @return an instance of the bean
    	 * @throws BeansException if the bean could not be created
    	 */
    	@SuppressWarnings("unchecked")
    	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 获取bean的名字,这里主要会过滤FactoryBean的&符号
    		final String beanName = transformedBeanName(name);
    		Object bean;
    
    		// Eagerly check singleton cache for manually registered singletons.
    		// 检查是否已经创建过单例对象
    		Object sharedInstance = getSingleton(beanName);
    		if (sharedInstance != null && args == null) {
    			if (logger.isTraceEnabled()) {
    				if (isSingletonCurrentlyInCreation(beanName)) {
    					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    							"' that is not fully initialized yet - a consequence of a circular reference");
    				}
    				else {
    					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    				}
    			}
    			//如果存在已经创建的bean,则检查这个bean是否是FactoryBean,是的话,则调用这个FactoryBean的getObject方法获取bean
    			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    		}
    
    		else {
    			// Fail if we're already creating this bean instance:
    			// We're assumably within a circular reference.
    			// 如果这个bean是多例模式,而多例模式循环依赖自己的话是无法解决的,因为需要无限new对象
    			// 而单例模式的循环依赖是可以解决的,毕竟只有一个对象,引用只有一个,不需要无限new对象
    			if (isPrototypeCurrentlyInCreation(beanName)) {
    				throw new BeanCurrentlyInCreationException(beanName);
    			}
    
    			// Check if bean definition exists in this factory.
    			// 优先使用父beanFactory实例化bean
    			BeanFactory parentBeanFactory = getParentBeanFactory();
    			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    				// Not found -> check parent.
    				String nameToLookup = originalBeanName(name);
    				if (parentBeanFactory instanceof AbstractBeanFactory) {
    					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
    							nameToLookup, requiredType, args, typeCheckOnly);
    				}
    				else if (args != null) {
    					// Delegation to parent with explicit args.
    					return (T) parentBeanFactory.getBean(nameToLookup, args);
    				}
    				else if (requiredType != null) {
    					// No args -> delegate to standard getBean method.
    					return parentBeanFactory.getBean(nameToLookup, requiredType);
    				}
    				else {
    					return (T) parentBeanFactory.getBean(nameToLookup);
    				}
    			}
          // 标记bean已经被创建
    			if (!typeCheckOnly) {
    				markBeanAsCreated(beanName);
    			}
    			try {
    			  // 如果一个bean有父bean,比如<bean id="son" class="com.llf.bean.Son" parent="father" depends-on="father"></bean>,则将这个父子的链合并成一个beanDefinition,因为父bean里也可能会定义一些spring的特性,所以需要一起实例化,比如父bean里有依赖注入等
    				checkMergedBeanDefinition(mbd, beanName, args);
    
    				// Guarantee initialization of beans that the current bean depends on.
    				// 查看当前bean有没有被@DependsOn注解标注,该注解的意思是标注当前bean在实例化前依赖的其他bean,需要先实例化@DependsOn注解中指定的依赖的类
    				String[] dependsOn = mbd.getDependsOn();
    				if (dependsOn != null) {
    					for (String dep : dependsOn) {
    						if (isDependent(beanName, dep)) {
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    						}
    						registerDependentBean(dep, beanName);
    						try {
    							getBean(dep);
    						}
    						catch (NoSuchBeanDefinitionException ex) {
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
    						}
    					}
    				}
    
    				// Create bean instance.
    				// 单例模式开始实例化
    				if (mbd.isSingleton()) {
    					sharedInstance = getSingleton(beanName, () -> {
    						try {
    							return createBean(beanName, mbd, args);
    						}
    						catch (BeansException ex) {
    							// Explicitly remove instance from singleton cache: It might have been put there
    							// eagerly by the creation process, to allow for circular reference resolution.
    							// Also remove any beans that received a temporary reference to the bean.
    							destroySingleton(beanName);
    							throw ex;
    						}
    					});
    					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    				}
            // 原型模式(每次new一个新对象)的实例化
    				else if (mbd.isPrototype()) {
    					// It's a prototype -> create a new instance.
    					Object prototypeInstance = null;
    					try {
    						beforePrototypeCreation(beanName);
    						prototypeInstance = createBean(beanName, mbd, args);
    					}
    					finally {
    						afterPrototypeCreation(beanName);
    					}
    					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    				}
            // 其他自定义Scope的实例化,比如session、request的scope的实例化
    				else {
    					String scopeName = mbd.getScope();
    					final 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, () -> {
    							beforePrototypeCreation(beanName);
    							try {
    								return createBean(beanName, mbd, args);
    							}
    							finally {
    								afterPrototypeCreation(beanName);
    							}
    						});
    						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    					}
    					catch (IllegalStateException ex) {
    						throw new BeanCreationException(beanName,
    								"Scope '" + scopeName + "' is not active for the current thread; consider " +
    								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
    								ex);
    					}
    				}
    			}
    			catch (BeansException ex) {
    				cleanupAfterBeanCreationFailure(beanName);
    				throw ex;
    			}
    		}
        // 如果类型不一致则做下类型转换
    		// Check if required type matches the type of the actual bean instance.
    		if (requiredType != null && !requiredType.isInstance(bean)) {
    			try {
    				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
    				if (convertedBean == null) {
    					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    				}
    				return convertedBean;
    			}
    			catch (TypeMismatchException ex) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Failed to convert bean '" + name + "' to required type '" +
    							ClassUtils.getQualifiedName(requiredType) + "'", ex);
    				}
    				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    			}
    		}
    		return (T) bean;
    	}
    

    3.1 单例bean的实例化

    spring 默认是单例bean,即:scope=“single”

    核心步骤如下:

    • 检查用来存储已经创建的单例bean的Map:singletonObjects中是否存在该bean,如果存在则直接返回
    • 如果容器正在销毁,则停止创建并抛出异常
    • 将beanName放到singletonsCurrentlyInCreation这个set中,标记当前bean正在创建中
    • 调用createBean方法实例化bean,详见后面源码分析
    • 实例化完成后,从singletonsCurrentlyInCreation这个set中删除该beanName,标识该bean的创建过程已经完成(但是这个bean锁依赖的属性都没有完成注入,还不能使用)
    • 将完成实例化的bean放到singletonObjects这个Map中
    • 从singletonFactories、earlySingletonObjects缓存中删除这个bean,这两个缓存是为了解决循环依赖问题,因为已经完全实例化并已加到singletonObjects中,所以从这两个缓存中删除
    • 按实例化顺序保存到registeredSingletons这个set中( registeredSingletons是个linkedSet)
    if (mbd.isSingleton()) {
    		sharedInstance = getSingleton(beanName, () -> {
    			try {
    				return createBean(beanName, mbd, args);
    			}
    			catch (BeansException ex) {
    				// Explicitly remove instance from singleton cache: It might have been put there
    				// eagerly by the creation process, to allow for circular reference resolution.
    				// Also remove any beans that received a temporary reference to the bean.
    				destroySingleton(beanName);
    				throw ex;
    			}
    		});
    		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }					
    					
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    		Assert.notNull(beanName, "Bean name must not be null");
    		synchronized (this.singletonObjects) {
    		  // 检查是否该单例bean已经被创建,已经被创建就直接返回
    			Object singletonObject = this.singletonObjects.get(beanName);
    			if (singletonObject == null) {
    				if (this.singletonsCurrentlyInDestruction) {
    					throw new BeanCreationNotAllowedException(beanName,
    							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
    							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
    				}
    				if (logger.isDebugEnabled()) {
    					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
    				}
    				// 检查singletonsCurrentlyInCreation这个set中是否存在当前类,存在的话,说明当前类本来就处于创建过程中,则抛出错误,所以在单例bean的循环依赖场景中,如果是通过构造函数来进行注入时的循环依赖就会抛出错误,因为构造器注入的循环依赖场景会导致bean的构造过程都无法完成,只能报错(通过属性来注入时的循环依赖场景并不妨碍先new出该对象,然后再注入彼此的引用就可以了)
    				beforeSingletonCreation(beanName);
    				boolean newSingleton = false;
    				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    				if (recordSuppressedExceptions) {
    					this.suppressedExceptions = new LinkedHashSet<>();
    				}
    				try {
    				// 调用调用这个方法时传入的函数,即: createBean(beanName, mbd, args)
    					singletonObject = singletonFactory.getObject();
    					newSingleton = true;
    				}
    				catch (IllegalStateException ex) {
    					// Has the singleton object implicitly appeared in the meantime ->
    					// if yes, proceed with it since the exception indicates that state.
    					singletonObject = this.singletonObjects.get(beanName);
    					if (singletonObject == null) {
    						throw ex;
    					}
    				}
    				catch (BeanCreationException ex) {
    					if (recordSuppressedExceptions) {
    						for (Exception suppressedException : this.suppressedExceptions) {
    							ex.addRelatedCause(suppressedException);
    						}
    					}
    					throw ex;
    				}
    				finally {
    					if (recordSuppressedExceptions) {
    						this.suppressedExceptions = null;
    					}
    					// 实例化完成后,从singletonsCurrentlyInCreation这个set中删除该beanName,标识该bean的创建过程已经完成(但是这个bean锁依赖的属性都没有完成注入,还不能使用)
    					afterSingletonCreation(beanName);
    				}
    				if (newSingleton) {
    				  // 创建完成后,将bean缓存到singletonObjectsMap中,从为了解决循环依赖的几个缓存中删除提前暴露的引用(后面会详细提到)
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}
    

    createBean()方法解析:

    createBean方法核心逻辑是调用doCreateBean()方法:

    核心步骤如下:

    • 检查缓存FactoryBean的factoryBeanInstanceCache的Map是否存在该bean
    • 如果没有则调用createBeanInstance()来实例化对象,详见后面的createBeanInstance源码分析
    • 指向MergedBeanDefinitionPostProcessor后置处理器逻辑,这些处理器里包括负责@Resource注解解析及注入的CommonAnnotationBeanPostProcessor和负责@AutoWired及@Value注解解析和注入的AutowiredAnnotationBeanPostProcessor后置处理器
    • 将半实例化的bean(还没有注入依赖属性的bean)放到singletonFactories这个map中提前暴露出去,来解决循环依赖问题
    • 进行依赖注入操作,详见后面你的源码分析
    • 检查该bean是否实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口,如果实现了,则执行对应接口的set方法
    • 执行BeanPostProcessor后置处理器的postProcessBeforeInitialization方法,这个方法允许返回一个对象来替换当前的bean,比如返回一个代理
    • 执行bean的InitMethods方法,包括实现了InitializingBean接口的afterPropertiesSet方法,@Bean注解指定的init-method方法
    • 执行BeanPostProcessor后置处理器的postProcessAfterInitialization方法,这个方法允许返回一个对象来替换当前的bean,比如返回一个代理
    • 检查如果BeanPostProcessor后置处理器返回了一个新对象来代替原bean,那么提前暴露到singletonFactories这个Map中的引用就是失效的,需要将依赖当前这个bean的对象重新实例化
    • 注册bean被销毁时需要执行的方法,比如实现了DisposableBean接口的destroy方法,这个destroy方法是根据bean的scope来区分的,这个scope表明这个bean的声明周期,比如scope=request表示当前bean的生命周期持续到一次请求结束,那么在请求结束时就需要执行这个bean的destroy方法
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    			throws BeanCreationException {
    
    		// Instantiate the bean.
    		BeanWrapper instanceWrapper = null;
    		// FactoryBean的缓存中是否存在
    		if (mbd.isSingleton()) {
    			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    		}
    		if (instanceWrapper == null) {
    		// 实例化bean
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		//获取真正的bean
    		final Object bean = instanceWrapper.getWrappedInstance();
    		Class<?> beanType = instanceWrapper.getWrappedClass();
    		if (beanType != NullBean.class) {
    			mbd.resolvedTargetType = beanType;
    		}
        
    		// Allow post-processors to modify the merged bean definition.
    		// 执行MergedBeanDefinitionPostProcessor后置处理器,为这个bean的依赖注入做准备
    		synchronized (mbd.postProcessingLock) {
    			if (!mbd.postProcessed) {
    				try {
    					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    				}
    				catch (Throwable ex) {
    					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    							"Post-processing of merged bean definition failed", ex);
    				}
    				mbd.postProcessed = true;
    			}
    		}
    
    		// Eagerly cache singletons to be able to resolve circular references
    		// even when triggered by lifecycle interfaces like BeanFactoryAware.
    		// 为了解决循环依赖,将实例化的bean的引用提前缓存到singletonFactories这个Map中,这时的bean里的依赖属性还没有被注入(通过构造器注入的属性例外),所以是不完整的
    		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    				isSingletonCurrentlyInCreation(beanName));
    		if (earlySingletonExposure) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Eagerly caching bean '" + beanName +
    						"' to allow for resolving potential circular references");
    			}
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    
    		// Initialize the bean instance.
    		Object exposedObject = bean;
    		try {
    		 // 注入属性
    			populateBean(beanName, mbd, instanceWrapper);
    			// 执行bean的init方法(被@PostConstruct标注的方法)
    			// 执行BeanPostProcessor后置处理器的方法
    			exposedObject = initializeBean(beanName, exposedObject, mbd);
    		}
    		catch (Throwable ex) {
    			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
    				throw (BeanCreationException) ex;
    			}
    			else {
    				throw new BeanCreationException(
    						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    			}
    		}
        // 如果提前暴露的bean已经被注入,这里还需要检测是否bean被重新实例化了,如果被重新实例化了,则原来暴露出去的引用已经过期,需要重新注入
    		if (earlySingletonExposure) {
    			Object earlySingletonReference = getSingleton(beanName, false);
    			if (earlySingletonReference != null) {
    				if (exposedObject == bean) {
    					exposedObject = earlySingletonReference;
    				}
    				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    					String[] dependentBeans = getDependentBeans(beanName);
    					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    					for (String dependentBean : dependentBeans) {
    						if (!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 " +
    								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    					}
    				}
    			}
    		}
    
    		// Register bean as disposable.
    		// 注册bean被销毁时需要执行的方法,比如实现了DisposableBean接口的destroy方法
    		try {
    			registerDisposableBeanIfNecessary(beanName, bean, mbd);
    		}
    		catch (BeanDefinitionValidationException ex) {
    			throw new BeanCreationException(
    					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    		}
    
    		return exposedObject;
    	}
    

    createBeanInstance方法源码

    核心逻辑如下:

    • 通过bean名称解析出bean的Class信息
    • 查看是否配置了生成对象的Supplier,如果配置了,就是用这个Supplier来生成对象
    • 检查bean是否配置了factory-method,这个就是配置一个工厂类来生成对象,比如
    • 检查是否之前已经解析过,如果已经解析过构造器或者factory-method,则不重新解析
    • 执行SmartInstantiationAwareBeanPostProcessor后置处理器的determineCandidateConstructors方法,该后置处理器返回bean的构造器,比如AutowiredAnnotationBeanPostProcessor后置处理器会返回带参数的构造器
    • 如果存在有参构造器,则执行有参构造器,并且执行过程中会负责这个构造器里参数的注入
    • 如果不存在有参构造器就执行无参构造器
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    		// Make sure bean class is actually resolved at this point.
    		// 通过bean名称解析出bean的Class信息
    		Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
    		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());
    		}
        // 查看是否配置了生成对象的Supplier
    		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    		if (instanceSupplier != null) {
    			return obtainFromSupplier(instanceSupplier, beanName);
    		}
        // 检查bean是否配置了factory-method,比如<bean id="myBean" factory-bean="myBeanFactory" factory-method="getMyBean"></bean>
    		if (mbd.getFactoryMethodName() != null) {
    			return instantiateUsingFactoryMethod(beanName, mbd, args);
    		}
        
    		// Shortcut when re-creating the same bean...
    		// 检查是否之前已经解析过,如果已经解析过构造器或者factory-method,则不重新解析
    		boolean resolved = false;
    		boolean autowireNecessary = false;
    		if (args == null) {
    			synchronized (mbd.constructorArgumentLock) {
    				if (mbd.resolvedConstructorOrFactoryMethod != null) {
    					resolved = true;
    					autowireNecessary = mbd.constructorArgumentsResolved;
    				}
    			}
    		}
    		// 已经解析过则直接实例化
    		if (resolved) {
    			if (autowireNecessary) {
    				return autowireConstructor(beanName, mbd, null, null);
    			}
    			else {
    				return instantiateBean(beanName, mbd);
    			}
    		}
    
    		// Candidate constructors for autowiring?
    		// 执行SmartInstantiationAwareBeanPostProcessor后置处理器的determineCandidateConstructors方法,该后置处理器返回bean的构造器
    		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    				// 执行有参数的构造器
    			return autowireConstructor(beanName, mbd, ctors, args);
    		}
    
    		// Preferred constructors for default construction?
    		ctors = mbd.getPreferredConstructors();
    		if (ctors != null) {
    			return autowireConstructor(beanName, mbd, ctors, null);
    		}
        // 执行无参构造器
    		// No special handling: simply use no-arg constructor.
    		return instantiateBean(beanName, mbd);
    	}
    	
    

    populateBean源码分析

    核心步骤如下:

    • 执行InstantiationAwareBeanPostProcessor后置处理器的postProcessAfterInstantiation方法,该方法如果返回fase则表示不需要做后续的依赖注入动作,直接返回
    • 查看当前这个BeanDefinition是否配置了依赖注入的对象
    • 根据注入类型来获取对应的需要注入的对象,默认值是0,即:没有指定是通过name还是type来注入,会使用后置处理器来完成注入,这里会通过CommonAnnotationBeanPostProcessor的postProcessProperties方法完成@Resourse的注入,通过AutowiredAnnotationBeanPostProcessor的postProcessProperties来完成@AutoWired和@Value的注入,有兴趣的同学可以看着两个方法的源码
    • 执行InstantiationAwareBeanPostProcessor后置处理器的postProcessProperties方法,这里就会执行CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor来完成相应注解的注入逻辑,同时这个方法会返回一个PropertyValues对象,如果该对象有值的话,会根据这个对象再次注入,而这两个后置处理器在处理注入时,会处理@Lazy注解标志的延迟加载逻辑,详见延迟加载源码分析 如果PropertyValues对象有值,则根据这个对象里的key找到bean里的属性,完成value的注入
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    		if (bw == null) {
    			if (mbd.hasPropertyValues()) {
    				throw new BeanCreationException(
    						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
    			}
    			else {
    				// Skip property population phase for null instance.
    				return;
    			}
    		}
    
    		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    		// state of the bean before properties are set. This can be used, for example,
    		// to support styles of field injection.
    		boolean continueWithPropertyPopulation = true;
        // 执行InstantiationAwareBeanPostProcessor后置处理器的postProcessAfterInstantiation方法,该方法如果返回fase则表示不需要做后续的依赖注入动作,直接返回
    		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof InstantiationAwareBeanPostProcessor) {
    					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    						continueWithPropertyPopulation = false;
    						break;
    					}
    				}
    			}
    		}
    
    		if (!continueWithPropertyPopulation) {
    			return;
    		}
        // 查看当前这个BeanDefinition是否配置了属性
    		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    
    		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    		// 根据注入类型来获取对应的需要注入的对象,默认值是0,即:没有指定是通过name还是type来注入,会使用后置处理器来完成注入
    		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    			// Add property values based on autowire by name if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
    				autowireByName(beanName, mbd, bw, newPvs);
    			}
    			// Add property values based on autowire by type if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    				autowireByType(beanName, mbd, bw, newPvs);
    			}
    			pvs = newPvs;
    		}
    
    		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
    		PropertyDescriptor[] filteredPds = null;
    		if (hasInstAwareBpps) {
    			if (pvs == null) {
    				pvs = mbd.getPropertyValues();
    			}
    			//  执行InstantiationAwareBeanPostProcessor后置处理器的postProcessProperties方法,这里就会执行CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor来完成相应注解的注入逻辑,同时这个方法会返回一个PropertyValues对象,如果该对象有值的话,会根据这个对象再次注入
    			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof InstantiationAwareBeanPostProcessor) {
    					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    					if (pvsToUse == null) {
    						if (filteredPds == null) {
    							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    						}
    						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    						if (pvsToUse == null) {
    							return;
    						}
    					}
    					pvs = pvsToUse;
    				}
    			}
    		}
    		if (needsDepCheck) {
    			if (filteredPds == null) {
    				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    			}
    			checkDependencies(beanName, mbd, filteredPds, pvs);
    		}
       // 根据pvs对象来进行注入
    		if (pvs != null) {
    			applyPropertyValues(beanName, mbd, bw, pvs);
    		}
    	}
    

    延迟加载源码分析

    我这里以CommonAnnotationBeanPostProcessor后置处理器的代码来分析下原理,代码位置在CommonAnnotationBeanPostProcessor类的内部类ResourceElement的getResourceToInject方法里的buildLazyResourceProxy方法,思路就是并不真正的实例化这个bean,而是返回一个代理类的引用,这个代理类里会生成一个TargetSource对象,在程序运行过程中,碰到这个bean的方法被真正调用时,就会首先调用这个TargetSource对象的getTarget方法来实例化这个bean,想看详细分析的点这里,代码如下:

    
    protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) {
    		TargetSource ts = new TargetSource() {
    			@Override
    			public Class<?> getTargetClass() {
    				return element.lookupType;
    			}
    			@Override
    			public boolean isStatic() {
    				return false;
    			}
    			@Override
    			public Object getTarget() {
    				return getResource(element, requestingBeanName);
    			}
    			@Override
    			public void releaseTarget(Object target) {
    			}
    		};
    		ProxyFactory pf = new ProxyFactory();
    		pf.setTargetSource(ts);
    		if (element.lookupType.isInterface()) {
    			pf.addInterface(element.lookupType);
    		}
    		ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
    				((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);
    		return pf.getProxy(classLoader);
    	}
    
    

    循环依赖问题分析

    Spring只能解决单例bean的循环依赖问题,对于多例bean(scope=“prototype”)的是无法解决的,解决办法就是在bean半实例化出来时(这时候的bean的注入逻辑还没完成,只是刚通过反射构造器new出来的一个空对象),就将这个bean的引用提前暴露到一个Map中,而依赖这个对象的bean在创建时,会首先遍历这个Map,并将找到的引用注入到bean中,这样就解决了循环依赖问题,但是当bean循环依赖的对象是通过构造器来进行注入时,就无法解决了,因为这时候连半实例化的对象都没有(因为要通过构造器的反射来实例化对象),下面是bean在创建过程中几个缓存的get和set的时间点的分布图:
    在这里插入图片描述

    3.2 原型bean的创建(scope=“prototype”)

    原型bean是每次都创建新的对象,所以每次是直接调用createBean方法,不像单例bean会将创建后的bean放到一个Map中并且每次首先查询这个Map,原型bean在创建前会调用beforePrototypeCreation()方法,将beanName放入prototypesCurrentlyInCreation这个set中,这个set存放了处于创建中的非单例bean,原型bean在创建前会遍历这个Set,如果存在则直接报错,所以对于非单例的bean的循环依赖问题,spring是没办法解决的

    
    else if (mbd.isPrototype()) {
    					// It's a prototype -> create a new instance.
    					Object prototypeInstance = null;
    					try {
    						beforePrototypeCreation(beanName);
    						prototypeInstance = createBean(beanName, mbd, args);
    					}
    					finally {
    						afterPrototypeCreation(beanName);
    					}
    					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    				}
    
    

    3.3 其他Scope的bean的创建

    比如scope=“request”、scope="session"这种生命周期的bean的创建过程,逻辑是调用通过Scope的get方法来获取bean,比如request的Scope的get方法会先从一个requestAttribute对象里取bean,如果不存在则再通过beanFactory来生成bean:
    在这里插入图片描述

      {
    					String scopeName = mbd.getScope();
    					final 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, () -> {
    							beforePrototypeCreation(beanName);
    							try {
    								return createBean(beanName, mbd, args);
    							}
    							finally {
    								afterPrototypeCreation(beanName);
    							}
    						});
    						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    					}
    					catch (IllegalStateException ex) {
    						throw new BeanCreationException(beanName,
    								"Scope '" + scopeName + "' is not active for the current thread; consider " +
    								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
    								ex);
    					}
    				}
    
    展开全文
  • SpringBootBean解析

    2020-04-09 22:46:54
    /** * 下面几行是为了解决特殊的依赖,如果有 bean 依赖了以下几个(可以发现都是跟容器相关的接口),会注入这边相应的值, * 这是因为 Spring 容器里面不保存容器本身,所以容器相关的依赖要到 ...

    Spring IOC思想

    官方文档

    This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) [1]principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the Service Locator pattern.
    In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
    本章介绍了控制反转(IoC)[1]原理的Spring框架实现。IoC也称为依赖项注入(DI)。它是一个对象定义其依赖项的过程,也就是说,对象只通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义它们所使用的其他对象。然后容器在创建bean时注入这些依赖项。这个过程基本上与bean本身相反,因此称为控制反转(IoC), bean本身通过使用类的直接构造或服务定位器模式等机制来控制其依赖项的实例化或位置。
    在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是由Spring IoC容器实例化、组装和管理的对象。否则,bean只是应用程序中的众多对象之一。bean及其之间的依赖关系反映在容器使用的配置元数据中。

    IOC全称为“Inversion of Control”,即控制反转,不是一种技术,而是一种设计思想。在这种设计思想中,你设计好的对象交给容器管理,而不是在应用程序内部对对象进行管理。控制的含义是IOC容器控制了对象(也可以包括文件及其他外部资源);而反转的含义是IOC容器负责创建及注入依赖的对象,但在传统的应用程序中,我们需要在对象内部去创建(new)依赖的对象,这叫“正”,在这样的情况下,对象之间的耦合度就非常高。IOC更像是一种中介,帮助雇佣者和被雇佣者。
    在这里插入图片描述

    refresh()方法解析

    在这里插入图片描述

    • prepareRefresh();
    	protected void prepareRefresh() {
    		// Switch to active.
    		// 记录启动时间,
        	// 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
    		this.startupDate = System.currentTimeMillis();
    		this.closed.set(false);
    		this.active.set(true);
    
    		if (logger.isDebugEnabled()) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Refreshing " + this);
    			}
    			else {
    				logger.debug("Refreshing " + getDisplayName());
    			}
    		}
    
    		// Initialize any placeholder property sources in the context environment.
    		//初始化属性,配置servletContext,servletConfig
    		initPropertySources();
    
    		// Validate that all properties marked as required are resolvable:
    		// see ConfigurablePropertyResolver#setRequiredProperties
    		//检验是否配置必备的属性,如果这个属性没有配置,则报错
    		getEnvironment().validateRequiredProperties();
    
    		// Store pre-refresh ApplicationListeners...
    		if (this.earlyApplicationListeners == null) {
    			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    		}
    		else {
    			// Reset local application listeners to pre-refresh state.
    			this.applicationListeners.clear();
    			this.applicationListeners.addAll(this.earlyApplicationListeners);
    		}
    
    		// Allow for the collection of early ApplicationEvents,
    		// to be published once the multicaster is available...
    		this.earlyApplicationEvents = new LinkedHashSet<>();
    	}
    

    1.容器状态的设置。
    2.初始化属性的设置。
    3.检查必备属性是否存在。

    • obtainFreshBeanFactory()
    	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    		refreshBeanFactory();
    		return getBeanFactory();
    	}
    

    错误的分析
    进入refreshBeanFactory()方法

    	~~@Override
    	/*protected final void refreshBeanFactory() throws BeansException {
    		if (hasBeanFactory()) {
    			destroyBeans();
    			closeBeanFactory();
    		}
    		try {
    			DefaultListableBeanFactory beanFactory = createBeanFactory();
    			beanFactory.setSerializationId(getId());
    			customizeBeanFactory(beanFactory);
    			loadBeanDefinitions(beanFactory);
    			synchronized (this.beanFactoryMonitor) {
    				this.beanFactory = beanFactory;
    			}
    		}
    		catch (IOException ex) {
    			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    		}
    	}*/
    
    	/**
    	 * This implementation performs an actual refresh of this context's underlying
    	 * bean factory, shutting down the previous bean factory (if any) and
    	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
    	 */~~ 
    

    根据方法注释我们可以知道,这个方法主要是为上下文生命周期的下一阶段初始化一个新的bean工厂,如果之前已经存在bean工厂的话,则关闭在以前的初始化一个新的bean工厂,同时为其设置序列号ID。在customizeBeanFactory(beanFactory)中设置beanFactory是否允许bean定义的覆盖,和是否允许循环引用。refreshBeanFactory就是进行Bean的发现,读取和注册实现。
    分析到这里我发现我跟错代码了…
    AbstractApplicationContext是一个抽象类,它有两个实现类实现了refreshBeanFactory()方法
    在这里插入图片描述
    我断点调试可以知道,进入的是GenericApplicationContext的refreshBeanFactory()方法,因为我们创建的ApplicationContext为AnnotationConfigServletWebServerApplicationContext
    在这里插入图片描述
    我们看一下AnnotationConfigServletWebServerApplicationContext的UML图
    在这里插入图片描述AnnotationConfigServletWebServerApplicationContext继承ServletWebServerApplicationContext,而ServletWebServerApplicationContext继承GenericWebApplicationContext,因为子类没有重写refreshBeanFactory(),所以我们这里调用的是GenericWebApplicationContext的refreshBeanFactory()方法。
    进入refreshBeanFactory()方法

    	@Override
    	protected final void refreshBeanFactory() throws IllegalStateException {
    		if (!this.refreshed.compareAndSet(false, true)) {
    			throw new IllegalStateException(
    					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    		}
    		this.beanFactory.setSerializationId(getId());
    	}
    

    标志refreshed,表面BeanFactory已经更新,设置BeanFactory的序列化ID。
    总的来说,obtainFreshBeanFactory设置beanFactory,并返回。

    • prepareBeanFactory();
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 设置 BeanFactory 的类加载器,这里设置为当前 ApplicationContext 的类加载器
        beanFactory.setBeanClassLoader(getClassLoader());
        // 设置表达式解析器
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        
        // 添加Aware后置处理器,实现了 Aware 接口的 beans 在初始化的时候,这个 processor 负责回调
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        
        /**
         * 下面几行的意思是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,Spring 会通过其他方式来处理这些依赖
         */
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    
        /**
        * 下面几行是为了解决特殊的依赖,如果有 bean 依赖了以下几个(可以发现都是跟容器相关的接口),会注入这边相应的值,
        * 这是因为 Spring 容器里面不保存容器本身,所以容器相关的依赖要到 resolvableDependencies 里面找。上文有提到过,
        * ApplicationContext 继承了 ResourceLoader、ApplicationEventPublisher、MessageSource,所以对于这几个依赖,
        * 可以赋值为 this,注意 this 是一个 ApplicationContext。
        * 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
        */
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
    
        /**
         * 这也是个 BeanPostProcessor ,在 bean 实例化后,如果是 ApplicationListener 的子类,那么将其添加到 listener 列表中,
         * 可以理解成:注册监听器
         */
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    
    
        /**
         * 从下面几行代码我们可以知道,Spring 往往很 "智能" 就是因为它会帮我们默认注册一些有用的 bean,我们也可以选择覆盖
         */
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }
    
    • postProcessBeanFactory();
    	@Override
    	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    		super.postProcessBeanFactory(beanFactory);
    		if (this.basePackages != null && this.basePackages.length > 0) {
    			this.scanner.scan(this.basePackages);
    		}
    		if (!this.annotatedClasses.isEmpty()) {
    			this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
    		}
    	}
    

    调用父类实现

    	@Override
    	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    		beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
    		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    		registerWebApplicationScopes();
    	}
    

    总的来说,首先是增加一个beanPostProcessor处理器,主要用于在bean初始化前后设置servlet相关配置,registerWebApplicationScopes()注册web应用的作用域和环境配置信息。这里需要注意的是basePackages 和this.annotatedClasses.isEmpty()的条件都不满足
    在这里插入图片描述
    所以不会通过scanner, reader来注册beanDefinition。
    总的来说,postProcessBeanFactory用于子类重写以在BeanFactory完成创建后,用于进一步的设置。

    • invokeBeanFactoryPostProcessors();
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
    		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    		}
    	}
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 首先通过getBeanFactoryPostProcessors查找手动配置的beanFactory后置处理器。(在前面分析的Initializer和listener中增加)

    • 判断其是否实现BeanDefinitionRegistryPostProcessor接口,如果是则先执行postProcessBeanDefinitionRegistry方法,并区分暂存到两个集合当中。BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口。

    • 通过beanFactory的getBeanNamesForType方法来查找容器中BeanDefinitionRegistryPostProcessor的实现,然后按优先级及排序,非排序等分别执行。

    • 把BeanDefinitionRegistryPostProcessor接口的方法都执行完成后,再分别执行其BeanFactoryPostProcessor接口的方法(这里包括手动配置及容器中查找的),并记录名字到集合。

    • 把BeanDefinitionRegistryPostProcessor接口的方法都执行完成后,再分别执行其BeanFactoryPostProcessor接口的方法(这里包括手动配置及容器中查找的),并记录名字到集合。
      总的来说,简单描述下,就是先查找BeanDefinitionRegistryPostProcessor接口实现并执行postProcessBeanDefinitionRegistry方法实现向容器中添加bean的定义,然后再查找执行BeanFactoryPostProcessor接口的实现,并执行postProcessBeanFactory方法,向容器中bean的定义添加属性。

    • registerBeanPostProcessors(beanFactory);

    	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    	}
    
    	public static void registerBeanPostProcessors(
    			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
                    // 查找BeanPostProcessor实现的名称
    		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    
    		// 添加BeanPostProcessorChecker,用于打印日志提示在BeanPostProcessor实例化期间新建bean,不能被全部的BeanPostProcessor实例处理
    		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    
    		// 按优先级,排序,非排序等分类调用.
    		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    		List<String> orderedPostProcessorNames = new ArrayList<>();
    		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    		for (String ppName : postProcessorNames) {
    			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    			        // 实例化
    				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    				priorityOrderedPostProcessors.add(pp);
    				// 记录内部处理
    				if (pp instanceof MergedBeanDefinitionPostProcessor) {
    					internalPostProcessors.add(pp);
    				}
    			}
    			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				orderedPostProcessorNames.add(ppName);
    			}
    			else {
    				nonOrderedPostProcessorNames.add(ppName);
    			}
    		}
    
    		// 先是优先级高的
    		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    
    		// 再是实现排序的
    		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    		for (String ppName : orderedPostProcessorNames) {
    			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    			orderedPostProcessors.add(pp);
    			// 记录内部处理
    			if (pp instanceof MergedBeanDefinitionPostProcessor) {
    				internalPostProcessors.add(pp);
    			}
    		}
    		sortPostProcessors(orderedPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    
    		// 然后是普通的
    		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    		for (String ppName : nonOrderedPostProcessorNames) {
    			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    			nonOrderedPostProcessors.add(pp);
    			// 记录内部处理
    			if (pp instanceof MergedBeanDefinitionPostProcessor) {
    				internalPostProcessors.add(pp);
    			}
    		}
    		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    
    		// 最后是MergedBeanDefinitionPostProcessor的实现
    		sortPostProcessors(internalPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
    		// 最最后增加一个关于ApplicationListener的探测类
    		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    	}
    
    

    总的来说就是找到BeanPostProcessor的实现,排序后又注册进容器中。

    • initMessageSource();
    protected void initMessageSource() {
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
    			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
    			// Make MessageSource aware of parent MessageSource.
    			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
    				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
    				if (hms.getParentMessageSource() == null) {
    					// Only set parent context as parent MessageSource if no parent MessageSource
    					// registered already.
    					hms.setParentMessageSource(getInternalParentMessageSource());
    				}
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using MessageSource [" + this.messageSource + "]");
    			}
    		}
    		else {
    			// Use empty MessageSource to be able to accept getMessage calls.
    			DelegatingMessageSource dms = new DelegatingMessageSource();
    			dms.setParentMessageSource(getInternalParentMessageSource());
    			this.messageSource = dms;
    			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
    			}
    		}
    	}
    

    初始化国际化相关的属性

    • initApplicationEventMulticaster();
      初始化事件广播器注册到容器当中。
    • onRefresh();
      该方法主要由AbstractApplicationContext子类来扩展实现,因为我们的web服务,所以由于ServletWebServerApplicationContext实现,主要是实例化web服务,比如ServletContext上下文配置,tomcat初始化配置等。
    • registerListeners
      添加容器内的监听器到事件广播器当中,然后派发早期没有处理的事件。
    • finishBeanFactoryInitialization(beanFactory);
      初始化单例的bean。这里不做详细的分析,后面会另开一章分析。
    • finishRefresh();
      初始化生命周期处理器,完成刷新工作,清除缓存;注册LifecycleProcessor的实现DefaultLifecycleProcessor并调用onRefresh方法;发布刷新事件;启动web服务等。
    • resetCommonCaches();
      处理上述方法产生的缓存的数据
      参考 :1
      2
      3
      4
    展开全文
  • import org.spring...import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component public class DataSourceConfig {
    package com.abcd.config;
    
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    import javax.sql.DataSource;
    
    @Component
    public class DataSourceConfig {
    
        @Bean
        public DataSource dodb(){
            DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
            dataSourceBuilder.driverClassName("com.mysql.jdbc.Driver");
            dataSourceBuilder.url("jdbc:mysql://192.168.180.121:3306/abcd_sc?useUnicode=true&characterEncoding=utf-8");
            dataSourceBuilder.username("root");
            dataSourceBuilder.password("111111");
            return dataSourceBuilder.build();
        }
    }
    

    先启动springboot,这时候没有初始化datasource,数据库也可以不启动。
    访问/db后初始化datasource,再访问/db2 和/do1就和平常一样可以使用数据库了

    package com.abcd.controller;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.context.ApplicationContext;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.sql.DataSource;
    import java.util.List;
    
    @Controller
    public class IndexController {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        // http://192.168.3.27:8080/abcd/db
        @GetMapping("/db")
        @ResponseBody
        public String database(){
    
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry)  applicationContext.getAutowireCapableBeanFactory();
    
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HikariDataSource.class);
            builder.addPropertyValue("driverClassName", "com.mysql.jdbc.Driver");
            builder.addPropertyValue("jdbcUrl", "jdbc:mysql://192.168.180.121:3306/abcd_sc?useUnicode=true&characterEncoding=utf-8");
            builder.addPropertyValue("username", "root");
            builder.addPropertyValue("password", "111111");
            builder.addPropertyValue("poolName", "my1");
    
            BeanDefinition def = builder.getBeanDefinition();
            String key = "ds1";
            if(!registry.containsBeanDefinition(key)) registry.registerBeanDefinition(key, def);
    
            DataSource obj1 = applicationContext.getBean(key, DataSource.class);
            // 获取启动时候配置的datasource,可以这样配置多数据源,延迟数据库连接检查,防止数据库连不上启动不了
            // DataSource obj2 = applicationContext.getBean("dodb", DataSource.class);
    
            System.out.println(obj1);
            // System.out.println(obj2);
    
            JdbcTemplate jdbcTemplate = new JdbcTemplate(obj1);
    
    
            List resultList = jdbcTemplate.queryForList("show tables;");
            System.out.println(resultList);
            return "db";
        }
    
        @GetMapping("/db2")
        @ResponseBody
        public String database2(){
            DataSource obj1 = applicationContext.getBean("ds1", DataSource.class);
            JdbcTemplate jdbcTemplate = new JdbcTemplate(obj1);
    
    
            List resultList = jdbcTemplate.queryForList("show tables;");
            System.out.println(resultList);
    
            return "db2";
        }
    
        @Autowired
        private ProjRepo projRepo;
    
        @Autowired
        private AcctUserRepo acctUserRepo;
    
        @GetMapping("/do1")
        @ResponseBody
        public String test(){
            List<Proj> projs = projRepo.findAll();
            System.out.println(projs.size());
    
            return "db2";
        }
    
    
    }
    
    
    展开全文
  • DI(依赖注入):全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。 那么IOC和DI这两者又是什么关系呢? IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。 把本来在类...
  • org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userController’: Unsatisfied dependency expressed through field ‘userService’; nested exception is ...
  • springboot-启动bean冲突

    千次阅读 2019-07-30 14:09:25
    在一次启动中遇到了bean冲突的问题,提示存在两个名称重复的bean org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.test.api.Application]; nested ...
  • springboot 启动报找不到注入bean

    千次阅读 2018-08-29 13:42:12
    springboot 启动报找不到注入bean 检查所有的注解 发现model类@Entity缺失  
  • 使用Test方法验证时,启动时始终提示无法注入Bean. 解决办法: 1.首先检查包名,包路径是否一致,如图所示: 2.继承ApplicationTest类 这种方法较为简单,直接在测试类上继承对应的ApplicationTest类。这样的...
  • 了解过springboot的加载流程的都知道springboot初始化bean都在refresh方法中。这个方法代码如下:// Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean ...
  • springBoot过滤器注入Bean的空指针问题

    千次阅读 2019-04-23 18:17:37
    在过滤器中的doFilterInternal写业务代码时,需要用到spring bean组件,发现在过滤器中无法初始化bean组件,均为NullpointException,经检查扫描包路径没问题。最终确定容器加载顺序引发的问题,在web.xml中各个元素...
  • 启动工程失败,报错如下所示: Field demoService in .......... required a bean of type '...........' that could not be found. Consider defining a bean of type '..............' in your configuration. ...
  • 先贴图 先说说我的具体排查思路 1.先看看数据库类型和实体类类型是否一致 2.是否忘了加注解 3.检查配置文件的数据源配置和mybatis配置 ...6.看pom文件的resource注解配置的mapper路径是否正确,xml配置...8.检查p...
  • springboot启动流程原理以及bean加载创建
  • 最近公司项目搭了一个springboot项目进行开发,在单元测试时,由于生成项目后可能哪个同事把项目生产的test文件目录删了,也不知道是项目生成时test目录没有生成,需要自己建立一个test目录进行测试。就是下图中的红...
  • Spring Bean四种注入方式(Springboot环境)_无界编程-CSDN博客 注入的方式 其他网址 为什么Spring推荐使用构造器注入而不是Field注入- OSCHINA - 中文开源技术交流社区为什么Spring推荐使用构造器注入? - ...
  • 通过情况下,如我们想在系统中添加一个健康检查的接口,我们怎么做呢? 我们会新建一个类,或在已存在类的基础上添加检测接口。 package com.crhms.medicareopinion; import org.springframework.web.bind....
  • 普通 Bean 或者带有 @Configuration 的配置文件 实现 ImportSelector 接口进行动态注入 实现 ImportBeanDefinitionRegistrar 接口进行动态注入 ​ 这里导入的是第二种 importSelector,这是一种动态注入 Bean 的...
  • springboot相同类名bean引发问题

    千次阅读 2018-02-18 23:14:38
    使用第三方jar包里的注解时,特别是这个注解是要把bean注入到spring的时候,写代码的时候IDE不会提升错误,但是运行时会出现bean不存在报错 原因: 1,要注解的两个类来之不同的依赖jar包,但是有相同的类名 2,第...
  • 博主学习了SpringBoot单元测试之后想做一个小的案例,在整合单元测试的时候出现了一个灰常严肃的问题,也是我的老壳不长记性吧,刚学完就忘记了。 现在就来探讨一下问题所在吧。 public class test { @...
  • dubbo版本:2.6.5,springboot版本:1.5.17 问题描述 最近公司要将dubbo改为api配置方式,由于xml配置很多过渡期会混合使用两种配置。升级改造期间服务竟然报错重复bean id异常,异常堆栈如下 2019-05-31 09:43:00,...
  • 按照传统的方式,对注入进行检查。service层已经加了@service的注解,怎么还是注入失败了呢,想查看配置文件,发现springboot没有配置文件,那么他是怎么扫描注解的呢?   百度了一下才知道,springboot默认...
  • springboot属性注入

    2021-01-11 20:41:15
    SpringBoot第二天 今天是学习SpringBoot的第二天,来总结一下今天所学习的东西吧。 编写和维护接口文档是每个程序员的职责,前面我们已经写好的接口现在需要提供一份文档,这样才能方便调用者使用。 考虑到编写接口...
  • 有一个问题一直让我好奇,为什么在SpringBoot中有的bean 我们都没有配置却能够自动注入,这个比如说我们使用JdbcTemplate 的时候那个对象明明我们都没有配置但是却能获取到。再比如SpringBoot在结合Redis的时候,...
  • 在阅读Spring Boot源码时,看到Spring Boot中大量使用ImportBeanDefinitionRegistrar来实现Bean的动态注入。它是Spring中一个强大的扩展接口。本篇文章来讲讲它相关使用。 Spring Boot中的使用 在Spring Boot 内置...
  • 小Hub领读:我觉得这是SpringBoot的比较核心的功能了,就是这个starter,自动装配,让我们可以快速集成第三方框架,真是个好设计!太赞了,SpringBoot+Vue前后端分离完整入门教程!​mp.weixin.qq.com作者:jack_xu...
  • 注入bean失败

    2018-08-04 18:27:08
    springboot+dubbo+zookeeper启动provider时报错RedisUtils注入失败 RedisUtils是以工具jar包依赖到shop-user工程中,该工程包含2个项目shop-user-provider和shop-user-consumer , 配置application.yml没问题 ,  ...
  • 记一个SpringBoot中属性注入失败的问题Consider defining a bean of type ‘’’ in your configuration 今天遇到的一个问题: 代码检查了好几次,都没有错误,但是启动时就会报错Consider defining a bean of type ...
  • spring会为该类生成一个jdk或cglib的动态代理,并缓存到beanFactory中,当其他类需要注入该类时,实际得到的是该类的代理,本文主要将从源码的角度介绍springboot启动过程以及如何利用jdk或cglib生成目标对象的代理...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,377
精华内容 3,350
关键字:

启动springboot注入bean检查

spring 订阅