springBoot2中-Configuration注解新增的proxyBeanMehtods属性详解

@Configuration(proxyBeanMethods = true/false)

1、Full模式(proxyBeanMethods=true)

proxyBeanMethods=true 为Full模式(默认为true),此时在spring IOC容器中的此配置类是一个CGLIB代理类,并且调用此配置类的@Bean方法产生的bean是单例的,即每次调用标有@Bean注解方法都会检查IOC容器中是否有该bean组件,如果没有则调用方法创建,否则就直接从IOC容器中获取。

测试代码

1
2
3
4
5
6
7
@Configuration(proxyBeanMethods = true)
public class ProxyBeanMethodTest {
@Bean
public User user(){
return new User();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class MainApplication {
public static void main(String[] args){
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
ProxyBeanMethodTest bean = run.getBean(ProxyBeanMethodTest.class);
System.out.println("配置类:"+bean);
User user1 = bean.user();
User user2 = bean.user();
System.out.println("第一次调用配置类中的@Bean注解方法得到的bean组件:"+user1);
System.out.println("第二次调用配置类中的@Bean注解方法得到的bean组件:"+user2);
}
}

运行结果

两次调用user()方法得到的是同一个user对象

2、Lite模式(proxyBeanMethods=false)

proxyBeanMethods=false 为Lite模式,此时在spring IOC容器中此配置类就是一个普通的类,每次调用此配置类中标有@Bean注解的方法时都会在IOC容器中注册新的bean组件,调用@Bean方法时无需检查IOC容器中是否存在该bean组件,可以提高效率,加速容器启动

测试代码

1
2
3
4
5
6
7
@Configuration(proxyBeanMethods = false)
public class ProxyBeanMethodTest {
@Bean
public User user(){
return new User();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class MainApplication {
public static void main(String[] args){
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
ProxyBeanMethodTest bean = run.getBean(ProxyBeanMethodTest.class);
System.out.println("配置类:"+bean);
User user1 = bean.user();
User user2 = bean.user();
System.out.println("第一次调用配置类中的@Bean注解方法得到的bean组件:"+user1);
System.out.println("第二次调用配置类中的@Bean注解方法得到的bean组件:"+user2);
}
}

运行结果

两次调用user()方法得到的是不同的User对象

3、Full模式和Lite模式优劣比较

Full模式可以很好地处理组件之间相互依赖的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration(proxyBeanMethods = true)
public class ProxyBeanMethodTest {

@Bean
public User user(){
User user = new User();
user.setDog(dog());
return user;
}

@Bean
public Dog dog(){
return new Dog();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

User user = run.getBean(User.class);
Dog dog1 = user.getDog();
Dog dog2 = run.getBean(Dog.class);
System.out.println(dog1 == dog2);
}
}

由以上结果可以看出,IOC容器中的Dog与User的属性Dog是同一个对象,也更加印证了当为User对象注入Dog属性时,此Dog是从IOC容器中获取的,而并非重新调用了dog()方法。从上面的测试代码中也可以看出,使用Full模式可以确保IOC容器中同一类型的对象始终是同一个,可以很好的处理组件依赖问题。

Lite模式免去了每次调用方法前去IOC容器中检查的过程,可以有效加速容器启动过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration(proxyBeanMethods = true)
public class ProxyBeanMethodTest {

@Bean
public User user(){
User user = new User();
user.setDog(dog());
return user;
}

@Bean
public Dog dog(){
return new Dog();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

User user = run.getBean(User.class);
Dog dog1 = user.getDog();
Dog dog2 = run.getBean(Dog.class);
System.out.println(dog1 == dog2);
}
}


4、结论

  • 配置类组件之间无依赖关系时使用Lite模式,可以省去检查容器中是否已经存在同类型组件的过程,加速容器启动
  • 配置类组件之间有依赖关系,使用Full模式,方法调用得到容器中的单实例组件

友情链接

视频讲解内容可参考尚硅谷-SpringBoot2讲解视频:https://www.bilibili.com/video/BV19K4y1L7MT?p=8