Spring-----IOC已更新

欢迎大家关注我的公众号,添加我为好友!

其实对于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();
	}

}

欢迎大家关注我的公众号,添加我为好友!

完结!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值