zoukankan      html  css  js  c++  java
  • 基于注解的自动配置

    经过前文的学习,我们已经知道怎样基于XML和Java进行显式配置。与此同时,我们也惊人地发现显式配置格外麻烦。我们必须写好配置文件,把需要创建哪些Bean的信息一个不差地填进配置文件里。这样,Spring应用上下文才能读取配置文件创建Bean。若是需要创建的Bean不多,只有十个,二十个还好;若是需要创建的Bean很多,有一千个,两千个,甚至更多。这时,把这些Bean的创建信息一个不差地填进配置文件里就难免繁杂了。

    那么,有没有什么办法能够解决这个问题,让事情优雅起来,简单起来呢?

    当然有的。比如,基于注解的自动配置就能优雅地解决这个问题,让事情变得简单。至于基于注解的自动配置有多自动,从而能够简化配置;不妨让我们紧接前文实现的music-player,看看改用基于注解的自动配置能使配置简化多少,进而学习基于注解的自动配置的基础知识。为此,请打开music-player项目,修改AppConfig配置类如下:

    1 package com.dream;
    2 
    3 import org.springframework.context.annotation.*;
    4 
    5 @Configuration
    6 @ComponentScan(basePackages="com.dream")
    7 public class AppConfig {
    8 }

    瞧,那些关于如何创建Bean的配置方法一个不剩,全没了!却见类上除了@Configuration注解之外,还带有一个神秘的@ComponentScan注解。

    这是怎么回事呢?

    原来,基于注解的自动配置对配置类没那么多要求,只要加上@ComponentScan注解就够了。至于那些关于如何创建Bean的配置方法,基于注解的自动配置是一个也不需要的。于是问题来了,@ComponentScan到底是什么样的注解?为什么它的功能如此强大,简简单单一句注解就能搞定配置?

    其实,@ComponentScan注解只是启用了组件扫描,别的事情一件也没做。因此,@ComponentScan注解有个常用的basePackages属性,用于指定需要扫描的包。需要扫描的包可以同时指定多个,不同的包之间用逗号隔开就行。Spring应用上下文加载配置类之后如果发现配置类带有@ComponentScan注解,就会扫描组件。扫描组件之前会先看一下basePackages属性的值。如果basePackages属性无值就扫描配置类所在的包;如果basePackages属性有值就扫描该值指定的包。

    于是我们知道了,AppConfig配置类上的@ComponentScan(basePackages="com.dream")注解只是启用了组件扫描,告诉Spring应用上下文扫描com.dream包,找出包里的所有组件。重点在于,找出所有组件之后呢?Spring应用上下文能否自动创建和装配Bean?如果Spring应用上下文真能自动创建和装配Bean,又是依据什么进行的呢?还有,组件是什么?带着这些问题,让我们修改一下Music类和Player类,如下:

     1 package com.dream;
     2 
     3 import org.springframework.beans.factory.annotation.*;
     4 import org.springframework.stereotype.*;
     5 
     6 @Component(value = "music")
     7 public class Music {
     8     private String musicName = null;
     9 
    10     public String getMusicName() {
    11         return this.musicName;
    12     }
    13 
    14     @Value(value="执着")
    15     public void setMusicName(String musicName) {
    16         this.musicName = musicName;
    17     }
    18 }
     1 package com.dream;
     2 
     3 import org.springframework.beans.factory.annotation.*;
     4 import org.springframework.stereotype.*;
     5 
     6 @Component(value = "player")
     7 public class Player {
     8     private Music music = null;
     9 
    10     public Music getMusic() {
    11         return this.music;
    12     }
    13 
    14     @Autowired(required = true)
    15     public void setMusic(Music music) {
    16         this.music = music;
    17     }
    18 
    19     public void play() {
    20         var musicName = this.music.getMusicName();
    21         var musicMessage = String.format("开始播放音乐《%s》", musicName);
    22         System.out.println(musicMessage);
    23     }
    24 
    25     public void pause() {
    26         var musicName = this.music.getMusicName();
    27         var musicMessage = String.format("暂停播放音乐《%s》", musicName);
    28         System.out.println(musicMessage);
    29     }
    30 }

    可以看到,Music类和Player类带有这些注解:
    1.Music类带有@Component注解。
    2.Music类的setMusicName方法带有@Value("执着")注解。
    3.Player类带有@Component注解。
    4.Player类的setMusic方法带有@Autowired(required = true)注解。

    这是怎么回事呢?

    原来,Spring应用上下文加载配置类之后如果发现类上带有@ComponentScan注解,就会扫描指定的包,找出包里所有带有@Component注解的类。这些带有@Component注解的类就是组件。之后,Spring应用上下文通过反射技术调用类的默认构造函数创建Bean。这些Bean的id默认是类名的第一个字母变成小写之后的字符串。当然,我们也可设置@Component注解的value属性指定Bean的id。

    于是我们知道了,组件扫描的目的是发现组件,创建Bean。那么,Bean的装配又是怎么进行的呢?

    这就涉及@Value注解和@Autowired注解了。众所周知,Bean的装配分为两种:一种是字面量值装配;一种是对象装配。Spring应用上下文扫描组件之后,如果发现组件的方法带有@Value注解,就会进行字面量值的自动装配。如果发现组件的方法带有@Autowired注解,就会进行对象的自动装配,看看带有@Autowired注解的方法需要什么类型的Bean,再从Spring应用上下文里找到这种类型的Bean自动装配上去。

    因此,@Value注解有个常用的value属性。这个属性是字符串类型的,用于指定字面量值。这样,Spring应用上下文读到@Value注解的value属性之后,就能进行字面量的自动装配了。@Autowired注解有个常用的required属性。这个属性是布尔类型的,用于指定对象的装配是不是必须的。当required属性的值等于TRUE时,对象的装配是必须的。如果Spring应用上下文找不到相应的Bean进行装配,就会抛出org.springframework.beans.factory.NoSuchBeanDefinitionException类型的异常;当required属性的值等于FALSE时,对象的装配不是必须的。如果Spring应用上下文找不到相应的Bean进行装配,则不进行装配。required属性的默认值是TRUE。

    于是我们知道了,Music类和Player类之所以带有@Component注解,是为了能被组件扫描发现。Music类的setMusicName方法之所以带有@Value("执着")注解,是为了把“执着”这个字面量值装配进去。Player类的setMusic方法之所以带有@Autowired注解,是为了让Spring应用上下文找到类型为Music的对象之后装配进去。

    非常明显,基于注解的自动配置分为两步:第一步是组件扫描(Component Scanning),第二步是自动装配(Auto Wiring)。Spring应用上下文加载配置类之后,发现配置类带有@ComponentScan注解,于是启用组件扫描从basePackages属性指定的包里找到所有组件,应用反射技术调用类的默认构造函数创建Bean。之后,Spring应用上下文开始自动装配。通过带有@Value注解的方法进行字面量值的自动装配;通过带有@Autowired注解的方法进行对象的自动装配。于是,基于注解的自动配置完成了。

    同时我们也应看到,基于注解的自动配置是通过配置文件启用组件扫描的。这个配置文件可以是Java配置类,自然也可以是XML配置文件。比如,就music-player这个项目而言,如果采用XML启用组件扫描,则可修改app-config.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"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.dream" />
    
    </beans>

    正如大家所料。那些关于如何创建Bean的配置信息一个不剩,全没了!却多了以下两样东西:
    1.XML模式文件http://www.springframework.org/schema/context/spring-context.xsd
    2.XML元素<context:component-scan base-package="com.dream" />

    spring-context.xsd模式文件定义了哪些XML元素可以用来配置Spring应用上下文。<context:component-scan base-package="com.dream" />正是spring-context.xsd模式文件定义的一个元素,用于启用组件扫描。其用法与@ComponentScan注解是一样的,这里不再赘述。

    于是我们知道了,Spring提供了两种配置方式:一种是显式配置;一种是自动配置。显式配置通过XML或Java显式描述Bean的创建信息,再由Spring应用上下文根据具体的配置信息进行Bean的创建和装配。因此,显式配置分为两种:一种是基于XML的显式配置,通常也叫通过XML进行配置;一种是基于Java的显式配置,通常也叫通过Java进行配置。自动配置由组件扫描和自动装配两部分组成。我们需用Java配置类或XML配置文件启用组件扫描,再在类里添加注解,告诉Spring应用上下文哪些类是组件以及Bean应该怎么装配。这样,Spring应用上下文扫描组件之后就能进行Bean的创建和装配了。因此,自动配置是一种基于注解的自动配置,通常也叫通过注解进行配置。

    至此,关于配置的基础知识介绍完了。想必大家还有很多困惑。比如关于自动装配,当Spring应用上下文里存在多个相同类型的对象时,Spring应用上下文怎么知道应该选用哪个对象进行装配呢?讲清诸如这样的问题需要花些篇幅,将在“细说Spring”的时候再行讨论。现在,让我们开启新的征程,先来看看Spring是怎样简化JDBC的。

    返回目录    下载代码

  • 相关阅读:
    RvmTranslator7.3.2
    PipeCAD
    Open CASCADE Technology 7.5.0 released
    IsoAlgo 环路处理
    OD流向地图的绘制——利用ArcGIS与Gephi方法
    Python调用百度地图和高德地图API批量获取国内城市地址经纬度坐标
    ArcGIS地理数据库Geodatabase
    Gephi 安装与简明教程
    安装Java SDK
    ArcGIS中自定义脚本工具制作
  • 原文地址:https://www.cnblogs.com/evanlin/p/15455798.html
Copyright © 2011-2022 走看看