1、@Configuration
该注解标注在一个类上表明该类是一个配置类
(1)编写配置类,通过配置类向IOC容器加入Bean对象
文件结构:
首先创建一个User类,然后编写一个MyConfig配置类,在配置类中将User对象装入IOC容器中,代码如下:
package com.yjh.config;
import com.yjh.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public User user01()
{
User zhangSan = new User("张三",18);
return zhangSan;
}
}
此时,user01已经被装入IOC容器中,我们可以在MainApplication中输出容器中的内容,对MainApplication中的代码进行修改,通过ConfigurableApplicationContext对象的getBeanDefinitionNames()方法可以获得容器中所有的bean。
package com.yjh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for(String beanName:beanDefinitionNames)
{
System.out.println(beanName);
}
}
}
在控制台中的搜索user01可以看到输出的内容中确实有user01,说明我们通过配置类将bean加入IOC中成功。
(2)判断容器中的bean是否是单例的,两次从容器中获取对象,并判断这两个对象是否是同一个
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for(String beanName:beanDefinitionNames)
{
System.out.println(beanName);
}
//判断是否为单例
User user1 = run.getBean("user01", User.class);
User user2 = run.getBean("user01", User.class);
System.out.println(user1==user2);
}
}
控制台输出true,表明默认是单例的。
(3)@Configuration可以带参数proxyBeanMethods,从名字上翻译过来就是代理Bean方法,该参数有两个值true和false,默认是true。下面进行代码演示:
首先将配置类中@Configuration的proxyBeanMethods置为false,然后在主程序中获取配置类对象,通过配置类对象调用成员方法user01()创建User对象,最后对比该对象与容器中的bean对象是否为同一个,具体代码如下:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for(String beanName:beanDefinitionNames)
{
System.out.println(beanName);
}
//判断是否为单例
User user1 = run.getBean("user01", User.class);
User user2 = run.getBean("user01", User.class);
System.out.println(user1==user2);
/*
* 测试proxyBeanMethods参数
* */
//获取配置类对象
MyConfig myConfig = run.getBean("myConfig", MyConfig.class);
//输出配置类对象
System.out.println(myConfig);
//配置类对象调用成员方法创建User对象
User user3 = myConfig.user01();
//判断该User对象与容器中的对象是否是同一个
System.out.println(user3==user1);
}
}
输出的结果:
将配置类上的注解@Configuration的proxyBeanMethods置为true,重新再次跑一次主程序,结果如下:
重点!!!
由上述输出的myConfig就可以发现当proxyBeanMethods置为true时,此时的对象是由CGLIB增强的代理对象,而并不是myConfig本身。
该代理对象在myConfig对象的基础上做了增强,在调用user01()成员方法时,该对象会先去容器中查找容器中是否已经有该bean,如果有则直接通过容器中的bean生成User对象,如果没有再通过成员方法创建对象。这也就是为什么当proxyBeanMethods为true时,两个对象相同,为false时,两个对象不同。
2、总结
@Configuration添加在某个类上面,该类就是配置类。
@Configuration有个参数proxyBeanMethods,当该参数为ture时,生成的配置类对象是增强的代理对象,该模式称为Full模式。反之,称为Lite模式。
何时使用Full模式,何时使用Lite模式?
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式