• Spring的@Configuration、@Bean、@Conponent 和 @ComponentScane


            这几日通过编写后端程序,突然对以上几个注解产生点迷糊,一直在懂与不懂得边缘游走。今天特写一篇文章,帮助我以及其他遇到此问题得小伙伴排忧解难。

    一、@Configuration、@Conponent 

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

    而 @Conponent 修饰的类不会被代理,每实例化一次就会创建一个新的对象。

    1、实现的细节。

    Configuration注解源码如下:

    1. @Target(ElementType.TYPE)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Component
    5. public @interface Configuration {
    6. String value() default "";
    7. }

    Component注解源码如下:

    1. @Target({ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Indexed
    5. public @interface Component {
    6.     String value() default "";
    7. }


    从定义来看, @Configuration 注解本质上还是 @Component,因此 或者 @ComponentScan 都能处理@Configuration 注解的类。

    1、@Configuration 中所有带 @Bean 注解的方法都会被动态代理(cglib),因此调用该方法返回的都是同一个实例

    2、@Conponent 修饰的类不会被代理,每实例化一次就会创建一个新的对象。

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

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

    2、加载过程

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

    因此我们在@Configuration注解定义的 bean 方法中可以直接调用方法,不需要@Autowired注入后使用。

    3、@Component注解

    1、@controller 控制器(注入服务)
    2、@service 服务(注入dao)
    3、@repository dao(实现dao访问)
    4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的

    1、@controller 控制器(注入服务)
            用于标注控制层,相当于struts中的action层

    2、@service 服务(注入dao)
            用于标注服务层,主要用来进行业务的逻辑处理

    3、@repository(实现dao访问)
            用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.

    4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的 

            泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。

    说明: 
     
    上面的这个例子是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。 
    共同点:被@controller 、@service、@repository 、@component 注解的类,都会把这些类纳入进spring容器中进行管理

    4、区别

    @Configuration 注解定义的 bean 方法中可以直接调用方法,不需要 @Autowired 注入后使用。

    因为源码是直接调用CGlib动态代理的代理类,obtainBeanInstanceFromFactory 方法比较简单,就是通过 beanFactory.getBean 获取 Country,如果已经创建了就会直接返回,如果没有执行过,就会通过 invokeSuper 首次执行。
     

    二、Bean注解


    Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。

    value: name属性的别名,在不需要其他属性时使用,也就是说value 就是默认值
    name: 此bean 的名称,或多个名称,主要的bean的名称加别名。如果未指定,则bean的名称是带注解方法的名称。如果指定了,方法的名称就会忽略,如果没有其他属性声明的话,bean的名称和别名可能通过value属性配置。

    1、@Bean的“full”模式和“lite”模式

    在一般常见情况下,@Bean注解在@Configuration类中声明,称之为“full”模式;

                                    当@Bean注解和@Component注解组合使用时,称之为“lite”模式。

    2、差异

    如果只是把@Bean注解用在方法上,并且各个@Bean注解的方法之间没有调用,上述两种模式达到的效果基本相同,都可以把@Bean注解方法返回的对象作为bean注册到容器中。

    如果各个@Bean注解的方法之间有相互调用,那么两种模式就会有很大的区别-与full模式下的@Configuration不同,lite模式下 @Bean方法互相调用无法声明Bean之间的依赖关系。

    这点在@Bean注解源码注释上也有说明。

    1. @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. public @interface Bean {
    5. @AliasFor("name")
    6. String[] value() default {};
    7. @AliasFor("value")
    8. String[] name() default {};
    9. Autowire autowire() default Autowire.NO;
    10. String initMethod() default "";
    11. String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
    12. }

    综上所述,在使用@Bean注解时需要注意两种模式的区别,一般情况下@Bean都是和@Configuration注解搭配使用的。

    @Configration 注解和@Bean 注解的区别:

    • @Configration 注解:声明当前类是一个配置类,相当于 Spring 中的一个 XML 文件
    • @Bean 注解:作用在方法上,声明当前方法的返回值是一个 Bean

    三、@ComponentScan 注解

    @ComponentScan 注解在配置 bean 中进行使用,等同于 XML 配置文件中的 标签

    目的:进行相关注解的扫描(@Component、@Value、@Autowired …)

    基本使用:

    XML 方式:

    注解方式:
    @Configuration
    @ComponentScan(basePackages = "com.yusael.scan")
    public class AppConfig2 {
    }

    排除策略的的使用:

    XML 方式:

        


    注解方式:
    排除特定的注解:type = FilterType.ANNOTATION, value={}
    排除特定的类型:type = FilterType.ASSIGNABLE_TYPE , value={]
    切入点表达式:type = FilterType.ASPECTJ, pattern=""
    正则表达式:type = FilterType.REGEX, pattern=""
    自定义排除策略:type = FilterType.CUSTOM, pattern=""
    @ComponentScan(basePackages = "com.yusael.scan",
                   excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION, value={Service.class}),
                                     @ComponentScan.Filter(type= FilterType.ASPECTJ, pattern = "*..User1")})

    包含策略的使用:

    XML 方式:

        


    注解方式:参数与排除策略中一样

    @ComponentScan(basePackages = "com.yusaael.scan",
                   useDefaultFilters = false,
                   includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value={Service.class})})

    四、参考文献:

    原文链接:https://blog.csdn.net/weixin_43734095/article/details/115947808
    原文链接:https://blog.csdn.net/tiantangdizhibuxiang/article/details/81784878
    原文链接:https://blog.csdn.net/isea533/article/details/78072133

       https://www.jb51.net/article/153430.htm

    原文链接:https://blog.csdn.net/y516369/article/details/127598350

  • 相关阅读:
    安装MinGW win安装gcc
    自定义线程池+countdownlatch
    C++Qt开发——类图结构
    arguments对象
    批量导入SQL Server中的建表、建存储过程和建调度作业的文件
    30天Python入门(第二十五天:深入了解Python中的pandas)
    useEffect
    戴尔PowerEdge服务器R450 RAID配置步骤
    PaddleOCR系列-训练模型并部署android手机
    Debian | 更换 Gnome 至 Xfce4
  • 原文地址:https://blog.csdn.net/m0_57037182/article/details/127746661