zoukankan      html  css  js  c++  java
  • Spring装配Bean的主要方式总结

    这里写图片描述

    Spring装配Bean有三种主要方式:自动装配、基于Java显示配置和基于XML显示配置。建议使用的是自动装配,一是简单快捷,二是显示配置维护麻烦。但是显示配置在有些场景下是必须的或者高效的,例如想讲第三方库的组件装配到自己的应用中,肯定不能去把第三方的组件类加上注释;或者需要维护别人写的代码,但是他用的是显示配置,如果不了解就无从下手,所以也应该了解spring的显示配置方式。

    1. 自动装配

    用CD和CD播放器举例:spring如何将一个CD类,通过配置装配到CD播放器中。
    这里写图片描述

    @Component声明组件

    通过UML图可以看到,需要做的是把SgtPeppers注入到CDplayer中,所以将这两个类看成是一个组件,spring通过一番操作将他们组合在一起,无论如何将他们组合在一起,第一步我们先把他们都声明成spring能认识的组件,肯定不会错。spring声明组件用的就是@Component。

    @Component
    public class SgtPeppers implements CompactDisc {
    
        private String title = "White Horse";
        private String artist = "Talyor Swift";
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
        }
    }
    

    @Autowired自动装配注解

    和SgtPeppers声明成为组件略微不同的是,CDplayer需要将SgtPeppers注入到其中。所以需要有一个让spring知道,SgtPeppers需要注入到CDplayer,我们常用的注入方式有构造器注入或者是setter方法注入,spring注入的方式也一样,只是通过@Autowired注解让其注入自动完成。

    @Component
    public class CDPlayer implements MediaPlayer {
    
        private CompactDisc cd;
    
        @Autowired(required=false)
        public CDPlayer(CompactDisc cd){
            this.cd = cd;
        }
    
        @Override
        public void play() {
            cd.play();
        }
    
    }

    要注意的是:@Autowired可以注释任何方法,有了这个注释spring会试图创建一个注释了的bean,但如果没有找到bean则会报出异常为了避免异常将@Autowired(required=false)添加false,但添加false避免该异常后,如果没有进行null检查会报NullPointExeception。

    @ComponentScan扫描组件

    刚才创建了两个组件,但是组件扫描默认是不开启的,所以需要我们显示地配置一下spring,先尝试用一个java类来定义spring的装配规则。

    /** 
      * 如果没有其他配置,spring通过以下配置会扫描CDPlayerConfig
      * 所处类下的包的所有子包
    /** 
    @Configuration
    @ComponentScan
    public class CDPlayerConfig {
    
    }

    但如果想要扫描多个基础包呢?

    //扫描多个基础包
    @Configuration
    @ComponentScan(basePackages={"soundsystem","video"})
    public class CDPlayerConfig {
    }

    上述方法扫描的基础包采用String类型的包名,类型不安全,改进采用包下的一个组件类:

    @Configuration
    @ComponentScan(baseClasses={CDPlayer.class,DVDPlayer.class})
    public class CDPlayerConfig {
    }

    当然你可能还会想到,通过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"
      xmlns:c="http://www.springframework.org/schema/c"
      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
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
      <context:component-scan base-package="soundsystem" />
    
    </beans>

    2. JavaConfig装配Bean

    当需要将第三方库中的组件装配到应用中时,是没有办法在他的类上添加@Component或者@Autowired的,所以可以采用javaxml,先来看java代码配置。

    利用java进行配置,我们把用于配置spring的java类成为JavaConfig,他和普通的java类其实是没有多大区别的,但是作为一个配置类,最好遵循以下几个原则,当然不是强制的:

    1. JavaConfig放在同一个包下
    2. 配置代码不侵入业务代码

    还是以上面的CD为例,原本的组件类不再申明为一个组件,去掉@Component,即假设他们是第三方库中的代码,我们无法添加注解

    public class SgtPeppers implements CompactDisc {
    
        private String title = "White Horse";
        private String artist = "Talyor Swift";
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
        }
    }

    那么配置代码中就要做相应改变,配置代码去掉@ComponentScan,并且用@Bean来申明JavaBean

    @Configuration
    public class CDPlayerConfig {
    
        @Bean
        public CompactDisc sgtPeppers(){
            return new SgtPeppers();
        }
    
        /*@Bean
        public CDPlayer cdplayer(CompactDisc compactDisc){
            return new CDPlayer(compactDisc);
        }*/
    
        @Bean
        public CDPlayer cdplayer(){
            return new CDPlayer(sgtPeppers());
        }
    
    }

    这里Bean的注入有两种方法,上面注释掉的是通过参数注入,而下面没有注释的是通过调用方法注入,两种方法都可以但是通过参数注入更加直观,也更加常用。值得注意的是,@Bean的注解可以使用任何必要的Java功能来返回一个bean实例。

    3. XML装配Bean

    还是那句话,推荐使用自动装配和JavaConfig,但是不可避免会用到XML的方式进行spring的配置,因为我们会需要维护别人的代码啊。

    XML申明一个Bean

    <bean id="compactDisc" class="soundsystem.SgtPeppers" />

    其中id是这个bean的别名,一般都会起别名,如果没有id属性,别名默认为“soundsystem.SgtPeppers#0”,#0用于计算区别于其他的Bean。
    

    如果申明一个Bean的过程中需要注入其他的对象,或者对象,可以采用两种方法:一种是采用构造器注入,一种是采用方法注入,两两组合所以有四种实例化的方式:

    1. 构造器注入对象

    <bean id="cdPlayer" class="soundsystem.CDPlayer">
       <constructor-arg ref="compactDisc" />
    </bean>

    还可以采用c名称空间,引入名称空间是为了简写

    <bean id="cdPlayer"
            class="soundsystem.CDPlayer"
            c:_-ref="compactDisc" />

    2. 构造器注入普通属性

    和注入对象稍微有一点差别

      <bean id="compactDisc" class="soundsystem.BlankDisc"
           <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
           <constructor-arg value="The Beatles" />
      </bean>

    名称空间写法

      <bean id="compactDisc"
            class="soundsystem.BlankDisc"
            c:_0="Sgt. Pepper's Lonely Hearts Club Band"
            c:_1="The Beatles">
      </bean>

    3. 方法注入对象

    前面使用构造器注入,这里用setter方法注入,如果JavaBean是这样的,自动使用setter进行注入

    public class CDPlayer implements MediaPlayer {
    
        private CompactDisc cd;
    
        @Autowired
        public void CompactDisc(CompactDisc compactDisc){
            this.CompactDisc = CompactDisc;
        }
    
        @Override
        public void play() {
            cd.play();
        }
    
    }

    相应的XML用property属性来配置,和使用构造器注入是一样的

    <bean id="cdPlayer" class="soundsystem.CDPlayer">
       <property name="compactDisc" ref="compactDisc" />
    </bean>

    当然也可以使用p名称空间

    <bean id="cdPlayer" class="soundsystem.CDPlayer">
       <p:compactDisc-ref="compactDisc" />
    

    4. 方法注入普通值

    其实都以类似的方法,用P名称空间演示

      <bean id="compactDisc"
            class="soundsystem.BlankDisc"
            p:title="Sgt. Pepper's Lonely Hearts Club Band"
            p:artist="The Beatles">
      </bean>

    5. 注入集合不能用名称空间

    名称空间可以简写,但是名称空间不能注入集合,集合的注入是这样的

      <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>

    4. 混合配置

    最后是将JavaConfig的配置同XML配置相互结合如何使用,因为他们是互不排斥的

    1. 在javaConfig中引用xml配置

    所以会有两个需要装配的bean,一个是用过javaConfig装配,另一个是通过xml装配,然后我们用一个JavaConfig装配在一起

    JavaConfig装配的Bean

    @Configuration
    public class CDConfig {
      @Bean
      public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    }

    Xml装配的Bean,XML文件名为cd-config.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>

    通过@ImportResource注解,在javaConfig中引用xml文件
    @Import引入JavaConfig文件

    @Configuration
    @Import(CDPlayerConfig.class)
    @ImportResource("classpath:cd-config.xml")
    public class SoundSystemConfig {
    
    }

    2. 在xml中引用JavaConfig配置

    前面是使用@ImportResource注解,那么在XML中加载JavaConfig配置其实也类似:

    <import resouse="cd-congig.xml"/>
    <bean class="soundsystem.CDConfig">
    

    介绍完了,给自己做个学习笔记,如有不对敬请指正。

  • 相关阅读:
    *** 82 删除排序链表中的重复元素II
    83 删除排序链表中的重复元素
    61 旋转链表
    ASP.NET MVC3 ModelState.IsValid为false的问题
    ServletContext
    ServletConfig
    Servlet线程安全
    Servlet的一些细节(2)
    Servlet的一些细节(1)
    Servlet的接口实现类
  • 原文地址:https://www.cnblogs.com/shuiyj/p/13185256.html
Copyright © 2011-2022 走看看