zoukankan      html  css  js  c++  java
  • 第02章-装配Bean

    1. Spring配置的可选方案

    • 在XML中进行显式配置;
    • 在Java中进行显式配置;
    • 隐式的bean发现机制和自动装配。

    2. 自动化装配bean

    Spring从两个角度来实现自动化装配:

    组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
    自动装配(autowiring):Spring自动满足bean之间的依赖。

    2.1 创建可被发现的bean

    使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。

    组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。

    启用组件扫描

    • 基于Java @ComponentScan注解启用了组件扫描
    @Configuration
    @ComponentScan(basePackages="soundsystem","video")
    public class CDPlayerConfig { 
    }

    如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。(通过一个空标记接口(remark interface)来这这个工作,是一个很好的实践。)

    2.2 设置组件扫描的基础包

    上面的例子中,所设置的基础包是以String类型表示的。我认为这是可以的,但这种方法是类型不安全(not type-safe)的。除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:

    @Configuration
    @ComponentScan(basePackageClasses = {CDPlayer.class})
    public class CDPlayerConfig { 
    }

    basePackages属性被替换成了basePackageClasses。同时,我们不是再使用String类型的名称来指定包,为basePackageClasses属性所设置的数组中包含了类。这些类所在的包将会作为组件扫描的基础包。

    • 通过XML启用组件扫描
    <context:component-scan base-package="soundsystem" />

    2.3 通过为bean添加注解实现自动装配

    为了声明要进行自动装配,我们可以借助Spring的@Autowired注解.
    @Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上。

    @Autowired
    public void setCompactDisc(CompactDisc cd) {
      this.cd=cd;
    }

    如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属
    性设置为false:

    @Autowired(required = false)
    public CDPlayer(CompactDisc cd){
      this.cd=cd;
    }

    3. 通过Java代码装配bean

    你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。 在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案:Java和XML。

    JavaConfig是配置代码。这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到业务逻辑代码之中。尽管不是必须的,但通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了。

    • 声明简单的bean
    @Bean
    public CompactDisc sgtPeppers() {
      return new SgtPeppers();
    }
    • 借助JavaConfig实现注入
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc) {
      return new CDPlayer(compactDisc);
    }

    通过这种方式引用其他的bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者通过XML来进行配置。

    • 使用方法替代构造器的注入
      需要提醒的是,我们在这里使用CDPlayer的构造器实现了DI功能,但是我们完全可以采用其他风格的DI配置。比如说,如果你想通过Setter方法注入CompactDisc的话,那么代码看起来应该是这样的:
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc) {
      CDPlayer cdPlayer = new CDPlayer(compactDisc);
      cdPlayer.setCompactDisc(compactDisc);
      return cdPlayer;
    }

    4. 通过XML装配bean

    • 声明一个简单的<bean>
    <bean class="soundsystem.SgtPeppers"/>
    • 借助构造器注入初始化bean
    <bean id="cdPlayer" class="soundsystem.CDPlayer">
            <constructor-arg ref="compactDisc"/>
    </bean>
    • 使用方法替代构造器的注入
    <bean id="cdPlayer"  class="soundsystem.CDPlayer">
            <property name="compactDisc" ref="compactDisc"/>
    </bean>

    <property>元素为属性的Setter方法所提供的功能与<constructor-arg>元素为构造器所提供的功能是一样的。

    • 将字面量注入到属性中
      有Java对象如下:
    public class BlankDisc implements CompactDisc {
    
      private String title;
      private String artist;
      private List<String> tracks;
    
      public BlankDisc(String title, String artist, List<String> tracks) {
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
      }
    
      public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for (String track : tracks) {
          System.out.println("-Track: " + track);
        }
      }
    
    }

    可用以下xml将字面值(StringList<String>)注入到属性中:

    <bean id="compactDisc"
          class="soundsystem.properties.BlankDisc">
      <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
      <property name="artist" value="The Beatles" />
      <property name="tracks">
        <list>
          <value>Sgt. Pepper's Lonely Hearts Club Band</value>
          <value>With a Little Help from My Friends</value>
          <value>Lucy in the Sky with Diamonds</value>
          <value>Getting Better</value>
          <value>Fixing a Hole</value>
          <value>She's Leaving Home</value>
          <value>Being for the Benefit of Mr. Kite!</value>
          <value>Within You Without You</value>
          <value>When I'm Sixty-Four</value>
          <value>Lovely Rita</value>
          <value>Good Morning Good Morning</value>
          <value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
          <value>A Day in the Life</value>
        </list>
      </property>
    </bean>

    5. 导入和混合配置

    5.1 在JavaConfig中引用XML配置

    • Java配置
    @Configuration
    public class CDPlayerConfig {
    
      @Bean
      public CDPlayer cdPlayer(CompactDisc compactDisc) {
        return new CDPlayer(compactDisc);
      }
    
    }
    • XML配置
    <bean id="compactDisc"
          class="soundsystem.BlankDisc"
          c:_0="Sgt. Pepper's Lonely Hearts Club Band"
          c:_1="The Beatles">
      <constructor-arg>
        <list>
          <value>Sgt. Pepper's Lonely Hearts Club Band</value>
          <value>With a Little Help from My Friends</value>
          <value>Lucy in the Sky with Diamonds</value>
          <value>Getting Better</value>
          <value>Fixing a Hole</value>
          <!-- …other tracks omitted for brevity… -->
        </list>
      </constructor-arg>
    </bean>

    以上xml配置中使用了c命名空间,这里_0,_1相当与第一个参数和第二个参数。

    • 在Java配置中引入XML配置
      两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。代码如下:
    @Configuration
    @Import(CDPlayerConfig.class)
    @ImportResource("classpath:cd-config.xml")
    public class SoundSystemConfig {
    
    }

    @Import将两个配置类组合在一起;
    @ImportResource可在JavaConfig中引入XML配置;
    以上代码是利用一个新的Java配置类,引入了已有的Java配置类以及XML配置文件。当然也可以在已有的Java配置类中直接引入XML配置文件。

    5.2 在XML配置中引用JavaConfig

    • Java配置
    @Configuration
    public class CDConfig {
      @Bean
      public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    }
    • XML配置
    <bean id="cdPlayer"
          class="soundsystem.CDPlayer"
          c:cd-ref="compactDisc" />
    • 在XML配置中引入Java配置
    <bean class="soundsystem.CDConfig" />
    
    <bean id="cdPlayer"
          class="soundsystem.CDPlayer"
          c:cd-ref="compactDisc" />

    以上代码是在已有的XML配置文件中引入Java配置类,当然可以建立一个新的XML引入已有的XML配置文件和已有的Java配置类,如:

    <bean class="soundsystem.CDConfig"/>
    <import resource="cdplayer-config.xml"/>
    

    XML配置文件应用已有XML配置文件使用<import resource>标签。

    注意

    不管使用JavaConfig还是使用XML进行装配,我通常都会创建一个根配置(root configuration),也就是这里展现的这样,这个配置会将两个或更多的装配类和/或XML文件组合起来。我也会在根配置中启用组件扫描(通过<context:component-scan>或@ComponentScan)。

    Spring 3的一些内容

    1、装配wiring,即创建应用对象之间的协作关系的行为,者也是依赖注入的本质。
    2、创建Spring配置
    从Sring3.0开始,Spring容器提供了两种配置Bean的方式:

    XML文件配置方式
    基于Java注解的配置方式

    3、典型的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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>

    beans命名空间不是唯一的Spring命名空间,Spring核心框架自带了10个命名空间配置,如下:

    4、当Spring容器加载Bean时,Spring使用反射来创建Bean。

    5、覆盖Spring默认的单例配置:Spring Bean默认都是单例,但有时我们每次都需要获得唯一的Bean实例,比如每个人的门票要唯一:
    我们只需要配置Bean的scope属性为prototype即可:
    1

    Spring提供的作用域选项:

    6、初始化和销毁Bean
    Auditorium(舞台)要保证做的最先和最后两件事情:
    开灯,关灯。

    需要在Bean中使用init-method和destory-method属性:

    当有很多上下文定义的Bean有相同名字的初始化方法和销毁方法时,可以直接在上层beans元素中声明default-init-method和default-destory-method属性,从而避免每一个都要设置一遍的问题。

    最小化Spring XML配置——
    Bean的自动装配(autowiring);
    Bean的自动检测(autodiscovery);

    一、自动装配Bean属性
    1、 4种类型的自动装配
    byName——把与Bean的属性具有相同名字(或ID)的其他Bean自动装配到Bean的对应属性中,名字不匹配则不装配;
    byType——把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中,类型不匹配则不装配;
    constructor——把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中;
    autodetect——首先尝试使用constructor自动装配,若失败,再尝试使用byType进行自动装配。

    2、byName
    原来的装配是这样的:


    当bean的id属性和property属性的name一致时,通过配置autowire属性皆可以自动装配instrument了,修改后的文件如下:

    3、byType自动装配
    byType自动装配的工作方式类似于byName,只不过不再是匹配属性的名字而是检查属性的类型。
    若Instrument类型有多个Bean,Spring就会抛出异常,为解决这个为,需要标识首选的Bean或者取消某个Bean的自动装配候选资格:

    首选Bean
    设置Bean的primary属性为true。但是不幸的是所有的bean的默认primary都是true,因此只能将非首选的Bean的primary属性设置为false:

    取消Bean候选资格
    排除某些Bean是,可设置这些Bean的autowire-candidate属性为false:

    4、constructor自动装配
    通过构造器注入来配置Bean,我们可以移除元素,由Spring在应用上下文中自动选择Bean注入到构造器入参中:

    与byType一样,当发现多个Bean匹配某个构造器入参时,Spring依旧报出异常。

    5、最佳自动装配

    首选constructor自动装配,若没有发现与构造器相匹配的Bean时,Spring将尝试使用byType自动装配。

    6、默认自动装配
    当需要为上下文中的每一个Bean配置相同的上述自动装配autowire属性,可以在根目录增加一个default-autowire属性:

    该属性默认none,标示所有Bean都不使用自动装配,除非Bean自己配置了autowire属性。
    另外,种配置的autowire属性可以覆盖根元素的默认自动装配策略——混合策略。
    混合策略对构造器有所限制:不能混合使用constructor自动装配策略和元素。

    二、使用注解装配
    注解方式允许更细粒度的自动装配,可以选择性地标注某一个属性来对其应用自动装配。
    Spring容器默认禁止注解装配,最简单的启用方式是使用Spring的context命名空间配置中的元素。

    注解,可以为Spring属性、方法和构造器进行自动装配,因此要写在这些的上方一行。
    1、@Autowired
    对属性的setter方法进行标注:

    Spring会尝试对该方法执行byType自动装配。
    除了setter方法,@Autowired可以标注需要自动装配Bean引用的任何方法、构造器。


    甚至可以使用@Autowired直接标注属性,并删除setter方法:

    但是,简单的@Autowired标注有两种麻烦——没有bean或者多个bean:

    没有bean
    当属性是可选的,而bean不存在时,可以使用required属性:
    @Autowired(required=false)
    多个bean【限定歧义性的依赖】
    为帮助@Autowired鉴别哪一个Bean才是我们想要的,可配合使用Spring的@Qualifier注解,该注解可以包含一个字符串作为Bean的标识(标识不一定是id)。
    如将一个id为guitar的乐器装配到instrument属性中:

    注意,上述的guitar可以在xml中对的id属性设置;
    另外,可以不用id属性,而是在中以qualifier子元素(子元素vs属性)中写明,或者在Guitar类上标注:


    若是Qualifier含义不是那么明确或者范围过大,可以自定义Qualifier接口,以代替Qualifier:


    2、借助@Inject实现基于标准的自动装配
    JCP(Java Community Process)发布Java依赖注入规范——JSR-330,@Inject注解是JSR-330的核心部件。
    》note: JDK中并没有JSR-330的实现,需要下载响应的jar依赖包http://mvnrepository.com/artifact/javax.inject/javax.inject

    @Inject
    和@Autowired一样,@Inject可以自动装配属性、方法和构造器,但是没有required属性,即@Inject注解所标注的依赖关系必须存在,否则会报出异常。
    与@Autowired对应的@Qualifier类似,@Inject对应@Name注解。
    @Inject本身也有@Qualifier注解,但是不推荐使用,而是推荐自定义限定器注解。

    3、在注解中使用表达式
    String类型以及基本类型的属性,可以直接通过@Value的方式填入值。但是这相当于硬编码,与直接写在代码中没多大区别,因此不推荐使用,如一首歌名Eruption:

    但是@Value可以使用SpEL表达式,获取系统属性,功能强大:

    三、自动检测Bean
    = +自动检测和定义Bean。
    自动检测可以免去的定义,是的Spring应用中的大多数甚至所有Bean实现定义【厉害啊】和装配。
    元素即负责Spring的自动检测Bean和定义Bean。
    【vs ,该元素有助于消除Spring配置中的元素,但是依旧需要显示定义】
    使用代替 元素:

    那么,哪些类需要注册为Spring的Bean呢?
    1、为自动检测标注Bean
    默认地,查找使用“构造型(stereotype)”注解所标注的类,这些特殊的注解如下:

    如,对一个类注解@Component:

    那么Spring扫描到Guitar,会自动将它注册为Spring Bean,该Bean的ID默认为无限定类名(何为无限定?)——guitar。

    2、过滤组件扫描
    通过为配置子元素,我们可以随意调整扫描行为。如自动注册所有的Instrument实现类:


    的type和expression属性一起协作来定义组件扫描策略。

    不过,默认的基于注解的过滤策略是最经常用的。

    四、使用Spring基于Java的配置
    1、创建基于Java的配置
    Spring的Java配置可以不用XML就可以编写大多数的Spring配置,但是还是需要极少量的XML来启动Java配置。就是说,XML总要有的。

    Spring在base-package指定的包内查找使用@Configuration注解所标注的所有类。

    2、定义一个配置类
    使用@Configuration注解的Java类,就等价于XML配置中的元素,可以在改类内部定义@Bean方法了。

    声明的方法示例如下,将得到ID为方法名的Bean:

    优点:Spring的基于Java的配置中,并没有String属性,Bean的ID和类型都被是否方法签名的一部分,所以可以进行编译期检查来确保Bean的类型是合法类型,并且Bean的ID是唯一的。
    vs XML配置:Bean的类型和ID都是由String属性标示的,String标识符的缺点是它们无法进行编译期检查,如果重命名了Juggler类,或许会忘记修改相应的XML配置!
    智能:其他Bean的声明调用另一个Bean时,Spring都会拦截该方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新的实例。

    源码

    自动配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-autoconfig
    Java配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-javaconfig
    XML配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-xmlconfig
    混合配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-mixedconfig

  • 相关阅读:
    关于事务
    jquery弹出框
    ??(怕忘记 特此记录)
    .net事务
    揭开iphone4 4S 5 之间的内幕!这次你们该相信了吧!
    net得到当前时间
    aspnet ajax2.0下载安装包 msi
    jquery css 逐渐增加div的大小
    DataTable转换为Json对象
    安装EntityFramework
  • 原文地址:https://www.cnblogs.com/myitroad/p/9297771.html
Copyright © 2011-2022 走看看