Spring中@Component和@Bean的区别

本文打算介绍几个不太容易说出其区别,或者用途的 Spring 注解,比如 @Component 与 @Bean 的比较,@ControllerAdvice 是如何处理自定义异常的等等。

1.Configuration注解

@Configuration这个注解可以加在类上,让这个类的功能等同于一个bean xml配置文件,如下:

@Configuration
public class ConfigBean {

}

上面代码类似于下面的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
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

</beans>

通过AnnotationConfigApplicationContext来加载@Configuration修饰的类,如下:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigBean.class);

此时ConfigBean类中没有任何内容,相当于一个空的xml配置文件,此时我们要在ConfigBean类中注册bean,那么我们就要用到@Bean注解了。

总结

@Configuration使用步骤:

在类上使用@Configuration注解

通过AnnotationConfigApplicationContext容器来加@Configuration注解修饰的类

2. @Bean注解

在Spring框架中,一旦你通过@Bean注解方法注册了一个Bean,你就可以在应用程序的其他部分通过依赖注入(Dependency Injection, DI)来使用它。下面是一个详细的例子,展示了如何创建、配置和使用Bean。

首先,创建一个简单的Java类,我们称之为MyBean:

public class MyBean {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

然后,创建一个配置类来注册MyBean的Bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyBean myBean() {
        MyBean myBean = new MyBean();
        myBean.setMessage("Hello, World!");
        return myBean;
    }
}

在上述配置类AppConfig中,我们定义了一个名为myBean的方法,并使用@Bean注解标记它。这个方法创建一个MyBean实例,并设置其message属性,然后返回它。

接下来,创建另一个类来使用MyBean:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    private final MyBean myBean;

    @Autowired
    public MyService(MyBean myBean) {
        this.myBean = myBean;
    }

//或者直接@Autowired
//    private final CacheClient cacheClient;

    public void printMessage() {
        System.out.println(myBean.getMessage());
    }
}

注意,必须是有@Component的类才能使用依赖注入,如果是自己new的类,则不能使用@Autowired。

2.1 同类型但不同不同实现方式的bean

在一个大型的Spring应用中,可能会有多个配置类,每个配置类都可能定义了同类型但不同名称的bean。例如,你可能有两个不同的数据源配置,每个数据源配置都创建一个DataSource bean,但每个bean有不同的数据库连接设置。在这种情况下,你会有两个DataSource bean在Spring容器中,需要使用@Qualifier注解来指定你想要注入哪个DataSource bean。

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource1() {
        // ... 创建并返回第一个DataSource
    }

    @Bean
    public DataSource dataSource2() {
        // ... 创建并返回第二个DataSource
    }
}

@Service
public class SomeService {
    
    @Autowired
    @Qualifier("dataSource1")
    private DataSource dataSource;
    // ...
}

2.2 bean的单例和多例

Bean的单例(Singleton)指的是在Spring容器中,一个类型的Bean只会被创建和初始化一次,所有对该类型Bean的请求都会返回同一个实例。这样可以节省资源和提高效率,因为Bean只被创建一次,并在需要时重用。单例是Spring容器的默认作用域。一个spring容器有一个实例。如果有多个spring容器,则即使是单例也会有多个实例。

prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。

在Spring配置中,可以通过scope属性来指定Bean的作用域,例如,将scope设置为singleton(单例)或prototype(原型,每次请求都创建新实例)。

@Configuration
public class AppConfig {

    @Bean
    @Scope("singleton")  // 此行是可选的,因为默认就是单例
    public User user() {
        return new User("John Doe", 25);
    }
}

@Service
public class SomeService {

    @Autowired
    private User user1;  // user1 和 user2 会是同一个实例

    @Autowired
    private User user2;

    // ...
}

在上述例子中,通过@Bean注解定义了一个User类型的bean,在SomeService类中通过@Autowired注解注入了两个User实例user1user2。由于User bean的作用域是单例,user1user2将指向相同的User实例。

注:

@Autowired 注解通常根据类型来自动装配bean。Spring容器会查找与目标字段或参数类型匹配的bean。如果找到多个匹配的bean,它将根据bean的名称或使用@Qualifier注解来确定要使用哪个bean。如果没有找到匹配的bean,或者找到多个匹配的bean但没有指定@Qualifier,Spring会抛出一个异常。

通俗解释看文章:Spring中Bean的单例和多例简单总结_如何查看spring 是单例还是多例-CSDN博客

2.3  为什么一定要使用@Configuration来加载bean

详细见文章:Spring系列第十九讲 @Configuration和@Bean注解详解-腾讯云开发者社区-腾讯云

2.4 在Bean实例中注入其他实例

如果你想在BookService中注入BookRepository,你可以将BookService的构造函数修改为接受BookRepository参数,并在@Bean方法中传递这个参数:

@Configuration
public class AppConfig {
    @Bean
    public BookRepository bookRepository() {
        return new BookRepository();
    }

    @Bean
    public BookService bookService(BookRepository bookRepository) {
        return new BookService(bookRepository);
    }
}

