深入理解@component与@Configuration注解

 更新时间:2023年11月02日 10:21:44   作者:四月是你的  
这篇文章主要介绍了深入理解@component与@Configuration注解,从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被扫描,并用于构建bean定义,初始化Spring容器,需要的朋友可以参考下

1、@Configuration

从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

注意:@Configuration注解的配置类有如下要求:

1、@Configuration不可以是final类型;

2、@Configuration不可以是匿名类;

3、嵌套的configuration必须是静态类。

用@Configuration加载spring的用法

@Configuration配置spring并启动spring容器

@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)

@Configuration启动容器+@Bean注册Bean

@Bean下管理bean的生命周期

可以使用基于 Java 的配置来管理 bean 的生命周期。@Bean 支持两种属性,即 initMethod和destroyMethod,这些属性可用于定义生命周期方法。在实例化 bean或即将销毁它时,容器便可调用生命周期方法。生命周期方法也称为回调方法,因为它将由容器调用。使用 @Bean 注释注册的 bean 也支持JSR-250 规定的标准 @PostConstruct 和 @PreDestroy 注释。如果您正在使用 XML 方法来定义bean,那么就应该使用 bean 元素来定义生命周期回调方法。

@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的作用:注册bean对象

@Bean注解在返回实例的方法上,如果未通过@Bean指定bean的名称,则默认与标注的方法名相同; @Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域; 既然@Bean的作用是注册bean对象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注册bean,当然需要配置@ComponentScan注解进行自动扫描。

  • @Configuration启动容器+@Component注册Bean
  • 使用 AnnotationConfigApplicationContext 注册 AppContext 类的两种方法
  • 配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)

2、@component注解

1、@controller 控制器(注入服务)

2、@service 服务(注入dao)

3、@repository dao(实现dao访问)

4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)

如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而用 @Component 对那些比较中立的类进行注释。 在 一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。 Spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了 @Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用 和在xml文件中使用bean节点配置组件时一样的。

说明: <context:component-scan base-package=”com.*”> 上面的这个例子是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。

共同点:被@controller 、@service、@repository 、@component 注解的类,都会把这些类纳入进spring容器中进行管理

3、@configuration和@component之间的区别

@configuration和@component之间的区别是:@Component注解的范围最广,所有类都可以注解,但是@Configuration注解一般注解在这样的类上:这个类里面有@Value注解的成员变量和@Bean注解的方法,就是一个配置类。

展示两个注解的配图

在这里插入图片描述

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

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

  1. 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
  2. 配置类不能是 final类(没法动态代理)。
  3. 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类,配置类必须是非本地的(即不能在方法中声明,不能是private)。
  4. 任何嵌套配置类都必须声明为static。
  5. @Bean方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有@Configuration,也不会被特殊处理,只会作为普通的bean)

加载过程

Spring 容器在启动时,会加载默认的一些PostProcessor,其中就有ConfigurationClassPostProcessor,这个后置处理程序专门处理带有@Configuration注解的类,这个程序会在bean 定义加载完成后,在bean初始化前进行处理。主要处理的过程就是使用cglib动态代理增强类,而且是对其中带有@Bean注解的方法进行处理。

基于Java的配置我们通常使用@Configuration注解来声明Spring Bean 除此之外我们还能使用@Component声明Spring Bean

具体实例验证两者的区别,下面代码使用@configuration注解

@Configuration
public class MyTestConfig {

    @Bean
    public Driver driver(){
        Driver driver = new Driver();
        driver.setId(1);
        driver.setName("driver");
        driver.setCar(car());
        return driver;
    }

    @Bean
    public Car car(){
        Car car = new Car();
        car.setId(1);
        car.setName("car");
        return car;
    }
}

测试代码如下

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {

    @Autowired
    private Car car;

    @Autowired
    private Driver driver;

    @Test
    public void contextLoads() {
        boolean result = driver.getCar() == car;
        System.out.println(result ? "同一个car" : "不同的car");
    }

}

