欢迎大家关注我的公众号,添加我为好友!
其实对于SpringIOC这个名字,我们已经很熟悉了。如果有不清楚的可以去访问这位大佬的文章:传送门
我想分享和记录的是我在学习SpringIOC容器中学会的一些方法。Spring注解驱动---因为现在都在提倡使用注解开发,之前基于xml的配置比较复杂和繁琐,因此在现在的开发中为了简化配置文件的书写,慢慢使用注解替换xml。
1.组件注册------@Configuration
使用“@Configuration”告诉Spring这是一个配置类,相当于spring配置文件中的“<beans>”用来初始化容器。
@Configuration
public class Config {
}
2.组件注解------@Bean
使用“@Bean”是给容器注册一个“bean”相当于xml配置文件中的“<bean>”,类型为返回值类型,id是默认方法名作为Id。
首先声明一个要注册的“bean”对象。
public class Book {
private String title;
private Double price;
public Book() {
}
public Book(String title, Double price) {
this.title = title;
this.price = price;
}
}
然后注册到spring 容器中去(如果想指定ID的话,可以写为 @Bean(“指定你想要的ID”))。
@Configuration
public class Config {
@Bean
public Book book(){
return new Book("Spring Boot", 52.00);
}
}
写个方法测试一下。
@org.junit.Test
public void testBean() {
// 传递配置文件获取application上下文信息
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
// 通过类获取
Book bean = annotationConfigApplicationContext.getBean(Book.class);
System.out.println(bean.getClass());
// 通过Id获取
Object book = annotationConfigApplicationContext.getBean("book");
System.out.println(book.getClass());
}
测试结果:
class com.hry.spring.annotation.bean.Book
class com.hry.spring.annotation.bean.Book
3.组件注解------@ComponentScan
使用“@ComponentScan”注解就是告诉Spring那个包里面的spring注解会被Spring自动扫描并装入bean容器。
@ComponentScan("com.xxx.bean") // 表示扫描指定包名路径
除了指定扫描的包之外,还可以指定排除扫描的包,使用如下:
@ComponentScan(value = "要扫描的包", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})})
还可以指定扫描的时候只包含那些组件,指定的时候需要添加一个参数把默认的规则禁用 “useDefaultFilters = false”。
@ComponentScan(value = "要扫描的包", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}, useDefaultFilters = false)
FilterType包含五个枚举类:
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE, // 按照给定的类型 (classes={UserService.class})
ASPECTJ, // 不太常用---使用ASPECTJ表达式
REGEX, // 使用正则
CUSTOM; // 使用自定义规则 (下个例子介绍使用)
private FilterType() {
}
}
使用自定义规则需要实现TypeFilter接口并实现方法。
public class MyFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源/类路径
Resource resource = metadataReader.getResource();
return false;
}
}
使用:
@ComponentScans(value = {
@ComponentScan(value = "要扫描的包", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyFilter.class})}, useDefaultFilters = false)
})
4.组件注解------@ComponentScans
使用“@ComponentScans”注解就是在“value”值里面配置“@ComponentScan”注解的规则
@ComponentScans(value = {
@ComponentScan(value = "要扫描的包", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})}, useDefaultFilters = false)
})
5.组件注解------@Scope
“@scope”默认是单例模式(singleton)IOC 容器启动会调用方法创建对象放到IOC容器中,以后每次获取直接从容器中拿取。
如果需要设置的话@scope("prototype") IOC容器启动 并不会 调用方法创建对象放在容器中,而是每次获取的时候才会调用方法创建对象;每次都会创建一个新的对象。
@Configuration
public class Config {
@Bean
@Lazy
public Book book() {
return new Book("Spring Boot", 52.00);
}
}
6.组件注解------@Lazy
“@Lazy”注解 只适用于单实例容器,因为单实例bean默认在容器启动的时候创建对象,所以使用懒加载可以在容器启动的时候不创建对象,第一次使用(获取)bean创建对象,并初始化。
7.组件注解------@conditional
通过“@Conditional”注解可以根据代码中设置的条件装载不同的bean,使用需要实现“Condition”接口。下面这个例子就是判断当前系统属于什么系统,然后执行相应的操作。
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取IOC使用的beanfactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
// 获取到类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
// 获取到bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Linux")) {
return true;
}
return false;
}
}
@Configuration
public class Config02 {
@Conditional({LinuxCondition.class})
@Bean("linus")
public Persion linus() {
return new Persion("Linux", 42);
}
@Conditional({WindowsCondition.class})
@Bean("windows")
public Persion windows() {
return new Persion("windows", 60);
}
}
测试代码:
@Test
public void conditionalTest() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config02.class);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Persion.class);
for (String string : beanNamesForType) {
System.out.println("beanNamesForType=============" +string);
}
Environment environment = applicationContext.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println("os.name========" + property);
Map<String, Persion> beansOfType = applicationContext.getBeansOfType(Persion.class);
System.out.println("beansOfType==========" + beansOfType);
}
测试结果:
beanNamesForType=============windows
os.name========Windows 10
beansOfType=========={windows=Persion{name='windows', age=60}}
8.组件注解------@Import
使用“@Import”快速给容器导入一个组件,该注解的返回值必须是一个class的全称,可以返回一个全类名的数组。需要实现“ImportSelector”接口并实现接口中的方法。在自定义的类中编写需要导入的组件(方法可以反回空数组,但是不能返回 null)
/**
* 自定义逻辑返回组件
*/
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.hry.spring.annotation.bean.Black", "com.hry.spring.annotation.bean.Red"};
}
}
public class Black {
}
public class Red {
}
@Configuration
@Import({MyImportSelector.class})
public class Config0 {
}
还可以使用手动注册bean到容器中。
public class MyImportBeanDefinition implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata 当前类的注解信息
* @param beanDefinitionRegistry 调用 beanDefinitionRegistry.containsBeanDefinition 自定义手工注册
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean red = beanDefinitionRegistry.containsBeanDefinition("com.hry.spring.annotation.bean.Black");
boolean black = beanDefinitionRegistry.containsBeanDefinition("com.hry.spring.annotation.bean.Red");
if (red && black) {
// 指定bean定义信息
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
// 注册一个bean 指定bean名
beanDefinitionRegistry.registerBeanDefinition("rainBow", rootBeanDefinition);
}
}
}
@Configuration
@Import({MyImportBeanDefinition.class})
public class Config {
}
9.组件注解------使用FactoryBean注册组件
创建一个spring定义的FactoryBean需要实现FactoryBean的接口,注意接口泛型,需要什么就填写什么。默认获取到的是工厂bean调用getObject创建的对象,要获取工厂Bean本身,我们需要给id前面加一个“&”也就是“&colorFactoryBean”(有点绕,仔细看例子。。。。。。)。
public class ColorBeanFactory implements FactoryBean<Color> {
/**
* 返回一个 color对象,这个对象会添加到容器中
* @return
*/
@Override
public Color getObject() {
System.out.println("bean init...........");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* 判断是否是单例,如果返回true 则代表这个bean是单实例,在容器中保存一份。 如果返回false 则代表是多实例,每次获取都会创建一个新的bean(调用的是 ColorBeanFactory 的 getObject() 方法)
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
@Configuration
public class Config02 {
@Bean("beanFactory")
public ColorBeanFactory beanFactory() {
return new ColorBeanFactory();
}
}
测试 :
public class Test {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
@org.junit.Test
public void selectImportTest() {
printBeans(applicationContext);
}
public void printBeans(ApplicationContext applicationContext) {
// 获取 Color
Object beanFactory = applicationContext.getBean("beanFactory");
System.out.println(beanFactory.getClass());
// 获取 ColorBeanFactory
Object beanFactory1 = applicationContext.getBean("&beanFactory");
System.out.println(beanFactory1.getClass());
}
}
测试结果:
bean init...........
class com.hry.spring.annotation.bean.Color
class com.hry.spring.annotation.bean.ColorBeanFactory
总结一下给容器注册组件的方法
1.包扫描 + 组件标注(注解)。
2.@Bean 导入第三方包里的组件。
3.@Import 快速给容器导入一个组件(ImportSelector:返回需要导入组件的全类名数组,ImportBeanDefinitionRegistrar:手动注册bean到容器)。
4.使用Spring提供的FactoryBean(工厂bean)。
10.Bean生命周期------指定初始化和销毁方法
Bean的生命周期为:bean创建------bean初始化------bean销毁
我们可以自定义初始化和销毁方法,通过“@Bean”指定“init-method”和“destroy-method”。
测试:
public class Car {
public Car() {
System.out.println("Constructor");
}
public void init() {
System.out.println("初始化。。。。。。");
}
public void destroy() {
System.out.println("销毁。。。。。。");
}
}
@Configuration
public class ConfigLifeCircle {
@Bean(destroyMethod = "destroy", initMethod = "init")
public Car car() {
return new Car();
}
}
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
annotationConfigApplicationContext.close();
}
}
结果:
Constructor
初始化。。。。。。
容器创建完成!!!!!!
销毁。。。。。。
Process finished with exit code 0
可以看到容器先是创建对,在进行初始化(对象创建完成,并赋值好,调用初始化方法), 销毁是在容器关闭的时候调用(单例模式下)。
我们再来看一个多实例的例子:
public class Car {
public Car() {
System.out.println("Constructor");
}
public void init() {
System.out.println("初始化。。。。。。");
}
public void destory() {
System.out.println("销毁。。。。。。");
}
}
@Configuration
public class ConfigLifeCircle {
@Scope("prototype")
@Bean(destroyMethod = "destroy", initMethod = "init")
public Car car() {
return new Car();
}
}
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
annotationConfigApplicationContext.close();
}
}
结果:
容器创建完成!!!!!!
可以发现多实例情况下,bean初始化不会创建对象,只有在获取的时候才会创建对象,下面在测试一下获取对象的方法和销毁的方法。
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
Object car = annotationConfigApplicationContext.getBean("car");
System.out.println(car.getClass());
annotationConfigApplicationContext.close();
}
}
结果:
容器创建完成!!!!!!
Constructor
初始化。。。。。。
class com.hry.spring.annotation.bean.Car
可以发现,确实是在获取的时候创建了对象,但是, 容器是不会销毁的。因为容器不会管理这个bean,所以容器不会调用销毁方法 。
11.Bean生命周期------InitializingBean和------DisposableBean
使用“InitializingBean”和“DisposableBean”需要实现这两者的接口并重写其中的方法。
@Component
public class Cat implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("destroy.......");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init......");
}
}
@Configuration
@ComponentScan("com.bean")
public class ConfigLifeCircle {
}
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
annotationConfigApplicationContext.close();
}
}
测试结果:
init......
容器创建完成!!!!!!
destroy.......
12.Bean生命周期------@PostConstruct和------@PreDestroy
使用“@PostConstruct”(在bean创建完成并且属性赋值完成,来执行初始化方法)和“@PreDestroy”(在容器销毁bean之前通知我们进行清理工作)可以直接注解在方法上。
@Component
public class Dog {
public Dog() {
System.out.println("狗 构造器 。。。。");
}
@PostConstruct// 在bean创建完成并且赋值属性完成 来执行初始化方法
public void inti() {
System.out.println("dog init ............");
}
@PreDestroy // 在容器销毁前通知我们进行清理工作
public void destroy() {
System.out.println("dog destroy........");
}
}
@Configuration
@ComponentScan("com.bean")
public class ConfigLifeCircle {
}
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
annotationConfigApplicationContext.close();
}
}
测试结果:
狗 构造器 。。。。
dog init ............
容器创建完成!!!!!!
dog destroy........
13.Bean的生命周期------BeanPostProcessor
“BeanPostProcessor”可以在bean初始化前后进行一些处理工作。因为“BeanPostProcessor”是一个接口,所以需要实现接口中的方法。
“postProcessBeforeInitialization”在初始化之前工作。
“postProcessAfterInitialization”在初始化之后工作。
@Component
public class Cat implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("destroy.......");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init......");
}
}
@Component
public class MyBeanPostProcesser implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization" + beanName + "------" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization" + beanName + "------" + bean);
return bean;
}
}
@Configuration
@ComponentScan("com.bean")
public class ConfigLifeCircle {
}
public class TestLifeCircle {
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigLifeCircle.class);
System.out.println("容器创建完成!!!!!!");
annotationConfigApplicationContext.close();
}
}
结果:
postProcessBeforeInitializationconfigLifeCircle------com.hry.spring.annotation.config.ConfigLifeCircle$$EnhancerBySpringCGLIB$$d521a073@45f45fa1
postProcessAfterInitializationconfigLifeCircle------com.hry.spring.annotation.config.ConfigLifeCircle$$EnhancerBySpringCGLIB$$d521a073@45f45fa1
postProcessBeforeInitializationcat------com.bean.Cat@52e677af
init......
postProcessAfterInitializationcat------com.bean.Cat@52e677af
容器创建完成!!!!!!
destroy.......
可以看到前两个是spring的默认组件。第三个是在构造器初始化前执行的方法,第五个是在构造器初始化之后执行的操作。
14.生命周期------BeanPostProcessor原理(我还没弄明白,等明白了在更新 包含 BeanPostProcessor在Spring底层中的应用)
* BeanPostProcessor原理
* populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
* initializeBean
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*}
* Spring底层对 BeanPostProcessor 的使用;
* bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
15.属性赋值------@Value
在Spring中可以使用“@Value”来为属性赋值。其中赋值的方法有三种:
1.基本数值。
2.可以写“SpEL”(SpringEL表达式) #{}
3.可以写“${}”取出配置文件【properties】中的值(在运行环境变量里面的值)需要加载配置文件。
public class Person {
@Value("Test")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
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;
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
}
}
@Configuration
//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value={"classpath:/person.properties"})
public class MainConfig {
@Bean
public Person person() {
return new Person();
}
}
public class TestLifeCircle {
@Test
public void value() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
Person person = (Person) annotationConfigApplicationContext.getBean("person");
System.out.println(person);
}
}
测试结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
Person [name=张三, age=18, nickName=李四]
16.自动装配------@Autowired
在开发中“@Autowired”是我们最常使用的,他可以帮我们自动注入外部需要的组件。它默认按照类型优先去容器中找对应的组件(applicationContext.getBean(XXX.class))找到就赋值。
如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找。当然我们也可以使用“@Qualifier("beanID")”指定需要装配的组件的id,而不是使用属性名。如果使用了“@Autowired”却没有配置bean就会运行报错,找不到bean,但是可以使用“@Autowired(required=false)”来告诉spring 当找不到的时候不需要报错,输出的结果则是 null。如果装配了多个相同的bean 我们想指定一个默认的bean 可以使用“@Primary”注解来标注,这个注解也可以配合“@Qualifier”使用。
@Autowired:可以标注在方法位置,@Bean+方法参数 参数从容器中获取 一般默认不写。
@Autowired:可以标注在构造器上,如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取。
@Autowired:可以标注在参数位置。
构造器,参数,方法,属性;都是从容器中获取参数组件的值。
17.自动装配------@Resource(JSR250)和@Inject(JSR330)
Spring还支持使用“@Resource(JSR250)”和“@Inject(JSR330)”[java规范的注解] 使用“@Resource”可以和“@Autowired”一样实现自动装配功能。默认是按照组件名称进行装配的,但是没有能支持“@Primary”功能没有支持“@Autowired(reqiured=false)”。使用“@Inject”需要导入javax.inject的包,和“@Autowired”的功能一样。没有required=false的功能。
@Autowired:Spring定义的; @Resource、@Inject都是java规范, 由AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能。
18.自动装配------Aware注入spring底层和原理
比如我们想自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)就可以自定义组件实现xxxAware接口,在实现时候,会调用接口规定的方法注入相关组件使用“Aware”可以把Spring底层一些组件注入到自定义的Bean中。xxxAware最终底层使用的功能是使用xxxProcessor (ApplicationContextAware-->ApplicationContextAwareProcessor)。
@Component
public class MyAware implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的IOC:" + applicationContext);
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String name) {
System.out.println("当前name:" + name);
}
@Override
public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
String resolveStringValue = stringValueResolver.resolveStringValue("您好 ${os.name}, 我今年 #{18 + 0} 岁了");
System.out.println(resolveStringValue);
}
}
public class TestLifeCircle {
@Test
public void value() {
}
}
测试结果:
当前name:myAware
您好 Windows 10, 我今年 18 岁了
传入的IOC:org.springframework.context.annotation.AnnotationConfigApplicationContext@69222c14, started on Thu Nov 29 22:00:56 CST 2018
19.自动装配------@Profile
在学习“@Profile”我感觉这个注解十分强大,它指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件。它可以加载在加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境。也可以写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效。需要注意的是:没有标注环境标识的bean在,任何环境下都是加载的。
总的来说Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能(以下例子摘自尚硅谷视频)。
@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) {
this.valueResolver = resolver;
// 这里使用了上面例子学习到的知识点解析字符串,需要注意
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
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();
}
}
欢迎大家关注我的公众号,添加我为好友!