spring:IOC注解

目录

 

1、@Configuration

2、@ComponentScan

3、@Scope

4、@Lazy

5、@Conditional

6、注册组件

6.1、@Import

6.2、@Bean

6.3、使用FactoryBean注册组件

7、生命周期

7.1、使用@Bean指定初始化和销毁方法

7.2、InitialLizingBean和DisposableBean

7.3、@PostConstruct和@PreDestroy(JSR250)

7.4、BeanPostProcessor后置处理器

7.4.1、BeanPostProcessor底层使用

8、属性赋值

8.1、@Value

8.2、@PropertySource

9、自动装配

9.1、@Autowired(spring自带的)

9.2、@Qualifier

9.3、@Primary

9.4、@Resource(JSR250)和@Inject(JSR330)

9.5、Aware注入Spring底层的组件

9.6、@Profile


1、@Configuration

  • @Configuration等同于beans.xml,可以在被@Configuration标注的类(配置类)中注册多个bean。
  1. proxyBeanMethods = true(默认),是Full模式。在这个模式下,配置类会被Cglib代理(也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。),在调用同一个配置文件中其它bean方法时,会直接从IOC容器中获取,所以不管拿多少次都是同一个对象。最好是当配置类中的组件存在依赖关系时才使用这个模式。
  2. proxyBeanMethods = false 是lite模式。这个模式下,配置类不会被代理,在调用同一个配置文件中其它bean方法时,会重新调用依赖的bean方法new一个新的对象。当组件之间不存在依赖关系时可以使用这种模式。减少生成代理类而带来的开销。
  3. 不带@Configuration的类(将@Configuration替换成@Component)也叫Lite配置类
  • 实例
@Configuration
public class SpringConfig {

    @Bean
    Person person(){
        System.out.println("person...");
        Person person = new Person();
        person.setCar(car());
        return person;
    }

    @Bean
    Car car(){
        System.out.println("car...");
        Car car = new Car();
        car.setName("宝马");
        return car;
    }
}
    @Test
    void test0(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Person person = context.getBean(Person.class);
        System.out.println(person);
    }

 

  • 结果1(上述代码不变)

person...
car...
Person(name=张三, car=Car(name=宝马))

  • 结果2(令@Configuration(proxyBeanMethods = false))

person...
car...
car...
Person(name=张三, car=Car(name=宝马))

第一种结果car...只出现一次是因为默认单例的bean会在容器创建时就创建对象(此时调用了一侧),然后在创建person对象时car对象(这时调用car()会直接从容器中获取,因为默认是开启了代理bean方法)会直接从IOC容器中获取,没有再调用car()方法。因此就只出现一次。第二种结果是因为bean在容器创建时需要创建一次(调用了一次car()方法),接着person创建时又需要调用一次car方法(第二次调用)(因为关闭了代理bean方法,而不是从容器中获取。)

2、@ComponentScan

  • 实例1
@Configuration
@ComponentScan(value = "com.wust",
includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
        },
useDefaultFilters = false)
public class SpringConfig {
    @Bean
    //@Scope("singleton")
    @Scope("prototype")
    Person person(){
        return new Person();
    }
}
/*
includeFilters:   
    FilterType.ANNOTATION:过滤注解类型,比如上面是过滤出@Controller注解,将其扫描到容器中
    FilterType.CUSTOM::自定义类型,自定义类实现TypeFilter进行过滤

excludeFilters: 和上面相反,对于某些满足过滤条件的类不进行扫描,即不注入到IOC容器中

useDefaultFilters = false
    useDefaultFilters :默认值为true,默认获得所有组件。和includeFilters配合使用时,也默认获得所有组件,和excludeFilters配合使用时,会排除满足过滤条件的组件
*/
  •  源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//省略
}
/*
@Repeatable(ComponentScans.class)
    @Repeatable:表明ComponentScan注解可在类上标注多次
    ComponentScans:也可以使用ComponentScans注解
*/
  • 实例2
@ComponentScan(value = "com.wust.service")
@ComponentScan(value = "com.wust.controller")
public class SpringConfig {
    @Bean
    //@Scope("singleton")
    @Scope("prototype")
    Person person(){
        return new Person();
    }
}
/*
上述会扫描service包和controller包
上述注解也可以使用@ComponentScans进行合并
@ComponentScans({@ComponentScan("com.wust.service"),@ComponentScan("com.wust.controller")})
*/