public class BookService {
    private final BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    // ...
}

注意,BookService类没有任何Spring注解,例如@Component@Service,所以它不会被Spring容器管理,也就无法接收到依赖注入。另外,@Autowired注解通常不能应用于非Spring管理的类。

如果一个类没有加注解如@component, @controller, @service等扫描这个类到容器中
在类中的变量加@Autowired注解无法生效。
因为如果一个类new对象生成的,那么这个类就不归spring容器管理,IOC等spring的功能也就无法使用了。

所以想要在没有注解的类中注入,就需要用构造器的方法定义这个注入的类。然后再new这个类的地方进行注入。(详情请参考自定义的stringRedisTemplate)。

3. @Component 和 @Bean 的区别是什么?

@Bean@Component都是Spring框架中用于注册bean的注解,但它们之间有一些重要的区别:

  1. 用途和应用场景

    • @Bean注解通常用于方法,指示Spring框架该方法将返回一个应该注册为bean的对象。它通常用在配置类中,用于创建和配置bean。
    • @Component注解用于类,指示Spring框架该类是一个组件,其实例应该被自动检测和注册为bean。它是一个通用注解,还有一些更具体的变体,如@Service@Repository@Controller
  2. Bean的创建

    • 使用@Bean注解的方法允许你编程式地创建和配置bean。你可以在方法体内包含创建对象和配置属性的逻辑。
    • 使用@Component注解时,Spring会自动为你创建bean的实例,通常是通过调用类的默认构造函数。
  3. 自定义逻辑

    • @Bean注解允许你有更多的控制权和自定义逻辑,因为你可以在方法体中包含任何需要的代码来配置bean。
    • @Component注解主要用于标记类,不提供在bean创建和配置过程中包含自定义逻辑的直接方式。
  4. 命名

    • @Bean注解的方法名通常用作bean的名称,但你也可以通过name属性为bean提供一个自定义名称。
    • @Component注解没有name属性,但你可以使用@Component("customName")为bean提供一个自定义名称。
  5. 依赖注入

    • @Bean注解的方法中,你可以通过方法参数来注入其他的beans。
    • @Component注解的类中,你可以通过构造函数、setter方法或字段来注入其他的beans。
  6. 生命周期回调

    • @Bean注解可以与initMethoddestroyMethod属性一起使用,以指定bean的初始化和销毁方法。
    • @Component注解可以与@PostConstruct@PreDestroy注解一起使用,以指定bean的初始化和销毁方法。

在实践中,你可能会根据具体的需求和上下文来选择使用@Bean@Component。例如,如果你需要更多的控制权和自定义逻辑,可能会选择使用@Bean。如果你想让Spring自动管理bean的创建和注册,可能会选择使用@Component

下面进行详解:

3.1 作用对象不同:@Component 注解作用于类,而 @Bean 注解作用于方法、

@Component 通常是通过路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean 告诉了 Spring 这是某个类的实例,当我们需要用它的时候还给我。

@Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring 容器时,只能通过 @Bean 来实现。

3.2  如果想将一个引入的外部类进行控制反转,只能用@Bean来操作。因为不能去外部类上面加@Component

3.3 @Bean有更强的自定义属性

比如说我有一个类User,需要构造参数name和age。这个User类用@Component修饰。当我需要注入时,使用@Autowired自动装配,我该如何同时传入这两个构造参数

在这种情况下,你可以创建一个配置类并使用@Bean注解方法来提供User实例,同时传递所需的构造参数:

@Configuration
public class AppConfig {

    @Bean
    public User user() {
        return new User("John Doe", 25);
    }
}

@Service
public class SomeService {

    @Autowired
    private User user;
    // ...
}

在上述代码中,AppConfig类定义了一个@Bean注解的user方法,该方法创建一个新的User实例并传递所需的nameage参数。然后,在SomeService类中,通过@Autowired注解自动装配User实例。

这种情况不使用@Component进行装配。

3.4 @Component简化开发

@Component注解主要简化了Bean的注册过程,使开发者不再需要在配置类中手动注册Bean。通过@Component及其派生注解(如@Service, @Repository, @Controller等),Spring可以自动扫描并注册Bean,使配置更为简洁,代码结构更为清晰。同时,它还允许通过构造器、字段或setter方法注入依赖,这样开发者可以更专注于核心业务逻辑,而不是配置代码。

详情如何使用构造器,字段方法注入,见:滑动验证页面

4. @Resource和@Autowired的区别

@Autowired会先按byType去找,如果没找到,则会按照byName去找
@Resource会先按byName去找,如果没找到则会byType去找。如果设置了name属性,则只会按byName去找,找不到就报错。

@Resource(name = "studentServiceImpl")
    private PersonService personService;


什么时候用Autowired、Resource?

Autowired:效率低下,先按类型查找,再按名字查找
Resource:按名字查找,后面要跟参数name,好处:当有多个Impl实现类时,可以通name快速找到

当只有一个Impl实类的时候,随便用哪个都差不多,>=2的时候,最好用@Resource,比@Autowired@Qualifier()效率高

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值