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