一、自動裝配方式
Spring利用依賴注入(DI),完成對ioc容器中各個組件的依賴關係賦值。
自動裝配的核心實現原理:
調用AutowiredAnnotationBeanPostProcessor:後置處理器,來解析完成自動裝配功能。
- @Autowired:spring定義的註解
- @Resource(JSR250):基於Java規範的註解
- @Inject(JSR330):基於Java規範的註解
- 自定義組件實現xxxAware的方式
1、@Autowired:spring定義的註解
@Autowired自動注入規則
規則1:
默認優先按照類型去容器中去找對應的組件:annotationConfigApplicationContext.getBean(BookDao.class)找到就賦值
規則2:
如果找到多個相同類型的組件,再將屬性的名稱作爲組件的id去容器中查找。
規則3:
@Qualifier("bookDao2"):使用@Qualifier指定需要裝配的組件id而不是使用屬性名。
規則4:
自動裝配默認一定要將屬性賦值好,沒有就會報錯。可以使用 @Autowired(required = false)去設置,這樣會返回一個null值
規則5:
@Primary:使用這個註解讓spring進行自動裝配的時候,默認使用首選的Bean,也可以繼續使用@Qualifier指需要裝配的Bean的名字。
@Autowired自動注入標註的位置
@Autowired:構造器,參數,方法,屬性,都是從容器中獲取參數組件值。
- 標註在構造器上:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以從容器中獲取。
- 標註在方法上
- 放在參數位置
2、@Resource(JSR250):基於Java規範的註解
規則:
- 可以和@Autowired一樣實現自動裝配功能,默認是按照組件名稱進行裝配的
- 沒有能支持@Primary功能,沒有能支持@Autowired(required = false)功能
3、@Inject(JSR330):基於Java規範的註解
需要導入javax.inject包,和@Autowired功能一樣,但沒有required = false功能。
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
1,2,3知識點的實現實例代碼片段:
/***********************Service層***************************/
@Service
public class BookService {
@Qualifier("bookDao2")
@Autowired(required = false)
// @Resource(name = "bookDao2")
// @Inject
BookDao bookDao;
public void print() {
System.out.println(bookDao);
}
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
/***********************DAO層***************************/
//名字默認是類名首字母小寫
@Repository
public class BookDao {
private String lable = "1";
public String getLable() {
return lable;
}
public void setLable(String lable) {
this.lable = lable;
}
@Override
public String toString() {
return "BookDao{" +
"lable='" + lable + '\'' +
'}';
}
}
/***********************配置層***************************/
//配置類
@Configuration
@ComponentScan({"com.tan.service", "com.tan.dao", "com.tan.controller", "com.tan"})
public class MainConfigOfAutowired {
@Primary
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
/**********************測試啓動層***************************/
//測試啓動層
public class IOCAutowiredTest {
@Test
public void test01() {
//創建容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
BookService bookService = annotationConfigApplicationContext.getBean(BookService.class);
System.out.println(bookService);
}
}
4、自定義組件實現xxxAware的方式
自定義組件想要使用spring容器底層的一些組件(ApplicationContext,BeanFactory,....)
實現步驟:
步驟1:自定義組件實現xxxAware, 在創建對象的時候,會調用接口規定的方法注入相關組件 Aware
步驟2:把spring底層一些組件注入到自定義的bean中
步驟3:xxxAware:功能使用xxxProcessor來處理的
如:ApplicationContextAware---->ApplicationContextAwareProcessor
@Component public class Red implements ApplicationContextAware{ private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("傳入的oc:" + applicationContext); this.applicationContext = applicationContext; } }
二、利用@Profile註冊bean
@Profile:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件.
加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中, 默認是default環境. 寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效. 沒有標註環境標識的bean,在任何環境下都是加載的.
實例分析:在不同環境下加載不同環境的數據庫連接池
第一步:配置pom文件,將cp30數據連接池和mysql的數據驅動jar包引入進來
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
第二步:配置類的編寫
/**
* @Profile:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件
*
* 1)、加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中, 默認是default環境
* 2)、寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效
* 3)、沒有標註環境標識的bean,在任何環境下都是加載的
*/
//@Profile("test") //寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效
@PropertySource("classpath:/dbConfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver stringValueResolver;
private String driverClass;
//1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test
//2、代碼的方式激活某種環境
@Bean
public Yellow yellow(){
return new Yellow();
}
// @Profile("default")
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}") String password) throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}") String password) throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
@Profile("prod")
@Bean("prodDataSource ")
public DataSource dataSourceProd(@Value("${db.password}") String password) throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.stringValueResolver = resolver;
this.driverClass = stringValueResolver.resolveStringValue("${db.driverClass}");
}
}
第三步:啓動不同環境進行測試
啓動的方式有兩種:
1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test 2、代碼的方式激活某種環境
使用代碼激活的方式如下:
public class IOCProfileTest {
//1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test
//2、代碼的方式激活某種環境
@Test
public void test01() {
//創建容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
//1、創建一個 ApplicationContext
//2、設置需要激活的環境
annotationConfigApplicationContext.getEnvironment().setActiveProfiles("test","prod");
//3、註冊主配置類
annotationConfigApplicationContext.register(MainConfigOfProfile.class);
//4、啓動刷新容器
annotationConfigApplicationContext.refresh();
String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(DataSource.class);
for (String beanName: beanNamesForType) {
System.out.println(beanName);
}
}
}