详细分析Spring中的@Configuration注解基本知识(附Demo)

前言

Java的基本知识推荐阅读:

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 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");
        };
    }

}

相关推荐

  1. 详细分析Vue3卡槽知识点(Demo

    2024-07-10 09:30:03       30 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 09:30:03       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 09:30:03       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 09:30:03       90 阅读
  4. Python语言-面向对象

    2024-07-10 09:30:03       98 阅读

热门阅读

  1. Oracle数据库服务器CPU占用率巨高的问题排查思路

    2024-07-10 09:30:03       34 阅读
  2. WebKit简介及工作流程

    2024-07-10 09:30:03       28 阅读
  3. nlp中tokenizer用法

    2024-07-10 09:30:03       28 阅读
  4. 2.Date类型的请求参数

    2024-07-10 09:30:03       29 阅读
  5. 基于antdesign封装一个react的上传组件

    2024-07-10 09:30:03       35 阅读
  6. Leetcode100.判断两颗二叉树是否相同

    2024-07-10 09:30:03       27 阅读
  7. 防止应用调试分析IP被扫描加固实战教程

    2024-07-10 09:30:03       31 阅读
  8. Js- Math对象

    2024-07-10 09:30:03       26 阅读
  9. 基于Unity3D的Rokid AR Glass项目开发实战教程

    2024-07-10 09:30:03       32 阅读
  10. 每日一道算法题 求最小公倍数

    2024-07-10 09:30:03       93 阅读