1. 程式人生 > >spring原始碼分析(二):bean元件賦值

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("[email protected]");
    }

    //容器移除物件之前
    @PreDestroy
    public void detory() {
        System.out.println("[email protected]");
    }

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

參見