3、@Scope

    @Bean
    //@Scope("singleton")
    @Scope("prototype")
    Person person(){
        return new Person();
    }
    @Test
    void test1(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Person person1 = context.getBean("person", Person.class);
        Person person2 = context.getBean("person", Person.class);
        System.out.println(person1 == person2);
    }

 

  1.  prototype:多实例,在每次需要对象的时候,IOC容器会重新new一个对象进行返回。false
  2. singleton:单例,在IOC容器启动时便创建了对象(如果没有设置懒加载),每次返回同一个对象。true

4、@Lazy

  • 实例
    @Bean
    @Lazy
    Person person(){
        System.out.println("容器中添加Person----");
        return new Person();
    }

 void test1(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //Person person = context.getBean("person", Person.class);
        //使用了@Lazy,会在第一次获取bean时创建对象

    }
/*
单实例的bean,默认会在容器创建时创建对象
@Lazy使bean在第一次获取bean时创建对象

*/

 

5、@Conditional

  • 源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * All {@link Condition} classes that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();

}

通过源码 可以知道,使用@Conditional注解需要一个Condition类型的类,所以需要我们自定义一个Condition的实现类去写判断条件。并且@Conditional注解可以用在类上或者方法上,作用在方法上(如实例1),会在判断条件不满足时,bean将不会注入到IOC容器中;作用在类上,如果不满足条件,整个配置类都不会生效,即所有的组件都不会注入到IOC容器中。

  • 实例1
@Configuration
public class SpringConfig1 {
    @Conditional(WindowsCondition.class)
    @Bean("bill")
    public Person person1(){
        return new Person("Bill Gates","62");
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person2(){
        return new Person("Linus","42");
    }
}
  •  实例2
@Conditional(LinuxCondition.class)
@Configuration
public class SpringConfig1 {
    //@Conditional(WindowsCondition.class)
    @Bean("bill")
    public Person person1(){
        return new Person("Bill Gates","62");
    }

   // @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person2(){
        return new Person("Linus","42");
    }
}

 

6、注册组件

  • 给容器中导入组件有以下这些方法:
  1. 使用@ComponentScan(即包扫描)+标注注解(@Component,@Controller,@Service,@Repository)
  2. 使用@Bean注解
  3. 使用@Import

6.1、@Import

  • 使用@Import给容器导入组件有三种方式

1、直接使用@Import快速导入组件

  • 实例
@Import(User.class)
@Configuration
public class SpringConfig2 {

}

2、使用ImportSelector

  • 实例

