目录
- 前言
- 1. 基本知识
- 2. 详细分析
- 3. Demo
- 3.1 简单Bean配置
- 3.2 属性配置
- 3.3 多条件配置
- 4. 实战拓展
前言
Java的基本知识推荐阅读:
- java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
- Spring框架从入门到学精(全)
拓展应用补充阅读:@Configuration注解使用
1. 基本知识
在Java和Spring框架中,@Configuration
注解用于定义配置类,这些类可以替代传统的XML配置文件
- 是Spring的一部分,用于创建和管理bean,提供了更灵活和强大的配置机制
- 配置类包含了一个或多个@Bean方法,这些方法返回要在Spring容器中管理的bean
基本示例如下:
AppConfig类被标注为一个配置类,并且定义了一个myService方法,该方法返回一个MyService实例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
自动装配:
配置类中的bean可以自动装配到其他bean中
@Configuration
public class AnotherConfig {
private final MyService myService;
@Autowired
public AnotherConfig(MyService myService) {
this.myService = myService;
}
@Bean
public AnotherService anotherService() {
return new AnotherServiceImpl(myService);
}
}
2. 详细分析
注解继承与组合:
@Configuration类可以使用其他Spring注解,如@ComponentScan和@Import,来扫描组件或导入其他配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// Bean定义
}
@Configuration
@Import(AppConfig.class)
public class MainConfig {
// 主要配置
}
代理机制:
@Configuration类在Spring容器启动时会通过CGLIB动态代理机制生成代理类,以确保@Bean方法只被调用一次,从而保证单例bean的行为
@Configuration
public class ConfigClass {
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
public AnotherBean anotherBean() {
// myBean() 方法将返回相同的实例,而不会创建新实例
return new AnotherBean(myBean());
}
}
条件化配置:
使用@Conditional注解,可以根据某些条件来决定是否创建某个bean
@Configuration
public class ConditionalConfig {
@Bean
@Conditional(MyCondition.class)
public MyBean conditionalBean() {
return new MyBean();
}
}
环境和属性配置:
使用@PropertySource和@Value注解可以将外部属性文件中的值注入到配置类中
@Configuration
@PropertySource("classpath:application.properties")
public class PropertyConfig {
@Value("${my.property}")
private String myProperty;
@Bean
public PropertyBean propertyBean() {
return new PropertyBean(myProperty);
}
}
3. Demo
3.1 简单Bean配置
总体完整的Demo如下:
// AppConfig.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyController myController() {
return new MyController(myService());
}
}
// MyService.java
package com.example.demo;
public class MyService {
public String sayHello() {
return "Hello, World!";
}
}
// MyController.java
package com.example.demo;
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
public String greet() {
return myService.sayHello();
}
}
// AppTest.java
package com.example.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyController controller = context.getBean(MyController.class);
System.out.println(controller.greet()); // 输出: Hello, World!
}
}
最终执行结果如下:
3.2 属性配置
// AppConfig.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {
@Value("${app.message}")
private String message;
@Bean
public MessageService messageService() {
return new MessageService(message);
}
}
// MessageService.java
package com.example.demo;
public class MessageService {
private final String message;
public MessageService(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
// AppTest.java
package com.example.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MessageService service = context.getBean(MessageService.class);
System.out.println(service.getMessage()); // 输出配置文件中的app.message值
}
}
// application.properties
app.message=Hello from properties!
截图如下:
3.3 多条件配置
// AppConfig.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
@Conditional(MyCondition.class)
public ConditionalService conditionalService() {
return new ConditionalService();
}
}
// MyCondition.java
package com.example.demo;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 返回true时才会创建ConditionalService bean
return true;
}
}
// ConditionalService.java
package com.example.demo;
public class ConditionalService {
public String getMessage() {
return "Conditional Service is active!";
}
}
// AppTest.java
package com.example.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
if (context.containsBean("conditionalService")) {
ConditionalService service = context.getBean(ConditionalService.class);
System.out.println(service.getMessage()); // 输出: Conditional Service is active!
} else {
System.out.println("Conditional Service is not active");
}
}
}
截图如下:
4. 实战拓展
对于这个@Configuration注解,往往会配合proxyBeanMethods一起使用
proxyBeanMethods = true
(默认行为):表示Spring会为配置类生成一个CGLIB代理对象,以确保每个@Bean方法只会被调用一次,并且返回相同的实例(单例模式)
这种方式可以确保@Bean方法间的依赖能够正确处理proxyBeanMethods = false
:表示Spring不会为配置类生成代理对象,每次调用@Bean方法时都会返回一个新的实例
这种方式可以减少CGLIB代理的开销,适用于@Bean方法之间没有依赖关系的场景
Demo如下:
@Configuration(proxyBeanMethods = false)
是一个Spring的注解,用于标识一个类是配置类,同时指定该配置类中@Bean方法的代理行为
方法每次调用都会返回一个新的 DeptDataPermissionRuleCustomizer 实例
@Configuration(proxyBeanMethods = false)
public class DataPermissionConfiguration {
@Bean
public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
return rule -> {
// dept
rule.addDeptColumn(AdminUserDO.class);
rule.addDeptColumn(DeptDO.class, "id");
rule.addDeptColumn(AppointmentCommissionDO.class, "dept_id");
// user
rule.addUserColumn(AdminUserDO.class, "id");
rule.addUserColumn(AppointmentCommissionDO.class, "user_id");
};
}
}