注解方式配置Spring容器

注解方式配置Spring容器

注解方式配置 Spring 容器可以完全替代传统的 XML 配置文件。只需要定义一个配置类,并在配置类上使用注解来指定扫描的包,Spring 就会自动扫描并注册这些包下的组件(如 @Component@Service@Repository 等)

核心步骤

  1. 导入依赖

  2. 定义一个配置类

    • 使用 @Configuration 注解标记一个类为配置类。这个类的作用类似于 XML 配置文件

    • @Configuration
      @ComponentScan(basePackages = "com.example") // 指定扫描的包
      public class AppConfig {
      }
      
    • @Configuration:标记该类为 Spring 的配置类。

    • @ComponentScan:指定 Spring 扫描的包路径,Spring 会自动注册这些包下的组件。

    • @PropertySource注解:在Java配置类使用@PropertySource注解,显式指定配置文件的位置

      • @Configuration
        //加载单个
        @PropertySource("classpath:application.properties")
        //加载多个
        @PropertySource({"classpath:application.properties", "classpath:another.properties"})
        public class AppConfig {
        }
        
      • @PropertySource默认只支持properties文件。如果需要加载YAML文件,需要额外配置

  3. 在组件上使用注解

    • 在需要被 Spring 管理的类上使用以下注解:
      • @Component:通用组件。
      • @Service:服务层组件。
      • @Repository:持久层组件。
      • @Controller:控制层组件(通常用于 Spring MVC)。
  4. 使用 @Autowired 注入依赖

    • 在需要注入依赖的地方使用 @Autowired 注解。Spring 会自动查找匹配的 Bean 并注入

    • @Service
      public class UserService {
          private final UserRepository userRepository;
      
          @Autowired
          public UserService(UserRepository userRepository) {
              this.userRepository = userRepository;
          }
      }
      
  5. 启动 Spring 容器

    • 使用 AnnotationConfigApplicationContext 加载配置类,启动 Spring 容器

    • public class MainApp {
          public static void main(String[] args) {
              // 加载配置类,初始化 Spring 容器
              ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
      
              // 从容器中获取 Bean
              UserService userService = context.getBean(UserService.class);
      
              // 使用 Bean
              userService.doSomething();
          }
      }
      
  6. 混合使用 XML 和注解

    • 如果需要,可以同时使用注解和 XML 配置。在配置类中使用 @ImportResource 导入 XML 配置文件

    • @Configuration
      @ComponentScan(basePackages = "com.example")
      @ImportResource("classpath:applicationContext.xml") // 导入 XML 配置文件
      public class AppConfig {
      }
      

