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

文章目录

常用注解

@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);
		}
	}

参见

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/qq_21434959/article/details/83552145
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