public class MyImportSelector implements ImportSelector {
    /**
     *
     * @param importingClassMetadata:注解信息(包含各个类的注解信息)
     * @return 以全类名的方式返回,@Import注解配合这个方法将被返回的类将被注册到IOC容器中,
     * 注意不能返回null,否则会报空指针异常,但是可以返回空数组
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.wust.bean.Color"};
    }
}
@Import({User.class,MyImportSelector.class})
@Configuration
public class SpringConfig2 {

}

3、使用ImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata:注解信息
     * @param registry:使用它注册bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        System.out.println(importingClassMetadata.getAnnotationTypes());
        //导入具体的类
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Ball.class);
        //指定bean的名称,将其注入到IOC容器中
        registry.registerBeanDefinition("ball",rootBeanDefinition);
    }
}
@Import({User.class,MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
@Configuration
public class SpringConfig2 {

}

 

6.2、@Bean

  • @Bean可以将自定义的实体类注入到IOC容器中,具体相关的内容在下面的生命周期章节讲解。

6.3、使用FactoryBean注册组件

  • 实例
public class UserFactoryBean implements FactoryBean<User> {
    //设置返回的对象
    @Override
    public User getObject() throws Exception {
        return new User();
    }
    //设置返回对象的类型
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
    //设置是否单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}
@Configuration
public class SpringConfig2 {
    @Bean
    public UserFactoryBean userFactoryBean(){
        return new UserFactoryBean();
    }
}
  •  测试
    @Test
    void test4(){
        ApplicationContext context = getContext(SpringConfig2.class);
        Object bean = context.getBean("userFactoryBean");
        System.out.println(bean.getClass());
    }

测试的结果 :class com.wust.bean.User

通过测试的结果可以知道,虽然在javaConfig中注入的bean的类型是UserFactoryBean,但是最终测试从容器中通过bean的id获取到的对象却是User类型的。


7、生命周期

  • bean的生命周期:

      创建------>初始化------>销毁

  • 可以自定义初始化和销毁方法

7.1、使用@Bean指定初始化和销毁方法

  • 编写实体类
public class Car {
    public Car() {
        System.out.println("创建car--------------");
    }
    public void init(){
        System.out.println("初始化car--------------");
    }
    public void destroy(){
        System.out.println("销毁car--------------");
    }
}
  • 编写配置类
@Configuration
public class SpringConfig3 {
    //initMethod:指定初始化方法
    //destroyMethod:指定销毁方法
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Car car(){
        return new Car();
    }
}
  • 测试
    @Test
    void test5(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig3.class);
        System.out.println("容器创建完成--------------");

        Car car = (Car) context.getBean("car");

        context.close();
        System.out.println("关闭容器--------------");
    }
  • 结果

创建car--------------
初始化car--------------
容器创建完成--------------
销毁car--------------
关闭容器-------------- 

  • 结论
  1. 单例bean:在容器创建时创建
  2. 多实例bean:在第一次获取bean时创建bean
  3. bean的初始化是在创建好bean之后,容器创建完成之前
  4. bean的销毁是在关闭容器之前执行

7.2、InitialLizingBean和DisposableBean

  • 实体类
public class Dog implements InitializingBean, DisposableBean {
    public Dog() {
        System.out.println("Constructor...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet...");
    }
}
  •  配置类
@Configuration
public class SpringConfig3 {
    @Bean
    public Dog dog(){
         return new Dog();
    }
}

7.3、@PostConstruct和@PreDestroy(JSR250)

  • 实体类
public class Cat {
    public Cat() {
        System.out.println("Cat Constructor...");
    }
    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("Cat init...");
    }

    //容器销毁之前调用
    @PreDestroy
    public void destroy(){
        System.out.println("Cat destroy...");
    }
}
  • 配置类
    @Bean
    public Dog dog(){
         return new Dog();
    }

7.4、BeanPostProcessor后置处理器

  • BeanPostProcessor实现类
@Component //将其加入到IOC容器中
public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 各个bean初始化之前调用
     * @param bean
     * @param beanName
     * @return 可以直接返回参数中的bean,也可以对bean进行包装后返回
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeforeInitialization..." + beanName);
        return bean;
    }

    /**
     * 各个bean初始化之后调用
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("AfterInitialization..." + beanName);
        return bean;
    }
}
  •  测试
    @Test
    void test5(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig3.class);
        System.out.println("容器创建完成--------------");

        context.close();
        System.out.println("关闭容器--------------");
    }
  • 结果

BeforeInitialization...springConfig3
AfterInitialization...springConfig3
创建car--------------
BeforeInitialization...car
初始化car--------------
AfterInitialization...car
Constructor...
BeforeInitialization...dog
afterPropertiesSet...
AfterInitialization...dog
Cat Constructor...
BeforeInitialization...cat
Cat init...
AfterInitialization...cat
容器创建完成--------------
Cat destroy...
destroy...
销毁car--------------
关闭容器-------------- 

  • 结论

根据结果可知,后置处理器内两个方法调用的时机:

  1. postProcessBeforeInitialization:各个bean初始化之前
  2. postProcessAfterInitialization:各个bean初始化之后

7.4.1、BeanPostProcessor底层使用

  • spring底层大量使用 BeanPostProcessor,比如:

  1. ApplicationContextAwareProcessor:可以在自定义组件中,获取ApplicationContext容器
  2. InitDestroyAnnotationBeanPostProcessor:上述@PostConstruct、@PreDestroy注解功能的实现就是依赖于它
  3. AutowiredAnnotationBeanPostProcessor:@Autowired自动注入的底层实现依赖于它,在对象创建之后进行自动注入
  • 实例:以ApplicationContextAwareProcessor为例
@Component
public class Color implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
  • 原理

debug发现在设置好Color类中的applicationContex之前,调用了ApplicationContextAwareProcessor中的两个方法。

@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

 由源码可知,postProcessBeforeInitialization()方法会在bean初始化之前先判断该bean是否是xxxAware类型,如果不是直接返回bean;如果是,之后就一定会调用invokeAwareInterfaces()方法。在invokeAwareInterfaces()方法中,主要判断bean具体是哪个类型的xxxAware,接着调用满足对应类型的set方法。所以针对上面的实例,Color组件会在初始化之前设置好自己内部的字段:applicationContext,从而获取IOC容器进行使用。


8、属性赋值

8.1、@Value

  • 实例
@Component
@Data
public class User {
    /**@Value使用set方法进行赋值,等同于
     * <bean id="" class="">
     *    <property name="" value=""/>
     * </bean>
     * 1、基本数值
     * 2、SPEL表达式,#{2*5}
     * 3、从配置文件中取值或者获取环境参数中的值${os.name}
     */
    @Value("张三")
    private String name;
    @Value("#{20+4}")
    private Integer age;
    @Value("${os.name}")
    private String os;
}

