1.自動裝配
1.1什么是自動裝配?
Spring利用依賴注入(DI),完成對IOC容器中各個組件的依賴關系賦值;
1.2@Autowired/@Qualifier/@Primary
1.2.1@Autowired基本使用
-默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class) 找到就賦值;
@Service public class BookService { @Autowired //將BookDao組件裝配到當前組件中,找到就賦值 private BookDao bookDao; ① }
-如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找 applicationContext.getBean("bookDao")
比方說在配置類中再添加個BookDao組件代碼如下:
@ComponentScan({"com.athome.service","com.athome.dao"}) @Configuration public class MainAutowiredConfig { @Bean("bookDao2") ② public BookDao bookDao(){ BookDao bookDao = new BookDao(); bookDao.setTag("2"); return bookDao; } }
那么上面的兩段代碼都有相同類型BookDao組件,這種情況下按照屬性名稱找對應的組件,找到就賦值;
如上面代碼①處 ,屬性名是bookDao,則找該組件,如果①處 屬性名改為成 ②處的名字( bookDao2) ,這種情況則找id為bookDao2的組件。
@Autowired 詳解
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { /** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */ boolean required() default true; }
從@Autowired定義來看,該注解可修飾 構造器、方法、參數、屬性、注解
- 標注在方法上:根據方法的形參,從容器中查找
@Component public class Teacher { private Book book;
@Autowired
//標注在方法,Spring容器創建當前對象,就會調用方法,完成賦值;
//方法使用的參數,自定義類型的值從ioc容器中獲取 public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Teacher{" + "book=" + book + '}'; } }
@Bean("teacher2") public Teacher teacher(@Autowired Book book){ Teacher teacher = new Teacher(); teacher.setBook(book); return teacher; }
//@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配
上面淺紫色區域可以不寫
- 標注在構造器:默認調用無參構造器;
//默認加在ioc容器中的組件,容器啟動會調用無參構造器創建對象,再進行初始化賦值等操作 @Component public class Teacher { private Book book; //構造器要用的組件,都是從容器中獲得 @Autowired public Teacher (Book book){ this.book = book; } public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Teacher{" + "book=" + book + '}'; } }
//如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取
- 標注在參數中:根據參數組件值從容器中查找對應的組件
@Component public class Teacher { private Book book; //標注在形參上也是一樣,都是從容器中獲得public Teacher ( @Autowired Book book){ this.book = book; } @Autowired public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Teacher{" + "book=" + book + '}'; } }
1.2.2@Qualifier
@Qualifier指定需要裝配的組件的id,而不是使用屬性名
@Service public class BookService { @Qualifier("bookDao2") @Autowired private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
上面這段代碼,裝配組件id為 bookDao2 的組件,並不是 屬性名為bookDao 的組件
1.2.3@Primary
讓Spring進行自動裝配的時候,默認使用首選的bean;
也可以繼續使用@Qualifier指定需要裝配的bean的名字;
@ComponentScan({"com.athome.service","com.athome.dao"}) @Configuration public class MainAutowiredConfig { @Primary @Bean("bookDao2") public BookDao bookDao(){ BookDao bookDao = new BookDao(); bookDao.setTag("2"); return bookDao; } }
在沒有使用@Qualifier指定裝配的情況下,上面的代碼則會,首選裝配 bookDao2組件
--------------------------------------------------------------------
@Service public class BookService {
@Qualifier("bookDao") @Autowired private BookDao bookDao; }
@Primary和 @Qualifier("bookDao") 都在使用的話,則 使用@Qualifier("bookDao")指定的組件
1.2.4 @Autowired(required=false)
因為 required=false,如果spring找不到對應的組件的話會賦空值進去;
@Service public class BookService {
@Autowired(required = false)//如果容器中沒有BookDao組件的話, 則bookDao=null private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
1.3@Resource(JSR250)和@Inject(JSR330)
- @Resource:默認是按照組件名稱進行裝配的;
@Service public class BookService { // @Qualifier("bookDao2") // @Autowired(required = false) @Resource private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
@Resource和@Autowired一樣實現自動裝配功能;
默認是按照組件名稱進行裝配的;
沒有能支持@Primary功能,沒有支持@Autowired(reqiured=false)和 Qualifier
@Resource(name = "bookDao2"),則裝配bookDao2組件
- @Inject:需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能,加@Named注解指定bean 的Id;
@Service public class BookService { // @Qualifier("bookDao2") @Inject @Named("bookDao2") private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
@Inject 和 @Qualifier 、@Primary 、@Named 可組合使用
1.4Aware注入Spring底層組件
自定義組件想要使用Spring容器底層的組件(ApplicationContext、BeanFactory、 ......)
思路: 自定義組件實現xxxAware, 在創建對象的時候, 會調用接口規定的方法注入到相關組件:XXXAware
查看有哪些接口繼承了Aware接口:
參考代碼:
@Component public class Person implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub System.out.println("傳入的ioc:"+applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { // TODO Auto-generated method stub System.out.println("當前bean的名字:"+name); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { // TODO Auto-generated method stub String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}"); System.out.println("解析的字符串:"+resolveStringValue); } }
XXXAware---->功能使用了XXXProcessor來處理的,這就是后置處理器的作用;
ApplicaitonContextAware--->ApplicationContextProcessor后置處理器來處理的
1.5@Profile
@Profile:Spring為我們提供的可以根據當前環境,動態的激活和切換一系列組件的功能;
指定組件在哪個環境的情況下才能被注冊到容器中,不指定,任何環境下都能注冊這個組件
參考代碼:
/** * Profile:指定組件在哪個環境的情況下才能被注冊到容器中,不指定,任何環境下都能注冊這個組件 * 1)、加了環境標識的bean,只有這個環境被激活的時候才能注冊到容器中。默認是default環境 * 2)、寫在配置類上,只有是指定的環境的時候,整個配置類里面的所有配置才能開始生效 * 3)、沒有標注環境標識的bean在,任何環境下都是加載的; */ @Configuration public class ConfigProfile { @Profile("test") @Bean("profileTest") public void profileTest() { System.out.println("profileTest"); } @Profile("dev") //@Profile("default") 默認生效該Bean組件 @Bean("profileDev") public void profileDev() { System.out.println("profileDev"); } @Profile("prod") @Bean("profileProd") public void profileProd() { System.out.println("profileProd"); } }
測試代碼:
public class IOC_ProfileTest { //1、使用命令行動態參數: 在虛擬機參數位置加載 -Dspring.profiles.active=test //2、代碼的方式激活某種環境; @Test public void test(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //1、創建一個applicationContext //2、設置需要激活的環境 context.getEnvironment().setActiveProfiles("dev"); //3、注冊主配置類 context.register(ConfigProfile.class); //4、啟動刷新容器 context.refresh(); String[] names = context.getBeanDefinitionNames(); for (String s: names) { System.out.println(s); } } }
測試結果:
2.屬性賦值
使用@Value賦值:
1.基本數值
2.可以寫SpEL; #{}
3.可以寫${};取出配置文件【properties】中的值(在運行環境變量里面的值)
下面是一個Bean: Person類
public class Person {
@Value("高菲") //基本數值 private String name;
@Value("#{20-2}") //SpEL表達式 #{} private Integer age;
@Value("${person.nickName}") //取出配置文件中的數據 ${} private String nickName; 下面代碼是 setter/getter/toString方法 }
配置類:
@PropertySource:讀取外部配置文件中的 K / V 保存到運行環境變量中;加載完外部的配置文件以后使用${}取出配置文件的值。
@PropertySource(value = {"classpath:/person.properties"})//獲取外部配置文件 @Configuration public class MainConfigOfPropertyValue { @Bean public Person person(){ return new Person(); } }
測試類:
@Test public void test(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValue.class); Person person = (Person) applicationContext.getBean("person"); String[] names = applicationContext.getBeanDefinitionNames(); for (String s: names) { System.out.println("mainConfigOfPropertyValue配置類中有哪些bean -->"+s); } System.out.println(person); //可以通過運行環境來獲取配置文件中的數據 ConfigurableEnvironment environment = applicationContext.getEnvironment(); String property = environment.getProperty("person.nickName"); System.out.println("運行環境取配置文件中的值: "+property); }
運行結果:
3.小結
-
自動裝配:Spring利用依賴注入(DI),完成對IOC容器中各個組件的依賴關系賦值;
1)、@Autowired:自動注入: 1)、默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class);找到就賦值 2)、如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找 applicationContext.getBean("bookDao") 3)、@Qualifier("bookDao"):使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名 4)、自動裝配默認一定要將屬性賦值好,沒有就會報錯; 可以使用@Autowired(required=false); 5)、@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean; 也可以繼續使用@Qualifier指定需要裝配的bean的名字 BookService{ @Autowired BookDao bookDao; } 2)、Spring還支持使用@Resource(JSR250)和@Inject(JSR330)[java規范的注解] @Resource: 可以和@Autowired一樣實現自動裝配功能;默認是按照組件名稱進行裝配的; 沒有能支持@Primary功能沒有支持@Autowired(reqiured=false); @Inject: 需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能; @Autowired:Spring定義的; @Resource、@Inject都是java規范 AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能; 3)、 @Autowired:構造器,參數,方法,屬性;都是從容器中獲取參數組件的值 1)、[標注在方法位置]:@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配 2)、[標在構造器上]:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取 3)、放在參數位置: 4)、自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx); 自定義組件實現xxxAware;在創建對象的時候,會調用接口規定的方法注入相關組件;Aware; 把Spring底層一些組件注入到自定義的Bean中; xxxAware:功能使用xxxProcessor;ApplicationContextAware==》ApplicationContextAwareProcessor;
-
屬性賦值
@Value("基本數值")
@Value("SpEL表達式") - #{}
@Value("獲取配置文件中值") - ${}