精华内容
下载资源
问答
  • 启动springboot注入bean检查
    2022-08-01 10:11:43

    方式一:配置文件+<bean/>标签

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--xml方式声明自己开发的bean-->
        <bean id="cat" class="Cat"/>
        <bean class="Dog"/>
    ​
        <!--xml方式声明第三方开发的bean-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
        <bean class="com.alibaba.druid.pool.DruidDataSource"/>
        <bean class="com.alibaba.druid.pool.DruidDataSource"/>
    </beans>

    方式二:配置文件扫描+注解定义bean

    由于方式一种需要将spring管控的bean全部写在xml文件中,对于程序员来说非常不友好,所以就有了第二种方式。哪一个类要受到spring管控加载成bean,就在这个类的上面加一个注解,还可以顺带起一个bean的名字(id)。这里可以使用的注解有@Component以及三个衍生注解@Service、@Controller、@Repository。

    @Component("tom")
    public class Cat {
    }
    @Service
    public class Mouse {
    }

    @Component
    public class DbConfig {
        @Bean
        public DruidDataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            return ds;
        }
    }

    上面提供的仅仅是bean的声明,spring并没有感知到这些东西,可以通过下列xml配置设置spring去检查哪些包,发现定了对应注解,就将对应的类纳入spring管控范围,声明成bean。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
        ">
        <!--指定扫描加载bean的位置-->
        <context:component-scan base-package="com.itheima.bean,com.itheima.config"/>
    </beans>

    方式二声明bean的方式是目前企业中较为常见的bean的声明方式,但是也有缺点。方式一中,通过一个配置文件,你可以查阅当前spring环境中定义了多少个或者说多少种bean,但是方式二没有任何一个地方可以查阅整体信息,只有当程序运行起来才能感知到加载了多少个bean。

    方式三:注解方式声明配置类

    @ComponentScan({"com.itheima.bean","com.itheima.config"})
    public class SpringConfig3 {
        @Bean
        public DogFactoryBean dog(){
            return new DogFactoryBean();
        }
    }

    使用FactroyBean接口

    补充一个小知识,spring提供了一个接口FactoryBean,也可以用于声明bean,只不过实现了FactoryBean接口的类造出来的对象不是当前类的对象,而是FactoryBean接口泛型指定类型的对象。如下列,造出来的bean并不是DogFactoryBean,而是Dog。有什么用呢?可以在对象初始化前做一些事情,下例中的注释位置就是让你自己去扩展要做的其他事情的。

    public class DogFactoryBean implements FactoryBean<Dog> {
        @Override
        public Dog getObject() throws Exception {
            Dog d = new Dog();
            //.........
            return d;
        }
        @Override
        public Class<?> getObjectType() {
            return Dog.class;
        }
        @Override
        public boolean isSingleton() {
            return true;
        }
    }

    有人说,注释中的代码写入Dog的构造方法不就行了吗?干嘛这么费劲转一圈,还写个类,还要实现接口,多麻烦啊。还真不一样,你可以理解为Dog是一个抽象后剥离的特别干净的模型,但是实际使用的时候必须进行一系列的初始化动作。只不过根据情况不同,初始化动作不同而已。如果写入Dog,或许初始化动作A当前并不能满足你的需要,这个时候你就要做一个DogB的方案了。然后,就没有然后了,你就要做两个Dog类。当时使用FactoryBean接口就可以完美解决这个问题。

    通常实现了FactoryBean接口的类使用@Bean的形式进行加载,当然你也可以使用@Component去声明DogFactoryBean,只要被扫描加载到即可,但是这种格式加载总觉得怪怪的,指向性不是很明确。

    @ComponentScan({"com.itheima.bean","com.itheima.config"})
    public class SpringConfig3 {
        @Bean
        public DogFactoryBean dog(){
            return new DogFactoryBean();
        }
    }

    注解格式导入XML格式配置的bean

    再补充一个小知识,由于早起开发的系统大部分都是采用xml的形式配置bean,现在的企业级开发基本上不用这种模式了。但是如果你特别幸运,需要基于之前的系统进行二次开发,这就尴尬了。新开发的用注解格式,之前开发的是xml格式。这个时候可不是让你选择用哪种模式的,而是两种要同时使用。spring提供了一个注解可以解决这个问题,@ImportResource,在配置类上直接写上要被融合的xml配置文件名即可,算的上一种兼容性解决方案,没啥实际意义。

    @Configuration
    @ImportResource("applicationContext1.xml")
    public class SpringConfig32 {
    }

    proxyBeanMethods属性

    前面的例子中用到了@Configuration这个注解,当我们使用AnnotationConfigApplicationContext加载配置类的时候,配置类可以不添加这个注解。但是这个注解有一个更加强大的功能,它可以保障配置类中使用方法创建的bean的唯一性。为@Configuration注解设置proxyBeanMethods属性值为true即可,由于此属性默认值为true,所以很少看见明确书写的,除非想放弃此功能。

    @Configuration(proxyBeanMethods = true)
    public class SpringConfig33 {
        @Bean
        public Cat cat(){
            return new Cat();
        }
    }

    下面通过容器再调用上面的cat方法时,得到的就是同一个对象了。注意,必须使用spring容器对象调用此方法才有保持bean唯一性的特性。此特性在很多底层源码中有应用,

    public class App33 {
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig33.class);
            String[] names = ctx.getBeanDefinitionNames();
            for (String name : names) {
                System.out.println(name);
            }
            System.out.println("-------------------------");
            SpringConfig33 springConfig33 = ctx.getBean("springConfig33", SpringConfig33.class);
            System.out.println(springConfig33.cat());
            System.out.println(springConfig33.cat());
            System.out.println(springConfig33.cat());
        }
    }

    方式四:使用@Import注解注入bean

    @Import({Dog.class,DbConfig.class})
    public class SpringConfig4 {
    }

    使用@Import注解注入配置类

    除了加载bean,还可以使用@Import注解加载配 置类。其实本质上是一样的,不解释太多了。

    @Import(DogFactoryBean.class)
    public class SpringConfig4 {
    }

    方式五:编程形式注册bean

    前面介绍的加载bean的方式都是在容器启动阶段完成bean的加载,下面这种方式就比较特殊了,可以在容器初始化完成后手动加载bean。通过这种方式可以实现编程式控制bean的加载。

    public class App5 {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            //上下文容器对象已经初始化完毕后,手工加载bean
            ctx.register(Mouse.class);
        }
    }

    其实这种方式坑还是挺多的,比如容器中已经有了某种类型的bean,再加载会不会覆盖呢?这都是要思考和关注的问题。新手慎用。

    public class App5 {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            //上下文容器对象已经初始化完毕后,手工加载bean
            ctx.registerBean("tom", Cat.class,0);
            ctx.registerBean("tom", Cat.class,1);
            ctx.registerBean("tom", Cat.class,2);
            System.out.println(ctx.getBean(Cat.class));
        }
    }

    方式六:导入实现了ImportSelector接口的类

    public class MyImportSelector implements ImportSelector {
        @Override
        //medata 元数据
        public String[] selectImports(AnnotationMetadata metadata) {
            //各种条件的判定,判定完毕后,决定是否装载指定的bean
            boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Configuration");
            if(flag){
                return new String[]{"com.itheima.bean.Dog"};
            }
            return new String[]{"com.itheima.bean.Cat"};
        }
    }
    ​

    方式七:导入实现了ImportBeanDefinitionRegistrar接口的类

    public class MyRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            //BeanDefinition创建bean的
            //创建一个BeanDefinition对象,
            BeanDefinition beanDefinition =     
                BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
            //设置是否单例
            beanDefinition.setScope();
            //使用registry注册bean;
            //参数一 bean的名字
            registry.registerBeanDefinition("bookService",beanDefinition);
        }
    }

    方式八:导入实现了BeanDefinitionRegistryPostProcessor接口的类

    public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            BeanDefinition beanDefinition = 
                BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
            registry.registerBeanDefinition("bookService",beanDefinition);
        }
    }
    ​

    总体上来说,上面介绍了各种各样的bean的注册加载初始化方式,脑子里建立个概念吧,方式很多,spring源码中大量运用各种方式。

    总结

    1. bean的定义由前期xml配置逐步演化成注解配置,本质是一样的,都是通过反射机制加载类名后创建对象,对象就是spring管控的bean

    2. @Import注解可以指定加载某一个类作为spring管控的bean,如果被加载的类中还具有@Bean相关的定义,会被一同加载

    3. spring开放出了若干种可编程控制的bean的初始化方式,通过分支语句由固定的加载bean转成了可以选择bean是否加载或者选择加载哪一种bean

    更多相关内容
  • 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: 内容较为简介,不过稍微一看就能看懂啦,小伙伴们加油哦

    展开全文
  • 目录简介使用自定义注解, 将bean注入springboot容器中项目结构类代码自定义注解启动类 简介 ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。 使用@Import,如果括号...

    简介

    • ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类
    • 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。

    使用自定义注解, 将bean注入到springboot容器中

    项目结构

    项目结构

    类代码

    自定义注解

    /**
     * 自定义注解, 作用同spring @service注解
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyService {
        
        
    }
    

    需要被注入的类

    /**
     * 被注入的类
     */
    @MyService
    public class UserService {
    
        public void print(){
            System.out.println("userService对象注入成功");
        }
    }
    

    启动类

    @SpringBootApplication
    @EnableAsync
    @EnableScheduling
    //在启动类上, 标记@Import注解, MyImportBeanDefinitionRegistrar类是ImportBeanDefinitionRegistrar子类
    @Import({MyImportBeanDefinitionRegistrar.class})
    public class Application {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
            UserService bean = context.getBean(UserService.class);
            bean.print();
        }
    }
    

    在启动类上标记@Import注解, 将MyImportBeanDefinitionRegistrar类设置为属性, 项目启动时, 会执行MyImportBeanDefinitionRegistrar类中的registerBeanDefinitions()方法

    MyImportBeanDefinitionRegistrar

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            //自定义的扫描类MyClassPathBeanDefinitionScanner, 实现了ClassPathBeanDefinitionScanner接口
            // 当前MyClassPathBeanDefinitionScanner已被修改为扫描带有指定注解的类
            MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
    //        scanner.setResourceLoader(resourceLoader);
            scanner.registerFilters();
            scanner.doScan("com.hctrl");
        }
    }
    

    在该类中, 自定义了一个扫描器MyClassPathBeanDefinitionScanner, 通过给扫描器设置扫描的注解, 扫描的路径, 就会将该路径下的标有扫描注解的类进行注入

    MyClassPathBeanDefinitionScanner

    public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
    
        public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
            super(registry, useDefaultFilters);
        }
    
        /**
         * @addIncludeFilter 将自定义的注解添加到扫描任务中
         * @addExcludeFilter 将带有自定义注解的类 ,不加载到容器中
         */
        protected void registerFilters () {
            /**
             *  addIncludeFilter  满足任意includeFilters会被加载
             *  注入@MyService注解标记的类
             */
            addIncludeFilter(new AnnotationTypeFilter(MyService.class));
            /**
             *  addExcludeFilter 同样的满足任意excludeFilters不会被加载
             *  可以配置过滤
             */
            // addExcludeFilter(new AnnotationTypeFilter(MyService.class));
        }
    
        /**
         * 重写类扫描包路径加载器,调用父类受保护的扫描方法 doScan
         * @param basePackages
         * @return
         */
        @Override
        protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            return super.doScan(basePackages);
        }
    }
    

    在自定义的扫描器中, 配置的扫描路基和注解
    MyClassPathBeanDefinitionScanner类继承了spring提供的ClassPathBeanDefinitionScanner类, 顾名思义, 这个类就是用来扫描类, 将类转化为beanDefinition对象的
    让我们进入MyImportBeanDefinitionRegistrar类的doScan方法进行源码追踪

    	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    		Assert.notEmpty(basePackages, "At least one base package must be specified");
    		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    		for (String basePackage : basePackages) {
    		    // 进入findCandidateComponents方法
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
    				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    				candidate.setScope(scopeMetadata.getScopeName());
    				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    				if (candidate instanceof AbstractBeanDefinition) {
    					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				}
    				if (candidate instanceof AnnotatedBeanDefinition) {
    					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    				}
    				if (checkCandidate(beanName, candidate)) {
    					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    					definitionHolder =
    							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    					beanDefinitions.add(definitionHolder);
    					registerBeanDefinition(definitionHolder, this.registry);
    				}
    			}
    		}
    		return beanDefinitions;
    	}
    

    在这里插入图片描述
    ScannedGenericBeanDefinition对象是BeanDefinition接口的子类, 里面包含大量构建bean的属性
    在这里插入图片描述

      private volatile Object beanClass;//bean的类型
        private String scope;//bean的作用范围
        private boolean abstractFlag;//是否是抽象类
        private boolean lazyInit;//是否延迟加载
        private int autowireMode; //自动注入模式
        private int dependencyCheck;//依赖检查,spring 3.0后弃用
        private String[] dependsOn; //表示这个bean,依赖于其它beans先实例化
        private boolean autowireCandidate;//设为false,则容器在自动装配时,将不考虑该bean(即这个bean不会作为其它bean自动装配的候选者),但是这个bean还可以自动装配其它bean
        private boolean primary;//自动装配出现多个bean时,将它作为首选者
        private final Map<String, AutowireCandidateQualifier> qualifiers;//用于记录Qualifier
        private boolean nonPublicAccessAllowed;//允许访问非公开的构造器和方法
        private boolean lenientConstructorResolution;//是否以宽松的模式解析构造函数,默认为true
        private String factoryBeanName;//指定工厂类和工厂方法
        private String factoryMethodName;
        private ConstructorArgumentValues constructorArgumentValues;//记录构造函数注入属性
        private MutablePropertyValues propertyValues;//普通属性集合
        private MethodOverrides methodOverrides; //方法重写的持有者
        private String initMethodName; //初始化方法
        private String destroyMethodName; //销毁方法
        private boolean enforceInitMethod; //是否执行初始化方法
        private boolean enforceDestroyMethod;//是否执行销毁方法
        private boolean synthetic;//是否是用户定义的而不是应用程序本身定义的,创建AOP时为true
        private int role;//定义这个bean的使用,application:用户,infrastructure:完全内部使用,与用户无关;support:某些复杂配置的一部分
        private String description;//bean的描述
        private Resource resource;//这个bean定义的资源。
    

    beanDefinition创建方法

    在这里插入图片描述

    @Component注解类注入原理

    ClassPathBeanDefinitionScanner是springboot提供的, 它默认会扫描和启动类同级目录下的所有文件下的类, 如果类上标记了@Component注解(或者@Component是他们元注解, 比如@Service, @Controller等)就会被注入到容器中
    源码解析 :
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    至此, @Component标记的类全部注入完成, 只有就是对beanDefinition对象赋默认值

    mybatis 通过ImportBeanDefinitionRegistrar将所有的Mapper对象注入到容器中

    前提

    创建一个项目, pom.xml包含

            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
    

    首先查看mybatis的自动装配
    在这里插入图片描述
    在这里插入图片描述
    进入到MapperScannerConfigurer类中
    在这里插入图片描述
    可以看到, 该类实现了BeanDefinitionRegistryPostProcessor接口, 项目启动时会执行postProcessBeanDefinitionRegistry()方法
    在这里插入图片描述

    可以看出, 该方法的主要作用就是创建一个ClassPathMapperScanner扫描器, 用来扫描@Mapper注解
    可以推断, ClassPathMapperScanner应该是ClassPathBeanDefinitionScanner的子类
    在这里插入图片描述
    之后在类启动时, ClassPathMapperScanner扫描器就会将指定路径下的, 所有标记@Mapper注解的类注入到容器中

    这就是Mybatis对象注入的全部流程

    == 问题 : @Mapper注解都是标记在接口上, 那么接口什么时候生成的代理对象呢? ==

    展开全文
  • 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);
    					}
    				}
    
    展开全文
  • Spring容器中Bean通常不会需要访问容器中其他的Bean—采用依赖注入,让Spring把被依赖的Bean注入到依赖的Bean中即可。 ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用...
  • import org.spring...import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component public class DataSourceConfig {
  • SpringBoot动态注入及操作Bean

    千次阅读 2020-12-30 05:38:35
    GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master在Spring中我们通过getBean来获得对象,但这些对象都是事先定义好的,如果需要操作事先未定义的Bean就需要动态注入、修改...
  • @SpringBootApplication public class SpringbootFirstApplication { public static void main(String[] args) { SpringApplication.run(SpringbootFirstApplication.class, args); } @Bean public ...
  • SpringBootBean解析

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

    千次阅读 2022-03-16 14:21:00
    在使用spring框架中我们都知道,某个类如果使用了@Service、@Autowire 这种依赖注入的方式引用了其他对象,在另外一个类中,只有通过spring的IOC容重中获取这个类的实例时,那些被依赖的对象才能正确被初始化,否则...
  • springboot启动流程原理以及bean加载创建
  • DI(依赖注入):全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。 那么IOC和DI这两者又是什么关系呢? IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。 把本来在类...
  • springboot启动过程中,首先会收集需要加载的bean的定义,作为BeanDefinition对象,添加到BeanFactory中去。 由于BeanFactory中只有getBean之类获取bean对象的方法,所以将将BeanDefinition添加到BeanFactory中,是...
  • springBoot过滤器注入Bean的空指针问题

    千次阅读 2019-04-23 18:17:37
    在过滤器中的doFilterInternal写业务代码时,需要用到spring bean组件,发现在过滤器中无法初始化bean组件,均为NullpointException,经检查扫描包路径没问题。最终确定容器加载顺序引发的问题,在web.xml中各个元素...
  • Spring 注入多例 Bean

    千次阅读 2021-11-13 23:55:16
    如何在单例 bean注入多例 Bean ? 目录配置多例 Bean再来个单例 Bean错误示例方式一 使用 @Lookup方式二 使用 ObjectProvider@Lookup 的局限及 ObjectProvider 的强大使用 @Lookup 注入使用 ObjectProvider 注入...
  • SpringBoot将所有@Component注解的类都当做配置类进行处理,每个类都是先处理@Import再处理@Bean,@Import引入的配置类将递归处理。 4. 处理启动类上所有的@Import,@Import可以引入普通类、配置类、实现了...
  • 在项目中,我们可能需要手动获取spring中的bean对象,这时就需要通过 ApplicationContext 去操作一波了! 1、直接注入(Autowired) @Component public class User { @Autowired private ApplicationContext ...
  • springboot相同类名bean引发问题

    千次阅读 2018-02-18 23:14:38
    使用第三方jar包里的注解时,特别是这个注解是要把bean注入到spring的时候,写代码的时候IDE不会提升错误,但是运行时会出现bean不存在报错 原因: 1,要注解的两个类来之不同的依赖jar包,但是有相同的类名 2,第...
  • 使用Test方法验证时,启动时始终提示无法注入Bean. 解决办法: 1.首先检查包名,包路径是否一致,如图所示: 2.继承ApplicationTest类 这种方法较为简单,直接在测试类上继承对应的ApplicationTest类。这样的...
  • 解决Springboot项目中单元测试时注入bean失败的问题

    万次阅读 多人点赞 2019-01-23 11:44:56
    最近公司项目搭了一个springboot项目进行开发,在单元测试时,由于生成项目后可能哪个同事把项目生产的test文件目录删了,也不知道是项目生成时test目录没有生成,需要自己建立一个test目录进行测试。就是下图中的红...
  • 来自:blog.csdn.net/showchi/article/details/97005720 注意:调用者要被spring管理 目录 方式一 注解@PostConstruct 方式二 启动类ApplicationContext 方式三 手动注入ApplicationContext 方式一 注解@...
  • 简述bean的几种加载方式}}上面的代码,两个Bean,dog2创建的是Dog对象吗?DogFactoryBean通过...names){}通过FactoryBean的方式创建Bean,可以在Bean的初始化时做一些其它事情,比如设置参数,进行参数检查等。......
  • 我们知道,当我们使用springboot框架引入Dubbo的时候,只需要在启动类上加入EnableDubbo注解的时候就能够注入Dubbo相关配置,我们看下怎么实现。 如果要了解这篇文档的一些内容,需要先看下之前对Springboot配置的...
  • 22 springboot依赖注入三种方式

    千次阅读 2022-02-25 15:14:03
    spring依赖注入
  • springboot 启动报找不到注入bean

    千次阅读 2018-08-29 13:42:12
    springboot 启动报找不到注入bean 检查所有的注解 发现model类@Entity缺失  
  • Spring Boot 获取 bean 的 3 种方式,还有谁不会
  • Spring Boot 在启动是执行了自动配置:class --> beanDefinition --> bean。这篇文章主要想梳理下:class 是怎么变成 beanDefinition 的。上一篇博客提到过,执行 run 方法中 invokeBeanFactoryPostProcessors...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,503
精华内容 4,601
热门标签
关键字:

启动springboot注入bean检查

spring 订阅