8.2、@PropertySource

  • 配置文件person.properties
person.name=李四
  • 实体类
@PropertySource({"classpath:/person.properties"})
@Component
@Data
public class User {
    /**@Value使用set方法进行赋值,等同于
     * <bean id="" class="">
     *    <property name="" value=""/>
     * </bean>
     * 1、基本数值
     * 2、SPEL表达式,#{2*5}
     * 3、从配置文件中取值或者获取环境参数中的值${os.name}
     */
    //@Value("张三")
    @Value("${person.name}")
    private String name;
    @Value("#{20+4}")
    private Integer age;
    @Value("${os.name}")
    private String os;
}

 


9、自动装配

  • 假设存在两个组件A和B,其中A组件依赖于B组件(即A组件中包含B类型的成员)。自动装配就是应用于这种情况,可以使用下面三种注解,将B组件自动注入到A组件中。

9.1、@Autowired(spring自带的)

  • 实例
@Data
public class Person {
    @Value("张三")
    private String name;

    @Autowired
    private  Car car;
}
@Data
public class Car {
    @Value("保时捷")
    private String name;
}

 

public class SpringConfig {
    @Bean
    Person person(Car car){
        Person person = new Person();
        person.setCar(car);
        return person;
    }

    @Bean
    Car car(){
        return new Car();
    }
}
    @Test
    void test0(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Person person = context.getBean(Person.class);
        System.out.println(person);
    }

 

  •  测试结果

Person(name=张三, car=Car(name=保时捷))

1. 上面的实例是当容器中只有一个类型为Car的组件,当容器中有多个相同类型的组件时该如何自动注入呢?

  • 基于上面的实例,对SpringConfig进行修改,增加一个car类型的组件
public class SpringConfig {
    @Bean
    Person person(Car car){
        Person person = new Person();
        person.setCar(car);
        return person;
    }

    @Bean
    Car car(){
        Car car = new Car();
        car.setName("宝马");
        return car;
    }
    @Bean
    Car car2(){
        Car car = new Car();
        car.setName("奔驰");
        return car;
    }
}
  • 结果

Person(name=张三, car=Car(name=宝马))

从结果可知,当容器中存在多个类型的组件时,@Autowired会按照依赖类中(Person)字段的名称(car)作为组件的id去容器中查找被依赖类(Car)。当找不到时,此时会报错。比如将car的name="宝马"的方法名改为car1,会报错。其实,对于@Autowired注解来讲,在字段、set方法、有参构造器、参数上标注了这个注解后,默认是一定要在容器中找到相应的组件的,否则就会报错。如果想要找不到时不报错可以设置@Autowired(required = false),找不到时需要自动注入的组件可以为null

  • @Autowired源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}
  • 结论
  1. 当容器中不存在相同类型的多个实例时,@Autowired默认优先按照类型去容器中查找。
  2. 当容器中存在相同类型的多个实例时,默认会按照依赖类中定义的被依赖类型的字段名称作为id去容器中查找。
  3. @Autowired可以标注在在字段、set方法、有参构造器以及参数上,当只有一个有参构造器时可以省略不写。
  4. 在@Bean方法中,参数代表的对象也是直接从IOC容器中拿,不用标注任何自动注入的注解 

9.2、@Qualifier

  • 指定自动注入的组件的id
  • 实例(修改Person类)
@Data
public class Person {
    @Value("张三")
    private String name;

    @Qualifier("car2")
    @Autowired
    private  Car car;
}
  • 结果(指定自动注入的组件的id会直接返回对应id的组件)

Person(name=张三, car=Car(name=奔驰))