打印结果如下: 同一个car

使用@component注解除Config类上的注解不同之外其他都相同,Spring对两者的处理方式就会完全不一样。

  • @configuration:会像我们期望的一样正常运行,因为new SimpleBeanConsumer(simpleBean())这段代码中simpleBean()方法会由Spring代理执行,Spring发现方法所请求的Bean已经在容器中,那么就直接返回容器中的Bean。所以全局只有一个SimpleBean对象的实例。
  • @component:在执行new SimpleBeanConsumer(simpleBean()) 时simpleBean()不会被Spring代理,会直接调用simpleBean()方法获取一个全新的SimpleBean对象实例所以全局会有多个SimpleBean对象的实

使用Configuration时在driver和spring容器之中的是同一个对象,而使用Component时是不同的对象。 造成不同结果的原因在ConfigurationClassPostProcessor类之中,通过调用enhanceConfigurationClasses方法,为被注解@Configuration的类进行CGLIB代理 虽然Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class,所以在生成Driver对象时和生成Car对象时调用car()方法执行了两次new操作,所以是不同的对象。当时Configuration注解时,生成当前对象的子类Class,并对方法拦截,第二次调用car()方法时直接从BeanFactory之中获取对象,所以得到的是同一个对象。

造成这种差异的原因如下:

如果使用@Configuration,所有用@Bean标记的方法会被包装成CGLIB的wrapper其工作原理是:如果方式是首次被调用那么原始的方法体会被执行并且结果对象会被注册到Spring上下文中。之后所有的对该方法的调用仅仅只是从Spring上下文中取回该对象返回给调用者。

到此这篇关于深入理解@component与@Configuration注解的文章就介绍到这了,更多相关@component与@Configuration注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Maven依赖作用域和依赖传递的使用

    Maven依赖作用域和依赖传递的使用

    本文主要介绍了Maven依赖作用域和依赖传递的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 详解使用spring boot admin监控spring cloud应用程序

    详解使用spring boot admin监控spring cloud应用程序

    本篇文章主要介绍了详解使用spring boot admin监控spring cloud应用程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • MVC AOP面向切面编程简单介绍及实例

    MVC AOP面向切面编程简单介绍及实例

    这篇文章主要介绍了MVC AOP面向切面编程简单介绍及实例的相关资料,需要的朋友可以参考下
    2016-12-12
  • springboot实现定时任务的四种方式小结

    springboot实现定时任务的四种方式小结

    本文主要介绍了springboot实现定时任务的四种方式小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • java 可重启线程及线程池类的设计(详解)

    java 可重启线程及线程池类的设计(详解)

    下面小编就为大家带来一篇java 可重启线程及线程池类的设计(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • SpringBoot基础教程之集成邮件服务

    SpringBoot基础教程之集成邮件服务

    这篇文章主要给大家介绍了关于SpringBoot基础教程之集成邮件服务的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用SpringBoot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-07-07
  • SpringCloud Webflux过滤器增加header传递方式

    SpringCloud Webflux过滤器增加header传递方式

    这篇文章主要介绍了SpringCloud Webflux过滤器增加header传递方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • springboot使用拦截器判断是否登录

    springboot使用拦截器判断是否登录

    这篇文章主要介绍了springboot使用拦截器判断是否登录,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • SpringBoot+Mybatis项目使用Redis做Mybatis的二级缓存的方法

    SpringBoot+Mybatis项目使用Redis做Mybatis的二级缓存的方法

    本篇文章主要介绍了SpringBoot+Mybatis项目使用Redis做Mybatis的二级缓存的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Reactor中的onErrorContinue 和 onErrorResume

    Reactor中的onErrorContinue 和 onErrorResume

    这篇文章主要介绍了Reactor中的onErrorContinue 和 onErrorResume,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-09-09

最新评论