@Configuration注解
@Configuration注解的作用是代替以前我们使用的xml配置文件,被注解的类就是配置类,其内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
被@Configuration注解标注配置类本身也是一个组件。
基本使用
Pet类
/**
* @author:小关同学爱吃汉堡
* @date: 2021/4/5 17:41
*/
public class Pet {
private String name;
public Pet(){
}
public Pet(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
User类
/**
* @author:小关同学爱吃汉堡
* @date: 2021/4/5 17:40
*/
public class User {
private String name;
private Integer age;
private Pet pet;
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public User(){
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
配置类
我们使用@Bean注解在方法上给容器注册组件,它默认是单实例的
import com.gcl.demo1helloworld.bean.Pet;
import com.gcl.demo1helloworld.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author:小关同学爱吃汉堡
* @date: 2021/4/5 17:44
*/
@Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类,
// 配置类本身也是一个组件
//proxyBeanMethods:代理bean的方法
// Full(proxyBeanMethods = true)
// Lite(proxyBeanMethods = false)
// 组件依赖
public class MyConfig {
/**
* @Bean注解标注的组件是单实例的
* 在单实例下
* 外部无论对配置类中的这个组件注册的方法调用多少次
* 获取到的都是之前注册容器中的单实例对象
* @return
*/
@Bean
//相当于xml文件中的bean标签,作用是给容器中添加组件,以方法名作为组件的id,返回类型就是组件类型
//返回的值,就是组件在容器中的实例
public User user01(){
User user = new User("张三",19);
user.setPet(pet01());
return user;
}
@Bean("cat")//这里修改组件的id为"cat"
public Pet pet01(){
return new Pet("cat");
}
}
启动类
import com.gcl.demo1helloworld.bean.Pet;
import com.gcl.demo1helloworld.bean.User;
import com.gcl.demo1helloworld.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
@SpringBootApplication(scanBasePackages="com.gcl")
public class Demo1HelloworldApplication {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext context = SpringApplication.run(Demo1HelloworldApplication.class, args);
//从容器中获取组件
Pet pet1 = context.getBean("cat", Pet.class);
Pet pet2 = context.getBean("cat", Pet.class);
//判断@Bean注解标注的组件是否是单实例的
System.out.println("组件:"+(pet1==pet2));//结果返回true,可知@Bean标注的组件是单实例的
MyConfig bean = context.getBean(MyConfig.class);
//结果:com.gcl.demo1helloworld.config.MyConfig$$EnhancerBySpringCGLIB$$b19d16f6@7e97551f
//从结果可以看出该配置类被SpringCGLIB增强了
System.out.println(bean);
//获取到的bean本身就是一个代理对象
//如果@Configuration(proxyBeanMethods = true)中的proxyBeanMethods值为true
//那么外部每次使用配置类的方法都会从容器中找组件,获取到的就是代理对象
//否则获取到的就不是代理对象
//当proxyBeanMethods = true时,结果为true,
//当proxyBeanMethods = false时,结果为false,
User user1 = bean.user01();
User user2 = bean.user01();
System.out.println(user1 == user2);
//当proxyBeanMethods = true时,结果为true,
//即:user.setPet(pet01());中的pet01()没有创建新的Pet对象,还是使用容器中已经加载好的Pet对象
//当proxyBeanMethods = false时,结果为false,
//即:user.setPet(pet01());中的pet01()创建了一个新的Pet对象,容器取消判断容器中是否有重复的组件
User user = context.getBean("user01",User.class);
Pet cat = context.getBean("cat",Pet.class);
System.out.println(user.getPet()==cat);
}
}
Full模式与Lite模式
Full模式
保证每个@Bean方法被调用多少次返回的组件都是单实例的
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件
Lite模式
每个@Bean方法被调用多少次返回的组件都是新创建的
配置类组件之间无依赖关系,用Lite模式加速容器启动过程,减少判断容器中是否有相同组件的过程
关于更多Full模式与Lite模式的知识有一篇文章写得很好:
Spring的@Configuration配置类-Full和Lite模式