9.3、@Primary

  • 该注解配合@Autowired进行使用,当容器中存在同一种类型而多种实例的bean,可以将其标注在对应的配置类的bean方法上,使其成为首要的自动注入的对象。
  • 实例
    @Primary //在别的依赖类进行注入Car类型的组件时,首要注入当前标注有@Primary的bean
    @Bean
    Car car1(){
        Car car = new Car();
        car.setName("宝马");
        return car;
    }
    
    @Bean
    Car car2(){
        Car car = new Car();
        car.setName("奔驰");
        return car;
    }

 上述实例当别的组件依赖Car类型的组件并自动注入时,默认首先加载Car类型的car1实例

9.4、@Resource(JSR250)和@Inject(JSR330)

  • @Resource和@Autowired一样都是实现自动注入的功能。@Resource默认是按照名称自动注入bean的,不支持@Primary的功能。
  • @Inject需要导入以下依赖
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
  • @Inject和@Autowired功能一样,支持@Primary注解,不同的是@Inject里面没有任何属性。
  • AutowiredAnnotationBeanPostProcessor就是实现这些自动注入的注解的功能的,包括@Value

9.5、Aware注入Spring底层的组件

  • Aware相关接口

  • 如果想要使用Spring底层的一些组件时,可以实现这些xxxAware接口
  • 实例 
@Component
public class MyAware implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    private ApplicationContext applicationContext;

    //获取当前bean的名字:myAware
    @Override
    public void setBeanName(String s) {
        System.out.println(s);
    }
    //获取applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println(applicationContext);
    }
    //解析字符串
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String s = resolver.resolveStringValue("你好${os.name},我是#{18*20}");
        System.out.println(s);
    }
}
  • 结果

myAware
你好Windows 10,我是360
org.springframework.context.annotation.AnnotationConfigApplicationContext@587c290d, started on Tue Jan 19 14:49:37 CST 2021

  • 以上这些xxxAware,最终都会有xxxAwareProcessor(后置处理器)进行处理。比如ApplicationContextAware以及ApplicationContextAwareProcessor

9.6、@Profile

  • @Profile根据当前环境,动态的激活和切换一系列组件的功能
  • 实例
@Configuration
//@ComponentScan("com.wust.bean")
public class SpringConfig {
    //开发环境
    @Profile("dev")
    @Bean
    Car car1(){
        Car car = new Car();
        car.setName("宝马");
        return car;
    }
    
    //测试环境
    @Profile("test")
    @Bean
    Car car2(){
        Car car = new Car();
        car.setName("奔驰");
        return car;
    }
    
    //生产环境
    @Profile("prod")
    @Bean
    Car car3(){
        Car car = new Car();
        car.setName("奥迪");
        return car;
    }
    
    //默认环境
    @Profile("default")
    @Bean
    Car car4(){
        Car car = new Car();
        car.setName("凯迪拉克");
        return car;
    }
}
  • 测试
    @Test
    void test0(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        String[] names = context.getBeanNamesForType(Car.class);
        for (String name : names) {
            System.out.println(name);
        }
        context.close();
    }
  • 结果

car4

  1. 在不设置任何环境时,spring默认为default环境,可以通过增加命令行参数来切换环境,在vm options 设置 -Dspring.profiles.active=prod,test

  2. 也可以通过代码方式进行设置环境

通过代码方式进行设置时,不能使用AnnotationConfigApplicationContext的有参构造器创建容器对象。因为使用有参构造器创建容器时,自动连贯的就将各个配置类进行注册并且启动刷新了容器,无法通过编写代码进行设置。所以只能使用无参构造器。

	//componentClasses就是各个配置类
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
        //注册配置类
		register(componentClasses);
        //启动刷新容器
		refresh();
	}
  • 设置实例
    @Test
    void test0(){
        //AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //1.创建容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //2.设置环境
        context.getEnvironment().setActiveProfiles("prod","test");
        //3.注册主配置类
        context.register(SpringConfig.class);
        //4.启动刷新容器
        context.refresh();

        String[] names = context.getBeanNamesForType(Car.class);
        for (String name : names) {
            System.out.println(name);
        }
        context.close();
    }
  • 结论 
  1. 另外当@Profile标注在类上时,意味着只有处于指定环境下,整个配置类才生效,否则不会生效。
  2. 对于那些没有指定环境的bean,默认是在任何环境下都会被加载到容器中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值