面试官:@Configuration 和 @Component 注解的区别?大部分人都会答错!

简介: 面试官:@Configuration 和 @Component 注解的区别?大部分人都会答错!

一句话概括就是 @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。


理解:调用@Configuration类中的@Bean注解的方法,返回的是同一个示例;而调用@Component类中的@Bean注解的方法,返回的是一个新的实例。


注意:上面说的调用,而不是从spring容器中获取! 见最下面的示例 1 及 示例 2


下面看看实现的细节。


@Configuration 注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

从定义来看, @Configuration注解本质上还是@Component,因此 <context:component-scan/> 或者 @ComponentScan 都能处理@Configuration注解的类。


@Configuration标记的类必须符合下面的要求:


配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。

配置类不能是final 类(没法动态代理)。

配置注解通常为了通过 @Bean注解生成 Spring 容器管理的类,

配置类必须是非本地的(即不能在方法中声明,不能是 private)。

任何嵌套配置类都必须声明为static。

@Bean方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)。

@Bean 注解方法执行策略

推荐一个开源免费的 Spring Boot 最全教程:


https://github.com/javastacks/spring-boot-best-practice


先给一个简单的示例代码:


@Configuration

public class MyBeanConfig {
    @Bean
    public Country country(){
        return new Country();
    }
    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country());
    }
}


相信大多数人第一次看到上面 userInfo() 中调用 country()时,会认为这里的 Country和上面@Bean方法返回的 Country 可能不是同一个对象,因此可能会通过下面的方式来替代这种方式:


@Autowired

private Country country;

实际上不需要这么做(后面会给出需要这样做的场景),直接调用country()方法返回的是同一个实例。


@Component 注解

@Component注解并没有通过 cglib 来代理@Bean 方法的调用,因此像下面这样配置时,就是两个不同的 country。


@Component

public class MyBeanConfig {
    @Bean
    public Country country(){
        return new Country();
    }
    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country());
    }
}



有些特殊情况下,我们不希望 MyBeanConfig被代理(代理后会变成WebMvcConfig$$EnhancerBySpringCGLIB$$8bef3235293)时,就得用 @Component,这种情况下,上面的写法就需要改成下面这样:


@Component

public class MyBeanConfig {
    @Autowired
    private Country country;
    @Bean
    public Country country(){
        return new Country();
    }
    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country);
    }
}



这种方式可以保证使用的同一个 Country 实例。


示例 1:调用@Configuration类中的@Bean注解的方法,返回的是同一个示例


第一个bean类


package com.xl.test.logtest.utils;
public class Child {
 private String name = "the child";
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}



第二个bean类


package com.xl.test.logtest.utils;
public class Woman {
 private String name = "the woman";
 private Child child;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Child getChild() {
  return child;
 }
 public void setChild(Child child) {
  this.child = child;
 }
}






@Configuration类


package com.xl.test.logtest.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
//@Component
public class Human {
 @Bean
 public Woman getWomanBean() {
  Woman woman = new Woman();
  woman.setChild(getChildBean()); // 直接调用@Bean注解的方法方法getChildBean()
  return woman;
 }
 @Bean
 public Child getChildBean() {
  return new Child();
 }
}



测试类 I


本测试类为一个配置类,这样启动项目是就可以看到测试效果,更加快捷;也可以使用其他方式测试见下面的测试类 II


package com.xl.test.logtest.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Man {
 @Autowired
 public Man(Woman wn, Child child) {
  System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  System.out.println(wn.getChild() == child ? "是同一个对象":"不是同一个对象");
 }
}


启动项目,查看输出结果:


image.png


测试类 II


package com.xl.test.logtest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xl.test.logtest.utils.Child;
import com.xl.test.logtest.utils.Woman;
@RestController
public class LogTestController {
 @Autowired
 Woman woman ;
 @Autowired
 Child child;
 @GetMapping("/log")
 public String log() {
  return woman.getChild() == child ? "是同一个对象":"不是同一个对象";
 }
}



浏览器访问项目,查看结果;输入localhost:8080/log


image.png


示例 2 :调用@Component类中的@Bean注解的方法,返回的是一个新的实例。


测试代码,只需要将@Configuration改为@Component即可!其他的均不变


package com.xl.test.logtest.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//@Configuration
@Component
public class Human {
 @Bean
 public Woman getWomanBean() {
  Woman woman = new Woman();
  woman.setChild(getChildBean()); // 直接调用@Bean注解的方法方法getChildBean()
  return woman;
 }
 @Bean
 public Child getChildBean() {
  return new Child();
 }
}





测试 :


image.png


控制台和浏览器展示,均符合预期!


原文:blog.csdn.net/qq_29025955/article/details/128818957



相关文章
|
12天前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
29天前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
1月前
|
编译器
经典面试题:变量的声明和定义有什么区别
在编程领域,变量的“声明”与“定义”是经典面试题之一。声明告诉编译器一个变量的存在,但不分配内存,通常包含变量类型和名称;而定义则为变量分配内存空间,一个变量必须至少被定义一次。简而言之,声明是告知变量形式,定义则是实际创建变量并准备使用。
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
109 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
1月前
|
前端开发 小程序 JavaScript
面试官:px、em、rem、vw、rpx 之间有什么区别?
面试官:px、em、rem、vw、rpx 之间有什么区别?
36 0
|
2月前
|
Java 关系型数据库 MySQL
面试官:GROUP BY和DISTINCT有什么区别?
面试官:GROUP BY和DISTINCT有什么区别?
88 0
面试官:GROUP BY和DISTINCT有什么区别?
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
6天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
8天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
27 4
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
66 2