講解bean的裝配
自動化裝配
註解配置
當使用@Configutation註解的類,則聲明該類爲一個配置類,與配置類有關的註解還有:
- @ComponentScan
- @ComponentScans
它們都是用來指定包掃描路徑的,使用方法如下:
@Configuration
@ComponentScan("wang.ismy.spring")
public class Config {}
裝配Bean
@Component // 將當前類對象放入容器
public class Bean {...}
@Component這個註解修飾的類,如果類路徑在容器的掃描路徑中(兄弟包以及子包),則該類會被容器創建對象
與之作用相同的註解還有:
- @Controller
- @Service
- @Repository
這些註解只是語義不同,作用都是一樣的。
使用Bean
要使用這個Bean,我們首先需要創建一個容器:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
然後,我們可以從中獲取Pojo這個類型的對象:
context.getBean(Pojo.class)
不僅可以使用Bean的類型獲取Bean,也可以使用Bean的名稱獲取:
context.getBean("pojo");
生命週期方法
有時候,我們需要Bean在創建後或者銷燬前做一些事情:我們可以使用以下兩個註解來實現:
//創建後執行
@PostConstruct
public void init(){ System.out.println("init"); }
//銷燬前執行
@PreDestroy
public void destroy(){ System.out.println("destroy"); }
需要注意的是,這兩個註解都不是Spring提供的,它是JAVA EE的標準,在使用的時候需要添加相關依賴
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
自動注入
Spring提供了一個最核心的功能就是依賴注入,也就說,Spring幫我們處理了各個對象之間的依賴關係,當一個對象創建時,Spring會找到這個對象所需要的依賴進行注入,我們只需要在要進行依賴注入的地方做一個標記即可,這個標記就是@Autowired
@Component
public class Bean {
private Bean1 bean1;
@Autowired
public Bean(Bean1 bean1) {
this.bean1 = bean1;
}
public void say(){
System.out.println("hi");
bean1.run();
}
}
這個註解不僅能加在構造函數上,也能放在成員變量、setter方法。
不過如果Bean只有一個構造函數,則可以省略這個註解。
JAVA代碼注入
由於某些類來源於外部,我們無法修改其源碼 所以可以使用java代碼的方式創建後注入
@Configuration
public class Config {
@Bean
public Bean1 bean1(){return new Bean1();}
}
處理自動裝配歧義性
在使用容器的時候,難免會遇到需要同類不同實例的對象,那麼這時候又該怎麼辦?
解決方法有兩個:
- 從生產方解決
- 從消費方解決
@Bean
@Primary // 標示首選bean
public Bean1 bean1(){
Bean1 bean1 = new Bean1();
bean1.setName("pro");
return bean1;
}
@Autowired
@Qualifier("bean1f") // 當有多個可選項時,將使用名爲bean1f的bean
public void setBean1(Bean1 bean1){}
Bean的作用域
- singleton:單例,即在整個容器中只會有一個同類型對象
- prototype:每次獲取都會創建實例
- session:每個會話一個bean(此處的會話指web容器的會話Session)
- request:每個請求一個bean(web容器的Request)
- global session:應用在Portlet環境.如果沒有Portlet環境那麼globalSession相當於session
條件裝配
可能我們的Bean並不是每次都需要創建,那麼則可以使用條件化裝配
@Bean
@Conditional(MyConditional.class)
public Bean1 bean1(){
Bean1 bean1 = new Bean1();
bean1.setName("pro");
return bean1;
}
只要實現Condition接口,就可以控制Bean的創建與否
public class MyConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
運行時值注入
在運行時,我們可能需要外部配置文件的一些值,我們可以先通過配置類注入配置文件
@Configuration
@ComponentScan(basePackages = "wang.ismy.spring")
@PropertySource("classpath:config.properties")
public class Config { }
在Bean中,可以使用@Value註解注入值
@Component
public class Bean {
@Value("${name}")
String name;
}
SPEL
Spring Expression Language(Spring表達式),是一種類似於腳本語言的東西,我們可以通過在@Value中寫一些字符串以此來達到語言級的能力:
@Value("#{T(System).currentTimeMillis()}") // 獲取當前時間
long time;
導入配置
使用@Import可導入其他配置類
@Configuration
@Import({DevConfig.class,ProConfig.class})
public class MasterConfig { }
配置環境
在開發與測試或者生產環境,很多配置都是不一樣的,如果需要頻繁地改,那會是很麻煩的,我們可以爲配置指定一個環境,在不同的場景啓用不同的環境
@Configuration
@Profile(("dev")) // 開發環境配置
public class DevConfig {}
@Configuration
@Profile("pro") // 生產環境配置
public class ProConfig {}
我們需要一個主配置,導入所有的配置:
@Configuration
@Import({DevConfig.class,ProConfig.class})
public class MasterConfig { }
在使用註解上下文時,我們使用這個主配置爲引導類
激活
方法有兩種,一是設置環境變量,二是手動編碼
System.setProperty("spring.profiles.active","dev"); // 通過設置環境變量
// 手動編碼設置
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(MasterConfig.class);
context.refresh();