常见注解

  • @Component

    • 作用: 标记一个类为 Spring 容器管理的 Bean。

    • 使用场景: 通用的组件,不特定于服务层、持久层或控制器层。

    • @Component
      public class MyComponent {
          // 类内容
      }
      
    • Bean的名称

      • 默认情况下,Spring 会将类名的首字母小写作为 Bean 的名称。例如,MyComponent 类的 Bean 名称是 myComponent。也可以通过 @Component 注解的 value 属性指定 Bean 的名称

      • Spring用map集合存储所有的Bean,键就是Bean的名称

      • @Component("customBeanName")
        public class MyComponent {
            // 类的内容
        }
        
  • @Service:标记一个类为服务层的 Bean

  • @Repository:标记一个类为持久层的 Bean

  • @Controller:标记一个类为控制层的 Bean,用于处理 HTTP 请求(通常在 Spring MVC 中使用)

  • @Bean

    • 作用: 标记一个方法返回的对象为 Spring 容器管理的 Bean。

    • 使用场景: 用于配置类中定义 Bean。

    • @Configuration类中,@Bean方法会被Spring通过CGLIB代理增强,确保每次调用@Bean方法时返回的是同一个单例Bean(除非显式指定@Scopeprototype

    • @Component类中的@Bean方法不会被CGLIB代理增强。因此,如果多次调用@Bean方法,可能会创建多个实例(除非手动确保单例行为)

    • 如果@Bean方法所在的类没有@Configuration@Component注解,可以通过@Import将其导入到配置类中

    • public class MyConfig {
          @Bean
          public MyService myService() {
              return new MyService();
          }
      }
      
      @Configuration
      @Import(MyConfig.class)
      public class AppConfig {
      }
      
    • @Bean 方法的参数注入机制

      • 当 Spring 容器调用 @Bean 方法时,它会:

        • 解析方法参数:根据参数类型从容器中查找匹配的 Bean。

          • 默认情况下,Spring 会根据类型注入
          • 如果存在多个相同类型的 Bean,Spring 会根据参数名称注入
        • 自动注入:将找到的 Bean 作为参数传递给 @Bean 方法。

        • @Bean
          public UserService userService(UserRepository userRepository) {
              return new UserService(userRepository);
          }
          
        • UserRepository userRepository 参数会被 Spring 自动注入。

  • @Configuration

    • 作用: 标记一个类为配置类,通常与 @Bean 注解一起使用。

    • 使用场景: 用于定义 Bean 的配置。

    • @Configuration
      public class MyConfig {
          @Bean
          public MyBean myBean() {
              return new MyBean();
          }
      }
      //Spring 会使用该((方法名))作为 Bean 的名称
      //自定义Bean名称
      @Configuration
      public class MyConfig {
      
          @Bean("customBeanName")
          public MyBean myBean() {
              return new MyBean();
          }
      }
      
  • @Conditional

    • 根据条件决定是否注册某个 Bean

    • @Bean
      @Conditional(MyCondition.class)
      public MyBean myBean() {
          return new MyBean();
      }
      
  • @Scope

    • 作用: 定义 Bean 的作用域(如单例、原型等)。

    • 使用场景: 用于指定 Bean 的生命周期。

    • @Component
      @Scope("prototype")
      public class MyComponent {
          // 类内容
      }
      
  • @Primary

    • 作用: 当有多个相同类型的 Bean 时,优先使用标记为 @Primary 的 Bean。
    • 使用场景: 用于指定默认的 Bean。
  • @PostConstruct 和 @PreDestroy

    • 作用: 分别标记在 Bean 初始化和销毁时执行的方法。

    • 使用场景: 用于生命周期回调。

    • @Component
      public class MyComponent {
          @PostConstruct
          public void init() {
              // 初始化逻辑
          }
      
          @PreDestroy
          public void destroy() {
              // 销毁逻辑
          }
      }
      

依赖注入

所有注入方式的前提条件:类必须由 Spring 管理

Spring支持以下几种依赖注入的方式:

  1. 字段注入

  2. 构造方法注入

    @Service
    public class MyService {
    
        private final MyRepository myRepository;
        private final MyComponent myComponent;
    
        @Autowired
        public MyService(
            @Qualifier("myRepositoryImpl") MyRepository myRepository,
            @Qualifier("myComponentImpl") MyComponent myComponent
        ) {
            this.myRepository = myRepository;
            this.myComponent = myComponent;
        }
    }
    
  3. Setter方法注入

  4. 条件化注入

方法注入

  • @Autowired 注解用于普通方法时,Spring 会将匹配的 bean 注入到方法的参数中

    • @Autowired
      public void setUserRepository(UserRepository userRepository) {
          this.userRepository = userRepository;
      }
      
      • 方法的参数类型是 UserRepository
      • Spring 会在容器中查找类型为 UserRepository 的 bean。
      • 如果找到唯一一个匹配的 bean,Spring 会将其注入到方法参数中。
  • 方法名无关紧要:Spring 只关心方法的参数类型,而不是方法名。方法名可以是任意的(例如 setUserRepositoryinit 等)。

    • 如果有该方法上存在@Bean注解的话方法名会被当作该Bean的默认名称

    • 方法参数必须匹配:方法的参数类型必须与 Spring 容器中的 bean 类型匹配。如果有多个匹配的 bean,需要使用 @Qualifier 注解指定具体的 bean。

      • @Service
        public class UserService {
        
            private UserRepository userRepository;
        
            @Autowired
            public void setUserRepository(@Qualifier("jdbcUserRepository") UserRepository userRepository) {
                this.userRepository = userRepository;
            }
        }
        

按照注入属性值类型的划分:

  1. 普通类型的属性注入

    • 普通类型包括基本数据类型(如intboolean等)及其包装类(如IntegerBoolean等),以及字符串(String

    • 使用@Value注解,@Value注解用于注入普通类型的值,可以直接注入字面量,也可以注入配置文件中的属性值

    • @Service
      public class MyService {
      
          // 注入字面量
          @Value("100")
          private int maxUsers;
      
          // 注入字符串
          @Value("Hello, World!")
          private String greeting;
      
          // 注入配置文件中的属性值
          @Value("${app.name}")
          private String appName;
      
          // 注入默认值(如果配置文件中没有app.version,则使用默认值1.0.0)
          @Value("${app.version:1.0.0}")
          private String appVersion;
      }
      
  2. 对象类型的注入

    • 使用@Autowired注解

      • @Autowired注解用于自动注入对象类型的属性。默认按类型(byType)进行注入

      • @Service
        public class UserService {
        
            @Autowired
            private UserRepository userRepository;
        
            public void doSomething() {
                userRepository.save();
            }
        }
        
        @Repository
        public class UserRepository {
            public void save() {
                System.out.println("User saved!");
            }
        }
        
    • 使用@Qualifier注解

      • 如果有多个相同类型的Bean,可以使用@Qualifier注解指定具体的Bean名称

      • @Service
        public class UserService {
        
            @Autowired
            @Qualifier("userRepositoryImpl")
            private UserRepository userRepository;
        }
        
        @Repository("userRepositoryImpl")
        public class UserRepositoryImpl implements UserRepository {
            public void save() {
                System.out.println("User saved by UserRepositoryImpl!");
            }
        }
        
        @Repository("anotherUserRepository")
        public class AnotherUserRepository implements UserRepository {
            public void save() {
                System.out.println("User saved by AnotherUserRepository!");
            }
        }
        
  3. 集合类型的注入

    • 普通值类型集合的注入

    • 对象集合类型的注入

      • 可以直接注入一个ListSet,Spring会自动将所有匹配的Bean注入到集合中

      • @Service
        public class MyService {
        
            @Autowired
            private List<UserRepository> userRepositories;
        
            @Autowired
            private Set<UserRepository> userRepositorySet;
        }
        
        @Repository
        public class UserRepositoryImpl implements UserRepository {
            public void save() {
                System.out.println("User saved by UserRepositoryImpl!");
            }
        }
        
        @Repository
        public class AnotherUserRepository implements UserRepository {
            public void save() {
                System.out.println("User saved by AnotherUserRepository!");
            }
        }
        
      • 可以注入一个Map,其中键是Bean的名称,值是Bean的实例

        • @Service
          public class MyService {
          
              @Autowired
              private Map<String, UserRepository> userRepositoryMap;
          }
          

Autowired和Resource 注解

  1. @Autowired 注解

    • @Autowired 是 Spring 框架提供的注解,用于实现依赖注入。它可以标注在字段、构造方法、Setter 方法或普通方法上,Spring 会根据类型自动匹配并注入 Bean

    • 注入规则

      • 按类型注入@Autowired 默认根据类型(byType)进行注入。如果容器中存在多个相同类型的 Bean,Spring 会抛出 NoUniqueBeanDefinitionException 异常。

      • 解决歧义:如果有多个相同类型的 Bean,可以通过以下方式解决:

        • 使用 @Qualifier 注解指定 Bean 的名称。

        • @Autowired
          @Qualifier("myRepositoryImpl")
          private MyRepository myRepository;
          
        • 将目标 Bean 标记为 @Primary,表示优先注入

        • @Primary
          @Repository
          public class MyRepositoryImpl implements MyRepository {
              // 实现
          }
          
    • 其他特性

      • required 属性@Autowired 默认是必须注入的(required=true),如果找不到匹配的 Bean,会抛出异常。可以通过 required=false 设置为非必须注入。

      • @Autowired(required = false)
        private MyRepository myRepository;
        
      • 构造方法注入推荐:Spring 官方推荐使用构造方法注入,因为它可以保证依赖不可变,并且更容易进行单元测试。

  2. @Resource 注解

    • @Resource 是 Java 标准注解(javax.annotation.Resource),Spring 也支持它。它的作用与 @Autowired 类似,但注入规则不同

    • 特点

      • 按名称注入@Resource 默认根据名称(byName)进行注入。如果未指定名称,则根据字段名或方法名匹配 Bean 的名称。

        @Component
        public class MyController {
            @Resource(name = "myService") // 显式指定名称
            private MyService service;
        
            public void execute() {
                service.doSomething();
            }
        }
        
        @Component
        public class MyController {
            @Resource // 未指定名称
            private MyService myService; // 字段名为 myService
        
            public void execute() {
                myService.doSomething();
            }
        }
        
      • 按类型注入:如果未找到匹配名称的 Bean,则会退回到按类型(byType)注入。

      • 不支持构造方法注入@Resource 不能用于构造方法注入。

      • required 属性@Resource 没有 required 属性,如果找不到匹配的 Bean,会抛出异常

posted @ 2025-03-18 14:38  QAQ001  阅读(64)  评论(0)    收藏  举报