@Configuration的详细使用

@Configuration的详细使用

Posted by bulingfeng on December 7, 2023

在讨论使用@Configuration之前呢,我先说下我使用的相关技术版本号,springboot的版本为:3.1.2;而这个版本对应的spring的版本是6.0;

@Configuration的基本使用

我们都知道@Configuration是一个配置的注解,通过这个注解,就是可以把对应的类给注入到spring的context中。比如如下代码:

1
2
3
4
5
6
7
@Configuration
public class WebConfiguration {
    @Bean
    public Dish getDish(){
        return new Dish("fish",false,100, Dish.Type.FISH);
    }
}

我们再通过spring的上下文来获取到WebConfiguration的类。并进行打印。

1
org.example.config.WebConfiguration$$SpringCGLIB$$0@420a8042

我们通过打印的信息发现,这是一个通过CGLIB来实现的代理类。

一些疑问

我们看到WebConfiguration类中有一个getDish这个方法,这个方法被@Bean所修饰,并且每次都会返回一个Dish类。那么我们通过拿到WebConfiguration类以后,然后反复的调用getDish那么会反复的创建Dish对象吗?

1
2
3
4
5
6
7
8
        ConfigurableApplicationContext applicationContext = SpringApplication.run(MybatisPlusApplication.class, args);

        WebConfiguration webConfig = applicationContext.getBean(WebConfiguration.class);
        System.out.println(webConfig);

        Dish dish1 = webConfig.getDish();
        Dish dish2 = webConfig.getDish();
        System.out.println(dish1 == dish2);

打印的结果为:

1
2
org.example.config.WebConfiguration$$SpringCGLIB$$0@3a7c678b
true

我们知道不管你调用几次,其实每次都是同一个对象。即使我在这个方法内创建多个方法,甚至是使用同一个bean的name,代码如下:

1
2
3
4
5
6
7
8
9
@Bean("getDish")
    public Dish getDish(){
        return new Dish("fish",false,100, Dish.Type.FISH);
    }

    @Bean("getDish")
    public Dish getDish2(){
        return new Dish("fish",false,100, Dish.Type.FISH);
    }

那么得到的结果,依然是这两个bean是一样的。比如两个beanName不一样呢?比如:

1
2
3
4
5
6
7
8
9
  @Bean
  public Dish getDish(){
      return new Dish("fish",false,100, Dish.Type.FISH);
  }

  @Bean
  public Dish getDish2(){
      return new Dish("fish",false,100, Dish.Type.FISH);
  }

那么结果自然是false,则两个bean是不一样的。

那么我们来看下官方文档是如何描述的把

1
In Spring, instantiated beans have a singleton scope by default. This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.

如果想了解更多,可以去官方文档进行查看

1
https://docs.spring.io/spring-framework/reference/core/beans/java/configuration-annotation.html#:~:text=%40Configuration%20is%20a%20class%2Dlevel,to%20define%20inter%2Dbean%20dependencies.

关于@Configuration中的一些参数使用

在上面的例子中我们可以看到,每次调用同一个getDish方法,都是获取的同一个bean对象。那么如果你想每次调用getDish方法都获取到不同的对象呢?

第一种方法,就是不使用@Configuration注解,而使用@Component注解。

第二种方法就是使用:

1
@Configuration(proxyBeanMethods = false)

proxyBeanMethods值的目的就是说是否使用代理类,默认为true.

而spring6.0还又多出来一个值:enforceUniqueMethods,这个值默认为true,说明在被@Bean修饰的方法中,是否能够运行方法重名。

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration(enforceUniqueMethods = true)
//@Component
public class WebConfiguration {
    @Bean
    public Dish getDish(){
        return new Dish("fish",false,100, Dish.Type.FISH);
    }
    @Bean
    public Dish getDish(String hello){
        return new Dish("fish",false,100, Dish.Type.FISH);
    }
}

这样的话,启动springboot的项目会直接报错。如果把值改成false,则不会报错。并且由于两个Dish都是同一个bean的name,所以这两个方法获取到的Dish对象是一样的。