Spring註解驅動——IOC
體系結構概述:
@Bean
之前時候,在xml配置檔案使用:
<bean id="person" class="com.atguigu.bean.Person" scope="prototype" > <property name="age" value="${}"></property> <property name="name" value="zhangsan"></property> </bean>
實體類:
public class Person { privateString name;private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } publicPerson(String name, Integer age) { super(); this.name = name; this.age = age; } public Person() { super(); // TODO Auto-generated constructor stub } public String toString() { return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]"; } }
測試:
public class MainTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Person bean = (Person) applicationContext.getBean("person"); System.out.println(bean); } }
註解方式:
寫一個配置類:需要@Configuration註解
//配置類==配置檔案 @Configuration //告訴Spring這是一個配置類 public class MainConfig { //給容器中註冊一個Bean;型別為返回值的型別,id預設是用方法名作為id,也可以指定id名為什麼 @Bean("person") public Person person01(){ return new Person("lisi", 20); } }
測試:
public class MainTest { @SuppressWarnings("resource") public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); String[] namesForType = applicationContext.getBeanNamesForType(Person.class); for (String name : namesForType) { System.out.println(name); } } }
@ComponentScan
之前在xml配置檔案裡配置:
<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>
現在配置在類上:
//配置類==配置檔案 @Configuration //告訴Spring這是一個配置類 @ComponentScan(value="com.atguigu") // value:指定要掃描的包 public class MainConfig { //給容器中註冊一個Bean;型別為返回值的型別,id預設是用方法名作為id @Bean("person") public Person person01(){ return new Person("lisi", 20); } }
@ComponentScan 的一般配置項:
@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) //@ComponentScan value:指定要掃描的包 //excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些元件 //includeFilters = Filter[] :指定掃描的時候只需要包含哪些元件
// 過濾規則: //FilterType.ANNOTATION:按照註解 //FilterType.ASSIGNABLE_TYPE:按照給定的型別; //FilterType.ASPECTJ:使用ASPECTJ表示式 //FilterType.REGEX:使用正則指定 //FilterType.CUSTOM:使用自定義規則
可以修改預設的過濾規則,寫一個類,實現FilterType
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); if(className.contains("er")){ return true; } return false; } }
@ComponentScan 可以在類上面寫多個,也可以通過一個@ComponentScans 註解來把多個@ComponentScan 註解配置放在裡面,兩個寫法都是一樣的可以生效
@ComponentScans( value = { @ComponentScan(value="com.atguigu",includeFilters = { @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class}) },useDefaultFilters = false) } )
Spring 的預設註冊元件都是單例的,可以用@Scope 註解修改bean 的作用域
雖然Spring 是單例的,但它用的是餓漢式單例,在Spring 啟動時候,就已經把物件註冊到了Spring 容器裡,可以用@Lazy 註解讓它變成懶載入,不過不推薦修改
//預設是單例項的 /** * ConfigurableBeanFactory#SCOPE_PROTOTYPE * @see ConfigurableBeanFactory#SCOPE_SINGLETON * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION sesssion * @return\ * @Scope:調整作用域 * prototype:多例項的:ioc容器啟動並不會去呼叫方法建立物件放在容器中。 * 每次獲取的時候才會呼叫方法建立物件; * singleton:單例項的(預設值):ioc容器啟動會呼叫方法建立物件放到ioc容器中。 * 以後每次獲取就是直接從容器(map.get())中拿, * request:同一次請求建立一個例項 * session:同一個session建立一個例項 * * 懶載入: * 單例項bean:預設在容器啟動的時候建立物件; * 懶載入:容器啟動不建立物件。第一次使用(獲取)Bean建立物件,並初始化; */ // @Scope("prototype") @Lazy @Bean("person") public Person person(){ System.out.println("給容器中新增Person...."); return new Person("張三", 25); }
@Conditional 按照條件給Spring 註冊bean,
/** * @Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean * * 如果系統是windows,給容器中註冊("bill") * 如果是linux系統,給容器中註冊("linus") */ @Bean("bill") public Person person01(){ return new Person("Bill Gates",62); } @Conditional(LinuxCondition.class) @Bean("linus") public Person person02(){ return new Person("linus", 48); }
獲取是否是Linux系統的類:
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; //判斷是否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(); String property = environment.getProperty("os.name"); //可以判斷容器中的bean註冊情況,也可以給容器中註冊bean boolean definition = registry.containsBeanDefinition("person"); if(property.contains("linux")){ return true; } return false; } }
獲取是否是Windows系統的類:
//判斷是否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; } }
測試:
@Test public void test03(){ 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); } Map<String, Person> persons = applicationContext.getBeansOfType(Person.class); System.out.println(persons); }
@Conditional 註解可以放在方法是,也可以放在類上
@Import
1、給容器匯入一個元件
要匯入的元件
public class Color { private Car car; public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Color [car=" + car + "]"; } }
Car 類:
public class Car { }
匯入:
@Import({Color.class}) //@Import匯入元件,id預設是元件的全類名 public class MainConfig2 {
2、也可以匯入多個:
新增兩個顏色的類:
public class Blue { }
public class Yellow { }
要寫一個類,實現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"}; } }
匯入多個:雖然MyImportSelector 看著 和匯入一個元件是一樣的,匯入了一個類而已,但是這個類裡添加了多個元件
@Import({Color.class,Red.class,MyImportSelector.class}) //@Import匯入元件,id預設是元件的全類名 public class MainConfig2 {
3、通過ImportBeanDefinitionRegistrar 介面手動匯入元件
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:當前類的註解資訊 * BeanDefinitionRegistry:BeanDefinition註冊類; * 把所有需要新增到容器中的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定義資訊;(Bean的型別,Bean。。。) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //註冊一個Bean,指定bean名 registry.registerBeanDefinition("rainBow", beanDefinition); } } }
新加的彩虹類:
public class RainBow { }
4、使用FactoryBean 註冊元件
建立Bean 的工廠:
//建立一個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; } }
用的時候:
@Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); }
測試:
@Test public void testImport(){ printBeans(applicationContext); Blue bean = applicationContext.getBean(Blue.class); System.out.println(bean); //工廠Bean獲取的是呼叫getObject建立的物件 Object bean2 = applicationContext.getBean("colorFactoryBean"); Object bean3 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean的型別:"+bean2.getClass()); System.out.println(bean2 == bean3); // 雖然匯入的是colorFactoryBean,但列印的還是color,如果非要獲取的是工廠bean名字,就在前面加一個& 就好了 Object bean4 = applicationContext.getBean("&colorFactoryBean"); System.out.println(bean4.getClass()); }
總結:
/** * 給容器中註冊元件; * 1)、包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)[自己寫的類] * 2)、@Bean[匯入的第三方包裡面的元件] * 3)、@Import[快速給容器中匯入一個元件] * 1)、@Import(要匯入到容器中的元件);容器中就會自動註冊這個元件,id預設是全類名 * 2)、ImportSelector:返回需要匯入的元件的全類名陣列; (比較重要,在SpringBoot 裡用的非常多) * 3)、ImportBeanDefinitionRegistrar:手動註冊bean到容器中 * 4)、使用Spring提供的 FactoryBean(工廠Bean); * 1)、預設獲取到的是工廠bean呼叫getObject建立的物件 * 2)、要獲取工廠Bean本身,我們需要給id前面加一個& * &colorFactoryBean */ @Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); }
生命週期
要註冊Bean 的類:
1、第一種方式需要的Bean
@Component public class Car { public Car(){ System.out.println("car constructor..."); } public void init(){ System.out.println("car ... init..."); } public void detory(){ System.out.println("car ... detory..."); } }
2、第二種方式的Bean
@Component public class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..."); } @Override public void destroy() throws Exception { // TODO Auto-generated method stub System.out.println("cat...destroy..."); } @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("cat...afterPropertiesSet..."); } }
3、第三種方式的
@Component public class Dog implements ApplicationContextAware { //@Autowired private ApplicationContext applicationContext; // 實現上面類的介面,這樣匯入後,以後用的時候就可以拿到IOC容器 public Dog(){ System.out.println("dog constructor..."); } //物件建立並賦值之後呼叫 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除物件之前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub this.applicationContext = applicationContext; } }
4、使用Bean 的後置處理器
/** * 後置處理器:初始化前後進行處理工作 * 將後置處理器加入到容器中*/ @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean); return bean; } }
註冊Bean
/** * bean的生命週期: * bean建立---初始化----銷燬的過程 * 容器管理bean的生命週期; * 我們可以自定義初始化和銷燬方法;容器在bean進行到當前生命週期的時候來呼叫我們自定義的初始化和銷燬方法 * * 構造(物件建立) * 單例項:在容器啟動的時候建立物件 * 多例項:在每次獲取的時候建立物件\ * * BeanPostProcessor.postProcessBeforeInitialization * 初始化: * 物件建立完成,並賦值好,呼叫初始化方法。。。 * BeanPostProcessor.postProcessAfterInitialization * 銷燬: * 單例項:容器關閉的時候 * 多例項:容器不會管理這個bean;容器不會呼叫銷燬方法; * * * 遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization, * 一但返回null,跳出for迴圈,不會執行後面的BeanPostProcessor.postProcessorsBeforeInitialization * * BeanPostProcessor原理 * populateBean(beanName, mbd, instanceWrapper);給bean進行屬性賦值 * initializeBean * { * applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); * invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化 * applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); *} * * * 建立Bean的4種方式 * 1)、指定初始化和銷燬方法; * 通過@Bean指定init-method和destroy-method;分別指定初始化 或 銷燬時候 呼叫的方法 * 2)、通過讓Bean實現InitializingBean(定義初始化邏輯), * DisposableBean(定義銷燬邏輯);
* 實現這兩個介面,然後重寫裡面的兩個方法 * 3)、可以使用JSR250; * @PostConstruct:在bean建立完成並且屬性賦值完成;來執行初始化方法,定義在方法上 * @PreDestroy:在容器銷燬bean之前通知我們進行清理工作,也在方法上定義 * 4)、BeanPostProcessor【interface】:bean的後置處理器; * 在bean初始化前後進行一些處理工作; * postProcessBeforeInitialization:在初始化之前工作 * postProcessAfterInitialization:在初始化之後工作 * * Spring底層對 BeanPostProcessor 的使用; * bean賦值,注入其他元件,@Autowired,生命週期註解功能,@Async, 。。。BeanPostProcessor; * */ @ComponentScan("com.atguigu.bean") @Configuration public class MainConfigOfLifeCycle { //@Scope("prototype") @Bean(initMethod="init",destroyMethod="detory") public Car car(){ return new Car(); } }
測試:
public class IOCTest_LifeCycle { @Test public void test01(){ //1、建立ioc容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器建立完成..."); //applicationContext.getBean("car"); //關閉容器 applicationContext.close(); } }
屬性賦值
@Value
public class Person { //使用@Value賦值; //1、基本數值 //2、可以寫SpEL; #{} //3、可以寫${};取出配置檔案【properties】中的值(在執行環境變數裡面的值) @Value("張三") private String name; @Value("#{20-2}") // 18 private Integer age; @Value("${person.nickName}") // 匯入的是配置檔案的值 private String nickName;
person.nickName=\u5C0F\u674E\u56DB // 小張三
之前在xml 檔案要配置的:
<context:property-placeholder location="classpath:person.properties"/>
現在可以在類上使用@PropertySource,如果要加入多個配置檔案,可以點進去看原始碼,比較簡單,可以放陣列型別
//使用@PropertySource讀取外部配置檔案中的k/v儲存到執行的環境變數中;載入完外部的配置檔案以後使用${}取出配置檔案的值 @PropertySource(value={"classpath:/person.properties"}) @Configuration public class MainConfigOfPropertyValues { @Bean public Person person(){ return new Person(); } }
自動裝配
第一種:我們開發中對dao、service、controller 都要加上三個註解,然後互相之間呼叫時候使用@Autowired把我們自定義的元件給自動裝配進來,它是按照型別來注入的,預設的Bean是類的首字母小寫,
如果找到了多個Bean,再按照屬性名查詢,如果要必須指定注入哪個,就用@Qualifier("指定的bean的名字"),@Autowired 可以指定是否一定要找spring 裡的bean,加上required 屬性就行,
還有一個註解@Primary首選去找到哪個bean,而@Qualifier 是必須要用哪個bean
@Autowired 可以在 構造器,引數,方法,屬性,都可以使用
第二種:還可以使用@Resource也可以完成自動裝配,不同的是@Resource 是java裡的註解,@Autowired 是spring裡的註解,@Resource 預設是按照屬性名裝配的,
@Resource 不能和@Autowired 一樣搭配著其他兩個註解一塊使用
@Inject也可以自動裝配,也是java的註解,但是需要匯入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
/** * 自動裝配; * 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; * */ @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; } /** * @Bean標註的方法建立物件的時候,方法引數的值從容器中獲取 * @param 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; //構造器要用的元件,都是從容器中獲取 public Boss(Car car){ this.car = car; System.out.println("Boss...有參構造器"); } public Car getCar() { return car; } //@Autowired //標註在方法,Spring容器建立當前物件,就會呼叫方法,完成賦值; //方法使用的引數,自定義型別的值從ioc容器中獲取 public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Boss [car=" + car + "]"; } }
Aware 注入spring底層元件測試
@Component public class Red 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); } }
@Profile 可以切換專案的當前環境,如果不用@Profile 指定,預設不管哪個環境都可以註冊的,@Profile 也可以寫在類上
/** * Profile: * Spring為我們提供的可以根據當前環境,動態的啟用和切換一系列元件的功能; * * 開發環境、測試環境、生產環境; * 資料來源:(/A)(/B)(/C); * * * @Profile:指定元件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個元件 * * 1)、加了環境標識的bean,只有這個環境被啟用的時候才能註冊到容器中。預設是default環境 * 2)、寫在配置類上,只有是指定的環境的時候,整個配置類裡面的所有配置才能開始生效 * 3)、沒有標註環境標識的bean在,任何環境下都是載入的; */ @PropertySource("classpath:/dbconfig.properties") @Configuration public class MainConfigOfProfile implements EmbeddedValueResolverAware{ @Value("${db.user}") private String user;
private StringValueResolver valueResolver; // 值解析器 private String driverClass; @Bean public Yellow yellow(){ return new Yellow(); } @Profile("test") @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}"); } }
配置檔案 dbconfig.properties
db.user=root db.password=123456 db.driverClass=com.mysql.jdbc.Driver
測試:
public class IOCTest_Profile { //1、使用命令列動態引數: 在虛擬機器引數位置載入 -Dspring.profiles.active=test //2、程式碼的方式啟用某種環境; @Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //1、建立一個applicationContext //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); } Yellow bean = applicationContext.getBean(Yellow.class); System.out.println(bean); applicationContext.close(); } }