spring源码分析(二):bean组件赋值

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

文章目录

常用注解

@Value和@PropertySource

介绍

@Value介绍:
– 1)直接写数据
– 2)SpEL #{ }表达式,
– 3)${}形式,用于获取【properties】中的值(可以通过环境变量获取)
@PropertySource:将配置文件中的变量加载到环境变量中

使用案例

配置类:


    @PropertySource(value={"classpath:/person.properties"})
    @Configuration
    public class MainConfigOfPropertyValues {

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

    }

实体类

    @Data
    public class Person {   
        @Value("张三")
        private String name;

        @Value("#{20-2}")
        private Integer age;

        @Value("${person.nickName}")
        private String nickName;
    }

测试类如下:

    public class IOCTest_PropertyValue {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        @Test
        public void test01(){
            printBeans(applicationContext);
            System.out.println("=============");

            Person person = (Person) applicationContext.getBean("person");
            System.out.println(person);

            ConfigurableEnvironment environment = applicationContext.getEnvironment();
            String property = environment.getProperty("person.nickName");
            System.out.println(property);
            applicationContext.close();
        }
    }

@AutoWired、@Qulifer 、@Primary

介绍

  • 1)、@Autowired:自动注入默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值,找不到就按照Id去找,
    @Autowired(required=false),该组件不存在也不会报错
  • 2)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
    也可以继续使用@Qualifier指定需要装配的bean的名字
  • 3)、@Qualifier(“bookDao”):使用@Qualifier指定需要装配的组件的id,而不是使用属性名

使用总结

-1) . 出现类型相同id 不同的组件,调用下面方法会报错(expected single matching bean but found 2: com.atguigu.dao.BookDao,bookDao2)

    applicationContext.getBean("bookDao") 

-2). 出现类型相同id相同的两个组件,在装配的时候后者会把前者的替换掉

-3)@Autowired(required=true),如果注入的组件找不到,会报以下错误

    UnsatisfiedDependencyException: Error creating bean with name 'bookService': Unsatisfied dependency expressed through field 'bookDao';

    Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

-4) @Resource、@Inject、@Autowired 使用对比

    @Resource(JSR250):
        可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
        没有能支持@Primary功能
        没有支持@Autowired(reqiured=false);
    @Inject@Inject(JSR330):
        需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
    @Autowired:Spring定义的;
        @Resource、@Inject都是java规范

方法、构造器位置自动装配

@AutoWired 可以在构造器和set方法上使用,都是依赖容器中的组件进行自动的注入。

案例

构造方法的注入,自动注入,可以不用写@Auowired

    @Component
    public class Boss {
        private Car car;

        //构造器要用的组件,都是从容器中获取
        public Boss(Car car){
            this.car = car;
            System.out.println("Boss...有参构造器");
        }
    }

其他方法的注入,必须加@Autowired

    @Component
    public class Car {

        private Blue blue;

        public Car() {
            System.out.println("car constructor...");
        }

        @Autowired
        public void setBlue111(Blue blue) {
            System.out.println("car -----> setBlue");
            this.blue = blue;
        }
     }

@Bean 形式的注入,可以不用写@Autowired

    @Configuration
    @ComponentScan({"com.atguigu.service","com.atguigu.dao","com.atguigu.controller"})
    @Import(value = {Car.class, Boss.class, Blue.class})
    public class MainConifgOfAutowired {
        /** * @Bean标注的方法创建对象的时候,方法参数的值从容器中获取 * @param car * @return */
        @Bean
        public Color color(Car car){
            Color color = new Color();
            color.setCar(car);
            return color;
        }

    }

xxAware设置属性的加载流程分析

简介:自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
把Spring底层一些组件注入到自定义的Bean中;
xxxAware:功能使用xxxProcessor;
ApplicationContextAware==》ApplicationContextAwareProcessor;

案例

我们以Aware 的注入spring容器底层组件为例,分析XXAware的执行流程。

    @Component
    public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

        private ApplicationContext applicationContext;

        private Blue blue;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      ==断点==      System.out.println("传入的ioc:" + applicationContext);
            this.applicationContext = applicationContext;
        }

        @Override
        public void setBeanName(String name) {
            System.out.println("当前bean的名字:" + name);
        }

        @Override
        public void setEmbeddedValueResolver(StringValueResolver resolver) {
            String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
            System.out.println("解析的字符串:" + resolveStringValue);
            System.out.println("bule " + blue.toString());
        }

        //对象创建并赋值之后调用
        @PostConstruct
        public void init() {
            System.out.println("Red....@PostConstruct...");
        }

        //容器移除对象之前
        @PreDestroy
        public void detory() {
            System.out.println("detory....@PreDestroy...");
        }

        @Autowired
        private void setBlue(Blue blue) {
         ==断点==   this.blue = blue;
        }

    }

测试方法与上边类似,使用时,只需要把上边这个Red类加入到容器中,在标有断点的地方打上断点。

由以上打断堆栈分析得出下面结论:

        AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
            this();
            register(annotatedClasses);
            refresh();
        }
            ⬇️
        //实例化剩下的不是懒加载的 单实例Bean
        finishBeanFactoryInitialization(beanFactory); 
            ⬇️
        beanFactory.preInstantiateSingletons();
            ⬇️
        // ? 构造器执行,创建一个Bean
        getBean(beanName);
            ⬇️
        doGetBean
            ⬇️
        getSingleton
            ⬇️
        doCreateBean{
            //将需要Autowired 的属性方法执行一遍
            populateBean(beanName, mbd, instanceWrapper);

            initializeBean(beanName, exposedObject, mbd){
                 // aware 方法执行,给实现了xxAware的方法设置值
                invokeAwareMethods(beanName, bean); 
                applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName){
                    beanProcessor.postProcessBeforeInitialization(result, beanName){
                        invokeAwareInterfaces(bean){
                            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
                        }
                    }
                }
                // 初始化方法,执行init
                invokeInitMethods(beanName, wrappedBean, mbd);
                applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
        }

参见


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码分析(二):bean组件赋值

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