2. JavaConfig
2. JavaConfig
JavaConfig
JavaConfig: 使用 java 类作为 xml 配置文件的替代, 是配置 spring 容器的纯 java 的方式. 在这个 java 类这可以创建 java 对象, 把对象放入 spring 容器中(注入到容器), 该配置类本身也是组件
使用两个注解:
@Configuration: 放在一个类的上面, 表示这个类是作为配置文件使用的.
@Bean: 声明对象, 把对象注入到容器中, 默认为单实例.
@Configuration
public class MyConfig {
/**
* 创建方法, 方法的返回值是对象. 在方法的上面加入@Bean
* 方法的返回值对象就注入到容器中.
* `@Bean`: 把对象注入到spring容器中. 作用相当于 xml文件的 <bean> 标签
* 位置: 方法的上面
* 说明: `@Bean`,不指定对象的名称, 默认是方法名是 id
*/
@Bean
public Student createStudent() {
Student s1 = new Student();
s1.setName("张三");
s1.setAge(26);
s1.setSex("男");
return s1;
}
/**
* 指定对象在容器中的名称(指定<bean>的id属性)
* `@Bean`的name属性, 指定对象的名称(id)
*/
@Bean(name = "lisiStudent")
public Student makeStudent() {
Student s2 = new Student();
s2.setName("李四");
s2.setAge(22);
s2.setSex("男");
return s2;
}
}
获取 bean 实例对象
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
// 获取容器内的对象, 默认单实例
Student createStudent = run.getBean("createStudent", Student.class);
System.out.println(createStudent);
Student lisiStudent = run.getBean("lisiStudent", Student.class);
System.out.println(lisiStudent);
}
}
尝试获取配置类本身
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
MyConfig myConfig = run.getBean(MyConfig.class);
System.out.println(myConfig);
}
}
com.example.config.MyConfig$$EnhancerBySpringCGLIB$$78d620be@3122b117
如果 @Configuration(proxyBeanMethods = true)
该配置类会被 SpringCGLIB 增强为代理对象, SpringBoot 总会检查这个组件是否在容器中.
所以通过配置类直接调用 createStudent()
方法返回的对象也会是单实例的.
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
MyConfig myConfig = run.getBean(MyConfig.class);
Student student = myConfig.createStudent();
Student student1 = myConfig.createStudent();
System.out.println(student == student1);
}
}
指定 @Configuration(proxyBeanMethods = false)
后 MyConfig 类将会变成一个普通类, 通过该类调用 createStudent()
方法将直接创建新对象.
@Configuration(proxyBeanMethods = false)
public class MyConfig {
@Bean
public Student createStudent() {
return new Student();
}
}
测试
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
MyConfig myConfig = run.getBean(MyConfig.class);
Student student = myConfig.createStudent();
Student student1 = myConfig.createStudent();
System.out.println(myConfig);
System.out.println(student == student1);
}
}
com.example.config.MyConfig@469d003c false
Full 模式与 Lite 模式:
Full(proxyBeanMethods = true) [保证每个@Bean 方法被调用多少次返回的组件都是单实例的]
Lite(proxyBeanMethods = false) [每个@Bean 方法被调用多少次返回的组件都是新创建的]
组件依赖必须使用 Full 模式默认, 其他默认是否 Lite 模式
@Import
该注解会自动创建导入的组件, 参数是一个数组, 默认组件为全类名
@Import({Student.class})
@Configuration
public class MyConfig {
}
获取组件
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
System.out.println(run.getBean(Student.class));
}
}
Student(id=null, name=null, age=null)
@Conditional
条件装配:满足指定的条件,则进行组件注入
@Conditional 本身是个根注解, 底下派生了非常多的子注解
idea 可使用 Ctrl + N
搜索 @Conditional Ctrl + H
打开继承树查看
当容器内存在名字为 school 的组件时才注册 student 组件
@Configuration
public class MyConfig {
// 当容器内存在名字为 school 的组件时才注册 student 组件
@ConditionalOnBean(name = "school")
@Bean(name = "student")
public Student getStudent() {
return new Student();
}
}
使用 containsBean() 方法验证容器内是否存在该组件
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
System.out.println(run.containsBean("school"));
System.out.println(run.containsBean("student"));
}
}
false false
如果 @ConditionalOnBean(name = "school")
标注在类上, 则对整个类生效
// 当容器内存在名字为 school 的组件时才配置类才会加载组件
@ConditionalOnBean(name = "school")
@Configuration
public class MyConfig {}
相关信息
SpringBoot 底层有非常多的条件装配, SpringBoot 的按需加载就是使用条件装配实现的.
@ImporResource
@ImportResource 作用是导入其他的 xml 配置文件, 一般用于适配老项目.
xml 实现方式:
<import resources="其他配置文件"/>
SpringBoot 实现方式:
@ImportResource 底层实现是一个数组:
public @interface ImportResource {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
Class<? extends BeanDefinitionReader> reader() default BeanDefinitionReader.class;
}
所以可以同时导入多个配置文件:
@Configuration
@ImportResource(value ={"classpath:applicationContext.xml","classpath:beans.xml"})
public class SpringConfig {
}
使用 SpringBoot 配置文件实例化一个 配置文件内的 bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myCat" class="com.example.bean.Cat">
<property name="name" value="myCat"/>
<property name="age" value="20"/>
<property name="carId" value="1"/>
</bean>
</beans>
在配置类里面导入:
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class MyConfig {}
测试:
@Test
void contextLoads3() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
Cat myCat = context.getBean("myCat", Cat.class);
System.out.println(myCat);
}
@PropertyResource
@PropertyResource: 读取 properties 属性配置文件, 进行配置绑定.
使用属性配置文件可以实现外部化配置, 在程序代码之外提供数据.
只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能
@Configuration
@PropertySource("classpath:config.properties")
@ComponentScan("com.example.bean")
public class MyConfig {}
步骤:
- 在 resources 目录下, 创建 properties 文件, 使用 k=v 的格式提供数据
- 在 PropertyResource 指定 properties 文件的位置
- 使用 @Value(value="${key}")
先确定项目文件的编码类型
创建一个 Tiger 类, 并实例化到 spring 容器中
使用 @Value(value="${key}") 指定 K
@Data
@Component("tiger") // 只有在容器中的组件,才会拥有SpringBoot提供的强大功能.
public class Tiger {
@Value("${tiger.name}")
private String name;
@Value("${tiger.age}")
private int age;
}
创建一个 properties 配置文件
在配置文件中对 tiger 实例的属性赋值, 指定 V
tiger.name=东北虎
tiger.age=2
@ConfigurationProperties
和 @PropertyResource 一样, 都是读取 properties 属性配置文件, 进行配置绑定, 但 @ConfigurationProperties 是作用在类实例上
使用要求也一样: 只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能
application.properties
student.id=1
student.name=Student
student.age=20
使用 @ConfigurationProperties(prefix = "student") 指定前缀
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component // 只有在容器中的组件,才会拥有SpringBoot提供的强大功能.
@ConfigurationProperties(prefix = "student")
public class Student {
private Integer id;
private String name;
private Integer age;
}
测试
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
System.out.println(run.getBean("student"));
}
}
Student(id=1, name=Student, age=20)
@ConfigurationProperties 的第二种实现: 配合 @EnableConfigurationProperties 注解
在配置类上使用 @EnableConfigurationProperties 注解指定实例类开启配置绑定功能
@Configuration
@EnableConfigurationProperties(Student.class)
public class MyConfig {
}
类实例就不需要 @Component 注解
@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "student")
public class Student {
private Integer id;
private String name;
private Integer age;
}
@EnableConfigurationProperties 的两个功能
开启 Student 配置绑定功能 把 Student 这个组件自动注册到容器中