1、编写springboot的配置类(基于java类 @Configuration)
- 首先编写用户类和宠物类(pojo.User pojo.Pet)
导入lombok 依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pet {
private String name;
}
- 之前学的用beans.xml 中 注入组件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--将用户注入到容器中-->
<bean id="user01" class="com.tesla.pojo.User">
<property name="name" value="Jack"/>
<property name="age" value="20"/>
</bean>
<!--将宠物注入到容器中-->
<bean id="cat01" class="com.tesla.pojo.Pet">
<property name="name" value="tomcat"/>
</bean>
</beans>
然后在主函数中使用注入的组件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Pet cat = context.getBean("cat01", Pet.class);
System.out.println(cat.getName());
- 另外一种方式,直接在java类中使用**@Configuration** (即创建一个配置类将组件注入容器
config.MyConfiguration
)
/**
* 告诉SpringBoot这是一个配置类 == 配置文件
*/
@Configuration
public class MyConfiguration {
/**
*给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
*/
@Bean
public User myUser(){
return new User("zhangsan",20);
}
@Bean
public Pet myCat(){
return new Pet("miaomiao");
}
}
获取容器中组件方法同上(主程序获取)
@SpringBootApplication(scanBasePackages = "com.tesla")
public class ApplicationMain {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(ApplicationMain.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
//3、从容器中获取组件,这里直接用 run 对象获取就可以了
User myUser1 = run.getBean("myUser", User.class);
User myUser2 = run.getBean("myUser", User.class);
//返回值是 true
System.out.println("两个用户是否相等:"+(myUser1==myUser2));
}
}
配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的(也就是不管在主程序中创建多少个对象,它们都是从容器中拿出来的,这些对象的地址都相等)
注意: 查看容器中的组件,可以发现 配置类(@Configuration
),控制类(@Controller
) 其实都是注入到容器中的组件
2、Full模式与Lite模式
proxyBeanMethods() 属性的详解
- @Configuration 有一个方法 proxyBeanMethods() 默认为 true (即开启代理Bean 方法)
//手动开启 代理Bean 方法
@Configuration(proxyBeanMethods=true)
现在在User 中添加一个属性Pet,增加了对Pet类的依赖
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
//现在User类 依赖 Pet类了
private Pet pet;
}
修改 配置类中 User的方法
@Bean
public User myUser(){
//先用mycat方法将组件从容器中拿出来
Pet pet = myCat();
return new User("zhangsan",20,pet);
}
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
//从而保持组件单实例
MyConfiguration bean = run.getBean(MyConfiguration.class);
User user1 = bean.myUser();
User user2 = bean.myUser();
System.out.println("两个用户是否相等:"+(user1==user2));
//返回值还是true,因为不管代理对象bean调用多少次myUser,他还是从容器中拿Pet类的对象
注意: 这里的使用的是代理对象bean调用
//从容器中拿出myUser组件
User myUser = run.getBean("myUser", User.class);
//从容器中拿出myCat组件
Pet myCat = run.getBean("myCat", Pet.class);
//比较myUser中的Pet类组件和容器中拿出myCat组件是否一样,返回值是 true
System.out.println("两个宠物是否相等:"+(myCat==myUser.getPet()));
- 将方法 proxyBeanMethods() 改为 false (即关闭代理Bean 方法)
@Configuration(proxyBeanMethods=false)
主程序中方法
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(ApplicationMain.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
//3、从容器中获取组件,这里直接用 run 对象获取就可以了
User myUser1 = run.getBean("myUser", User.class);
User myUser2 = run.getBean("myUser", User.class);
//返回值是:true
System.out.println("两个用户是否相等:"+(myUser1==myUser2));
//返回值是:true
System.out.println("两个宠物是否相等:"+(myUser1.getPet()==myUser2.getPet()));
//如果@Configuration(proxyBeanMethods = false),SpringBoot不会检查这个组件是否在容器中有。
MyConfiguration bean = run.getBean(MyConfiguration.class);
User user1 = bean.myUser();
User user2 = bean.myUser();
//返回值是:false
System.out.println("两个用户是否相等:"+(user1==user2));
User myUser = run.getBean("myUser", User.class);
Pet myCat = run.getBean("myCat", Pet.class);
//返回值是:false
System.out.println("两个宠物是否相等:"+(myCat==myUser.getPet()));
//将用 配置类 创建的对象 user1 和直接用 容器创建的 myUser 比较 两个结果都是 false
System.out.println("两个用户是否相等:"+(user1==myUser));
System.out.println("两个宠物是否相等:"+(myCat==user1.getPet()));
//将两个都在 IOC容器中创建的对象 myUser1 和 myUser 比较,结果为 true
System.out.println("两个用户是否相等:"+(myUser1==myUser));
System.out.println("两个宠物是否相等:"+(myUser1.getPet()==myUser.getPet()));
//前者是在IOC容器中创建的,后者是在 @Bean 注解下创建的对象,它们不相同 所以结果是false
System.out.println("两个宠物是否相等:"+(myCat==myUser1.getPet()));
总结:
- 第一个true:使用@Bean标注在方法上给容器注册组件是单例的,实质是从容器中拿的( 当然在 Bean 注解下面添加
@Scope("prototype")
变为原型模式,结果就为 false 了) - 第二个true:因为都是从容器中拿到的组件,它们所依赖的对象也是一样的
- 第三个false:将代理Bean 方法设为false,这样每次使用Config类创建时,SpringBoot不会检查这个组件是否在容器中有,而是直接创建一个
- 第四个false:注册的myUser组件调用@Bean标注的方法获取到的Pet类的对象和下面IOC容器中的myCat对象不一样
- proxyBeanMethods配置类是用来指定@Bean注解标注的方法是否使用代理,默认是true使用代理,直接从IOC容器之中取得对象;如果设置为false,也就是不使用注解,每次调用@Bean标注的方法获取到的对象和IOC容器中的都不一样,是一个新的对象
- lite 模式:不用检查是否在容器,启动加载起来快(只注册组件,组件之中不存在依赖,就用lite模式)
- full模式:存在组件依赖关系,会检查这个组件是否在容器中