Spring註解開發
淺嘗Spring註解開發,基於Spring 4.3.12
包含自定義掃描元件、自定義匯入元件、手動註冊元件、自動注入方法和引數、使用Spring容器底層元件等
配置
@Configuration配置類
告訴Spring這是一個配置類,代替以前的xml檔案,配置類=配置檔案
@Configuration
public class MainConfig {
//給容器中註冊一個Bean;型別為返回值的型別,id預設是用方法名作為id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
註冊元件
給容器中註冊元件有以下方法:
包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)[自己寫的類]
@Bean[匯入的第三方包裡面的元件]
@Import[快速給容器中匯入一個元件]
- @Import(要匯入到容器中的元件);容器中就會自動註冊這個元件,id預設是全類名
- ImportSelector:返回需要匯入的元件的全類名陣列;
- ImportBeanDefinitionRegistrar:手動註冊bean到容器中
使用Spring提供的 FactoryBean(工廠Bean);
預設獲取到的是工廠bean呼叫getObject建立的物件
要獲取工廠Bean本身,我們需要給id前面加一個&
如:&colorFactoryBean
@Bean註冊
給容器中註冊一個Bean,型別為返回值的型別,id預設是用方法名作為id,也可以指定id
@Bean("person")//指定Bean id
public Person person01(){
return new Person("lisi", 20);
}
IoC容器
建立一個IoC容器AnnotationConfigApplicationContext,傳入配置類,獲取Bean
//建立IoC容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//獲取Bean物件
Person bean = applicationContext.getBean(Person.class);
//獲取所以Person型別Bean的名字
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println(name);
}
⭐@ComponentScan掃描元件
@Component(包括@Controller@Service@Repository和@Bean目的一樣)和@ComponentScan的區別
- @Component:將普通JavaBean例項化到spring容器中,Spring容器統一管理,用起來不用自己new了,相當於配置檔案中的<bean id="" class=""/>
- @ComponentScan:一般用在核心配置類,由你來定義哪些包需要被掃描。
- @Component標在類上,@Bean標在方法上,兩者使用在普通類或方法上時,都不起作用,只有放在配置類中才能註冊元件(@Bean可以在寫在配置類中,@Component由於本身標在類上,所以不能寫在類中),而@ComponentScan就是給了@Component一種註冊進容器的辦法,只要掃描到@Component標註的類就直接註冊進容器
-
自動掃描元件,可有多個@ComponentScan,或一個@ComponentScans
-
value:指定要掃描的包
所有指定的包下的類都要進入掃描,是否能夠通過,需要看下面使用了什麼規則,有排除、包含、指定型別、正則、和自定義規則,自定義規則通過反射獲取包中所有類,然後判斷是否能夠進入ioc容器中。
-
excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些元件
-
includeFilters = Filter[] :指定掃描的時候只需要包含哪些元件
- FilterType.ANNOTATION:按照註解
- FilterType.ASSIGNABLE_TYPE:按照給定的型別
- FilterType.ASPECTJ:使用ASPECTJ表示式
- FilterType.REGEX:使用正則指定
-
FilterType.CUSTOM:使用自定義規則,需要TypeFilter實現類
-
useDefaultFilters:不使用預設的 Filter進行掃描。在includeFilters中使用,取消預設掃描,指定掃描物件,可以在SpringMVC中使用
@ComponentScan(value="com.atguigu",includeFilters = {
//掃描指定註解
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
//掃描指定型別
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
//掃描自定義
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters = false)
FilterType.CUSTOM:使用自定義規則,需要實現TypeFilter介面
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:讀取到的當前正在掃描的類的資訊
* metadataReaderFactory:可以獲取到其他任何類資訊的
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//獲取當前類註解的資訊
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//獲取當前正在掃描的類的類資訊
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//獲取當前類資源(類的路徑)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
//根據自定義規則,只讓類名中包含er的類進入ioc容器。
if(className.contains("er")){
return true;
}
return false;
}
}
@Scope作用域
調整作用域,單例項,多例項
- prototype:多例項的:ioc容器啟動並不會去呼叫方法建立物件放在容器中。每次獲取的時候才會呼叫方法建立物件;
- singleton:單例項的(預設值):ioc容器啟動會呼叫方法建立物件放到ioc容器中。以後每次獲取就是直接從容器(map.get())中拿
- request:同一次請求建立一個例項。web環境中
- session:同一個session建立一個例項。web環境中
@Scope("singleton")
@Lazy
@Bean("person")
public Person person(){
System.out.println("給容器中新增Person....");
return new Person("張三", 25);
}
@Lazy懶載入
- 在單例項bean應用:預設在容器啟動的時候建立物件,配置懶載入後,容器啟動不建立物件。第一次使用(獲取)Bean建立物件,並初始化,仍是單例項。
⭐@Conditional條件註冊Bean
指定條件向容器中注入Bean
@Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件才將Bean註冊進容器,可以標在@Bean方法和@Configuration類上
- 新增了@Conditional({Condition}) 的Bean方法或配置Bean的類,只有在滿足Condition中的條件才能執行(裝配Bean)
- Condition:需要實現Condition介面的條件類,可以判斷容器中的bean註冊情況,也可以給容器中註冊bean
Condition條件實現類
建立兩個判斷條件,判斷系統是Windows還是Linux,自定義註冊不同的Bean,註解可以標在方法上,也可以標在類上
- 實現Condition介面
//判斷是否linux系統
public class LinuxCondition implements Condition {
/**
* ConditionContext:判斷條件能使用的上下文(環境)
* AnnotatedTypeMetadata:註釋資訊
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系統
//1、能獲取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、獲取類載入器
ClassLoader classLoader = context.getClassLoader();
//3、獲取當前環境資訊
Environment environment = context.getEnvironment();
//4、獲取到bean定義的註冊類
BeanDefinitionRegistry registry = context.getRegistry();
//5、獲取系統名
String property = environment.getProperty("os.name");
//這裡判斷容器中的bean註冊情況,也可以使用BeanDefinitionRegistry.registerBeanDefinition()給容器中註冊bean
boolean definition = registry.containsBeanDefinition("person");
//判斷系統名是否包含linux
if(property.contains("linux")){
return true;
}
return false;
}
}
//判斷是否windows系統
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
標在方法上
- 標在註冊Bean/元件的方法上
@Configuration
public class MainConfig2 {
/**
* @Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean
*
* 如果系統是windows,給容器中註冊Person型別("bill")
* 如果是linux系統,給容器中註冊Person型別("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01(){
return new Person("Bill Gates",62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
}
標在類上
//類中元件統一設定。滿足當前條件,這個類中配置的所有bean註冊才能生效;
@Conditional({WindowsCondition.class})
@Configuration
public class MainConfig2 {
//...
}
測試方法
-
使用,可配置VM引數:
-Dos.name=linux
測試public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); @Test public void test03(){ //獲取所有Person型別的Bean名字 String[] namesForType = applicationContext.getBeanNamesForType(Person.class); //獲取執行時環境 ConfigurableEnvironment environment = applicationContext.getEnvironment(); //動態獲取環境變數的值;Windows 10 String property = environment.getProperty("os.name"); System.out.println(property); for (String name : namesForType) { System.out.println(name); } //獲取所有Person型別Bean的物件,名字是否是lunus或bill Map<String, Person> persons = applicationContext.getBeansOfType(Person.class); System.out.println(persons); } }
⭐@Import註冊
@Import的三種方法都是寫在@Import註解中,都是向容器中匯入元件
- @Import(要匯入到容器中的元件):容器中就會自動註冊這個元件,id預設是全類名
- ImportSelector:返回需要匯入的元件的全類名陣列
- ImportBeanDefinitionRegistrar:手動註冊bean到容器中
@Import
-
@Import(要匯入到容器中的元件):容器中就會自動註冊這個元件,id預設是全類名com.xxx.bean.Color
@Configuration @Import({Color.class,Red.class}) //@Import匯入元件,id預設是元件的全類名 public class MainConfig2 { /... }
-
測試
public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); //輸出:除了Spring自己的Bean還有Import的Color、Red @Test public void testImport(){ printBeans(applicationContext); } //輸出容器中所有的Bean名 private void printBeans(AnnotationConfigApplicationContext applicationContext){ String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } } }
⭐ImportSelector註冊
-
介面,可以選擇註冊指定的類,返回需要匯入的元件的全類名陣列;
//自定義邏輯返回需要匯入的元件 public class MyImportSelector implements ImportSelector { //返回值,就是到匯入到容器中的元件全類名 //AnnotationMetadata:當前標註@Import註解的類的所有註解資訊 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // TODO Auto-generated method stub //importingClassMetadata //方法不要返回null值,返回的值就是要註冊的元件 return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"}; } }
-
配置
@Configuration //@Import匯入元件,MyImportSelector是自定義選擇的Bean @Import({Color.class,Red.class,MyImportSelector.class}) public class MainConfig2 { //... }
-
測試
public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); //輸出:除了Spring自己的Bean還有MyImportSelector選中的Bean @Test public void testImport(){ printBeans(applicationContext); Blue bean = applicationContext.getBean(Blue.class); System.out.println(bean); } //輸出容器中所有的Bean名 private void printBeans(AnnotationConfigApplicationContext applicationContext){ String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } } }
⭐ImportBeanDefinitionRegistrar
自定義注入元件,在Spring註解原始碼中使用
-
實現介面,指定規則,手動注入新的bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:當前類的註解資訊 * BeanDefinitionRegistry內有BeanDefinition註冊類,所有Bean都在這裡註冊; * 把所有需要新增到容器中的bean * 呼叫方法BeanDefinitionRegistry.registerBeanDefinition手工註冊進來 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //判斷是否有紅色,藍色 boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red"); boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue"); //如果存在 if(definition && definition2){ //指定Bean定義資訊BeanDefinition型別;(Bean的型別,Bean作用域等...) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //註冊一個新Bean,指定bean名 registry.registerBeanDefinition("rainBow", beanDefinition); } } }
-
配置
@Configuration //MyImportBeanDefinitionRegistrar是手動註冊到Bean容器中,可以指定規則 @Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class}) //@Import匯入元件,id預設是元件的全類名 public class MainConfig2 { //... }
-
測試
public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); //輸出:除了Spring自己的Bean還有手動定製規則新匯入的rainBow @Test public void testImport(){ printBeans(applicationContext); Blue bean = applicationContext.getBean(Blue.class); System.out.println(bean); } //輸出容器中所有的Bean名 private void printBeans(AnnotationConfigApplicationContext applicationContext){ String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } } }
⭐FactoryBean註冊
多用於第三方元件
介面,給容器中注入元件,使用Spring提供的 FactoryBean(工廠Bean)建立的Bean
-
預設獲取到的是工廠bean呼叫getObject建立的物件,而不是工廠物件本身
-
要獲取工廠Bean本身,我們需要給id前面加一個"&"如:context.getBean("&xxx")
-
實現介面,建立工廠
//建立一個Spring定義的FactoryBean public class ColorFactoryBean implements FactoryBean<Color> { //返回一個Color物件,這個物件會新增到容器中 @Override public Color getObject() throws Exception { // TODO Auto-generated method stub System.out.println("ColorFactoryBean...getObject..."); return new Color(); } @Override public Class<?> getObjectType() { // TODO Auto-generated method stub return Color.class; } //是單例? //true:這個bean是單例項,在容器中儲存一份 //false:多例項,每次獲取都會建立一個新的bean; @Override public boolean isSingleton() { // TODO Auto-generated method stub return false; } }
-
配置
@Configuration public class MainConfig2 { /** * 給容器中註冊元件; * 4)、使用Spring提供的 FactoryBean(工廠Bean); * 1)、預設獲取到的是工廠bean呼叫getObject建立的物件 * 2)、要獲取工廠Bean本身,我們需要給id前面加一個& * &colorFactoryBean */ @Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); } }
-
測試
public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); //直接使用輸出的不是工廠本身,而是工廠內getObject建立的Bean @Test public void testImport(){ //工廠Bean獲取的是呼叫getObject建立的Color物件 Object bean2 = applicationContext.getBean("colorFactoryBean"); Object bean3 = applicationContext.getBean("colorFactoryBean"); //輸出:com.xxx.bean.Color System.out.println("bean的型別:"+bean2.getClass()); System.out.println(bean2 == bean3); //輸出:com.xxx.bean.ColorFactoryBean Object bean4 = applicationContext.getBean("&colorFactoryBean"); System.out.println(bean4.getClass()); } //輸出容器中所有的Bean名 private void printBeans(AnnotationConfigApplicationContext applicationContext){ String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } } }
屬性賦值
@Value賦值
基本數值
public class Person {
//使用@Value賦值;
//1、基本數值
@Value("張三")
private String name;
}
SpEL表示式 #{}
public class Person {
//使用@Value賦值;
//1、基本數值
//2、可以寫SpEL; #{}
@Value("張三")
private String name;
//計算後值為18
@Value("#{20-2}")
private Integer age;
}
@PropertySource配置檔案取值
讀取properties配置檔案的值,例如讀取資料庫連線資訊
- 讀取檔案
- 取值
讀取配置檔案
使用@PropertySource讀取外部配置檔案
//使用@PropertySource讀取外部配置檔案中的k/v儲存到執行的環境變數中;載入完外部的配置檔案以後使用${}取出配置檔案的值
@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
@Bean
public Person person(){
return new Person();
}
}
配置檔案person.properties
person.nickName=法外狂徒
配置檔案取值${}
取出配置檔案properties中的值
public class Person {
//使用@Value賦值;
//1、基本數值
//2、可以寫SpEL; #{}
//3、可以寫${};取出配置檔案【properties】中的值(在執行環境變數裡面的值)
@Value("張三")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
}
執行時環境變數取值
執行時properties配置檔案載入進環境變數,可以直接取出
public class IOCTest_PropertyValue {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
@Test
public void test01(){
//直接從applicationContext容器中獲取執行時環境變數ConfigurableEnvironment
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//取值
String property = environment.getProperty("person.nickName");
System.out.println(property);
applicationContext.close();
}
}
自動裝配
AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能
幾種自動裝配:
- @Autowired:自動注入
- Spring還支援使用@Resource(JSR250)和@Inject(JSR330)[java規範的註解]
- @Autowired:構造器,引數,方法,屬性,都是從容器中獲取引數元件的值
- 自定義元件想要使用Spring容器底層的一些元件(ApplicationContext,BeanFactory,xxx)
@Autowired
自動注入:
- 預設優先按照型別去容器中找對應的元件,同applicationContext.getBean(BookDao.class),找到就賦值
- 如果找到多個相同型別的元件,再將屬性的名稱(@Bean的value或者方法名)作為元件的id去容器中查詢,同applicationContext.getBean("bookDao")
- 如果都相同就會報錯
@Qualifier
指定裝配:
- @Qualifier("bookDao"):使用@Qualifier指定需要裝配的元件的id,而不是使用屬性名自動裝配,預設一定要將屬性賦值好,沒有就會報錯;
- 如果沒有就不裝配,可以使用@Autowired(required=false)表示
@Primary
預設裝配:
- @Primary:讓Spring進行自動裝配的時候,預設使用首選的bean;
- 也可以繼續使用@Qualifier指定需要裝配的bean的名字
下面是兩個Bean的情況
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
@Primary//首選裝配
@Bean("bookDao2")
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
@Service
public class BookService {
@Qualifier("bookDao")//指定,大於首選
@Autowired(required=false)//可以不存在
private BookDao bookDao;
}
@Resource
-
可以和@Autowired一樣實現自動裝配功能,預設是按照元件名稱進行裝配的
-
沒有能支援@Primary和@Autowired(reqiured=false)的功能
-
@Autowired跟spring強耦合,如果換成了JFinal等其他框架,功能就會失效。而@Resource是JSR-250提供的,它是Java標準,絕大部分框架都支援
@Resource(name="bookDao2")
private BookDao bookDao;
@Inject
-
需要匯入javax.inject的包,和@Autowired的功能一樣。沒有@Autowired(reqiured=false)的功能
-
@Autowired:Spring定義的, @Resource、@Inject都是java規範,@Autowried不能脫離Spring
@Inject
private BookDao bookDao;
⭐@Autowired注入方法,引數
@Autowired:構造器,引數,方法,屬性都是從容器中獲取引數元件的值
使用[@Bean+方法引數]的方式在SpringBoot中使用很多,在使用各種配置時,只配置方法,方法中的引數直接從容器中獲取
- [標註在方法位置]:@Bean+方法引數,引數從容器中獲取,預設不寫@Autowired效果是一樣的,都能自動裝配
- [標在構造器上]:如果元件只有一個有參構造器,這個有參構造器的@Autowired可以省略,引數位置的元件還是可以自動從容器中獲取
- 放在引數位置
方法上
-
@Autowired直接標在方法上
@Autowired //標註在方法,Spring容器建立當前物件,就會呼叫方法,完成賦值; //方法使用的引數,自定義型別的值從ioc容器中獲取 public void setCar(Car car) { this.car = car; }
-
如果是@Bean標註的方法,引數位置不標@Autowired,引數也可以自動裝配,都是從容器中獲取
/** * @Bean標註的方法建立物件的時候,方法引數的值從容器中獲取 * @param car car也是從容器中獲取的值,前提是car已經注入容器 * @return */ @Bean public Color color(Car car){ Color color = new Color(); color.setCar(car); return color; }
構造器
-
標在構造器上
-
如果元件只有一個有參構造器,這個有參構造器的
@Autowired
可以省略,引數位置的元件還是可以自動從容器中獲取//預設加在ioc容器中的元件,容器啟動會呼叫無參構造器建立物件,再進行初始化賦值等操作 @Component public class Boss { private Car car; //構造器要用的元件,都是從容器中獲取 //@Autowired public Boss(Car car){ this.car = car; System.out.println("Boss...有參構造器"); } }
引數上
-
標在引數前
public void setCar(@Autowired Car car) { this.car = car; }
⭐Aware使用Spring底層元件
-
自定義元件想要使用Spring容器底層的一些元件(如:ApplicationContext,BeanFactory,xxx)只要自定義元件實現xxxAware
-
在建立物件的時候,會呼叫介面規定的方法注入相關元件,把Spring底層一些元件注入到自定義的Bean中
-
xxxAware:對應功能使用xxxProcessor
ApplicationContextAware==>ApplicationContextAwareProcessor
實現過程在BeanPostProcessor後置處理器中
使用不同的底層元件
@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
//使用IOC
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
System.out.println("傳入的ioc:"+applicationContext);
this.applicationContext = applicationContext;
}
//使用BeanName
@Override
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("當前bean的名字:"+name);
}
//使用EmbeddedValueResolve解析元件
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
System.out.println("解析的字串:"+resolveStringValue);
}
}
@Profile環境標識
@Profile:Spring為我們提供的可以根據當前環境,動態的啟用和切換一系列元件的功能;
環境:開發環境、測試環境、生產環境,分別對應:
資料來源:devDataSource、testDataSource、prodDataSource
@Profle:指定元件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個元件
- 標註
- 加了環境標識的bean,只有這個環境被啟用的時候才能註冊到容器中。預設是default環境
- 寫在配置類上,只有是指定的環境的時候,整個配置類裡面的所有配置才能開始生效
- 沒有標註環境標識的bean,在任何環境下都是載入的;
- 使用
- 如果對Bean標註了@Profile("default"),即使不啟用,也預設使用此環境。即使標註了,如果沒有對應的環境則都不啟用,除了"default"
- 在啟動時新增VM引數
-Dspring.profiles.active=test
,會使用此環境 - 不使用有參的AnnotationConfigApplicationContext建立ioc,使用無參構造器,在註冊配置類之前設定啟用環境。
- [SpringBoot]在類上使用註解@ActiveProfiles("test")啟用
建立多種資料來源環境匹配不同資料庫
//使用多種方法讀取properties配置檔案資訊
//第一種方法讀取配置檔案
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
//第二種方法讀取配置檔案
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
//普通的Bean,任何時候都可以載入進容器
@Bean
public Yellow yellow(){
return new Yellow();
}
//測試環境標識
@Profile("test")
//@Profile("default")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
//開發環境標識
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
dataSource.setDriverClass(driverClass);
return dataSource;
}
//生產環境標識
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
dataSource.setDriverClass(driverClass);
return dataSource;
}
//第三種方法讀取配置檔案,解析元件讀取配置檔案
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
測試
//啟用環境
public class IOCTest_Profile {
//1、使用命令列動態引數: 在虛擬機器引數位置載入 -Dspring.profiles.active=test
//2、程式碼的方式啟用某種環境;
@Test
public void test01(){
//1、建立一個applicationContext
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//2、設定需要啟用的環境
applicationContext.getEnvironment().setActiveProfiles("dev");
//3、註冊主配置類
applicationContext.register(MainConfigOfProfile.class);
//4、啟動重新整理容器
applicationContext.refresh();
//獲取被啟用註冊容器的資料來源名字
String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
for (String string : namesForType) {
System.out.println(string);
}
//普通Bean不受影響,一直可用
Yellow bean = applicationContext.getBean(Yellow.class);
System.out.println(bean);
applicationContext.close();
}
}
輸出
devDataSource
com.atguigu.bean.Yellow@1ab3a8c8