• Spring Bean详细讲解


    什么是Bean?

    Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。

    Spring 容器会自动完成@bean对象的实例化。

    创建应用对象之间的协作关系的行为称为:装配(wiring),这就是依赖注入的本质。

    Spring 三种配置方案

    1.在XML中进行显示配置
    2.使用Java代码进行显示配置
    3.隐式的bean发现机制和自动装配
    推荐方式: 3>2>1

    一、自动化装配bean

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

    package com.stalkers;
     
     
     
    /**
     
    * CD唱片接口
     
    * Created by stalkers on 2016/11/17.
     
    */
     
    public interface ICompactDisc {
     
    void play();
     
    }
     
    package com.stalkers.impl;
      
     
    import com.stalkers.ICompactDisc;
     
    import org.springframework.stereotype.Component;
     
     
     
    /**
     
    * Jay同名专辑
     
    * Created by stalkers on 2016/11/17.
     
    */
     
    @Component
     
    public class JayDisc implements ICompactDisc {
     
     
     
    private String title = "星晴";
     
     
     
    public void play() {
     
    System.out.println(title + ":一步两步三步四步,望着天上星星...");
     
    }
     
    }

    Component注解作用:
    表明该类会作为组件类。

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

    1.java code开启组件扫描:
    其中,如果CompoentScan后面没有参数的话,默认会扫描与配置类相同的包

    @Configuration
     
    @ComponentScan
     
    public class CDPlayerConfig {
     
    @Bean
     
    public ICompactDisc disc() {
     
    return new JayDisc();
     
    }
     
    }

    2.xml启动组件扫描

    <?xml version="1.0" encoding="utf-8" ?>
     
    <beans xmlns="http://www.springframework.org/schema/beans"
     
    xmlns:context="http://www.springframework.org/schema/context"
     
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     
    xsi:schemaLocation="http://www.springframework.org/schema/context
     
    http://www.springframework.org/schema/context/spring-context.xsd">
     
    <context:component-scan base-package="com.stalkers.impl"/>
     
    </beans>

    测试代码

    package com.stalkers;
     
     
     
    import com.stalkers.config.CDPlayerConfig;
     
    import org.junit.Test;
     
    import org.junit.runner.RunWith;
     
    import org.springframework.beans.factory.annotation.Autowired;
     
    import org.springframework.test.context.ContextConfiguration;
     
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     
     
     
    /**
     
    * Created by stalkers on 2016/11/18.
     
    */
     
    @RunWith(SpringJUnit4ClassRunner.class)
     
    @ContextConfiguration(classes = CDPlayerConfig.class)
     
    public class TestPlay {
     
    @Autowired
     
    private ICompactDisc jayDisc;
     
     
     
    @Test
     
    public void play() {
     
    jayDisc.play();
     
    }
     
    }

    在ComponentScan扫描的包中,所有带有@Component注解的类都会创建为bean

    为组件扫描的bean命名

    Spring应用上下文种所有的bean都会给定一个ID。在前面的例子中,尽管我们没有明确地为JayDisc bean设置ID,但是Spring会默认为JayDisc设置ID为jayDisc,也就是将类名的第一个字母变成小写。

    如果想为这个bean设置不同的ID,那就将期望的值传递给@Component注解

    1.  
      @Component("zhoujielun")
    2.  
      public class JayDisc implements ICompactDisc {
    3.  
      ...
    4.  
      }

    如果不使用@Component注解的话,则使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解bean的ID。

    需要引入:

    1.  
      <dependency>
    2.  
      <groupId>javax.inject</groupId>
    3.  
      <artifactId>javax.inject</artifactId>
    4.  
      <version>1</version>
    5.  
      </dependency>
    1.  
      @Named("zhoujielun")
    2.  
      public class JayDisc implements ICompactDisc {
    3.  
      ....
    4.  
      }

    设置组件扫描的基础包

    前面再给CDPlayerConfig类设置@ComponentScan,我们并没有设置任何属性,这个时候默认扫描默认包是:CDPlayerConfig类所在包及其包的子包。

    如果是下图这种情况,DisConfig与其这时候就需要设置@ComponentScan的扫描的包。

    image

    1.  
      @Configuration
    2.  
      @ComponentScan(basePackages = {"com.stalkers.soundsystem"})
    3.  
      public class DiscConfig {
    4.  
      }

    basePackages使用的是复数,则意味着可以设置多个基础包。

    但是basePackages后面跟的是String类型,这种类型并不安全。可以使用basePackageClasses有下面这种写法:

    1.  
      @Configuration
    2.  
      @ComponentScan(basePackageClasses = {com.stalkers.soundsystem.JayCompactDisc.class})
    3.  
      public class DiscConfig {
    4.  
      }

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

    如果所有的对象都是独立的,彼此之间没有任何依赖,那么使用组件扫描就能自动化装配bean。

    但是实际工作中,很多对象会依赖其他对象完成任务。这时候就需要能够将组件扫描得到的bean和他们依赖装配在一起。这就是自动装配(autowiring)

    使用Spring的Autowired

    public interface IMediaPlayer {
     
    void play();
     
    }
     
    @Component
     
    public class CDPlayer implements IMediaPlayer {
     
     
     
    private ICompactDisc cd;
     
     
     
    @Autowired
     
    public CDPlayer(ICompactDisc cd) {
     
    this.cd = cd;
     
    }
     
     
     
    public void play() {
     
    System.out.println("cd Play:");
     
    cd.play();
     
    }
     
    }

    CDPlayer类的构造器上添加了@Autowired注解,表明当Spring创建CDPlayerbean的时候,会通过这个构造器来进行实例化

    Autowired的多种方式
    1.构造器注解(constructor)

    2.属性setter注解

    3.field注解

    不管使用上面3中的哪个方法,Spring都会满足声明的依赖。假如有且只有一个bean匹配依赖的话,那么这个bean将会被装配进来。

    如果使用2,3方式注解,有多个bean的话,则用Qualifier指定。

    如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,可以使用

    @Autowired(required = false)
    
    private IMediaPlayer CDPlayer;

    required=false表示如果没有匹配的话,Spring会让bean处于未装配的样子。使用未装配的属性,会出现NullPointerException

    总结:
    所以在使用开发的时候一般建议使用Resource(package javax.annotation)进行注解。但是Resource不支持构造器注解

    二、通过Java代码装配Bean

    尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化更为推荐,但是有时候行不通。比如引用第三方组件,没办法在它的类上添加@Component及@Autowired。所以就需要JavaConfig或者XML配置

    在进行显示配置的时候,JavaConfig是更好的解决方案。

    JavaConfig与其他的Java代码又有所区别,在概念上它与应用程序中的业务逻辑和领域代码又有所不同。JavaConfig是配置相关代码,不含任何逻辑代码。通常会将JavaConfig放到单独的包中。

    创建JavaConfig类

    @Configuration
     
    public class CDPlayerConfig {
     
    }

    使用@Configuration表明CDPlayerConfig是一个配置类

    声明简单的bean

    @Bean
     
    public IMediaPlayer cdplayer() {
     
    return new VCDPlayer(new JayCompactDisc());
     
    }

    @Bean注解会告诉Spring将返回一个对象。

    默认情况下,@Bean的Id与带有@Bean的方法名一样。当然也可以通过@Bean的name属性指定额外的方法名。

    借助JavaConfig注入

    在上面的例子中,初始化个VCDPlayer都需要new一个JayCompactDisc对象。如果其他的对象的也需要JayCompactDisc,所以优化如下:

    @Bean
     
    public IMediaPlayer cdplayer() {
     
    return new VCDPlayer(disc());
     
    }
     
     
     
    @Bean
     
    public ICompactDisc disc() {
     
    return new JayCompactDisc();
     
    }

    单独抽出disc()方法,在其方法上加上Bean注解,Spring上加@Bean注解的都是默认单例模式,不管disc()被多个方法调用,其disc()都是同一个实例。

    当然上面的初始化可以优化如下:

    1.  
      @Bean
    2.  
      public IMediaPlayer cdplayer(ICompactDisc disc) {
    3.  
      return new VCDPlayer(disc);
    4.  
      }

    三、通过XML装配Bean

    在xml配置中,创建一个xml文件,并且要以元素为根。

    1.  
      <?xml version="1.0" encoding="utf-8" ?>
    2.  
      <beans xmlns="http://www.springframework.org/schema/beans"
    3.  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.  
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    5.  
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    6.  
       
    7.  
      </beans>

    在使用xml的时候,需要在配置文件顶部声明多个xml模式(XML Schema Definition xsd)文件

    对于我们需要配置bean的则在spring-beans模式中。

    1.  
      <?xml version="1.0" encoding="utf-8" ?>
    2.  
      <beans xmlns="http://www.springframework.org/schema/beans"
    3.  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.  
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    5.  
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    6.  
      <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    7.  
      </beans>

    1.借助构造器注入初始化bean

    构造器注入的方案:
    1.元素

    1.  
      <?xml version="1.0" encoding="utf-8" ?>
    2.  
      <beans xmlns="http://www.springframework.org/schema/beans"
    3.  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.  
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    5.  
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    6.  
      <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    7.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer">
    8.  
      <constructor-arg ref="jayCompactDisc"/>
    9.  
      </bean>
    10.  
      </beans>

    2.使用Spring3.0所引入的c-命名空间

    使用c-命名空间,需要引入:

    xmlns:c="http://www.springframework.org/schema/c"
    1.  
      <?xml version="1.0" encoding="utf-8" ?>
    2.  
      <beans xmlns="http://www.springframework.org/schema/beans"
    3.  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.  
      xmlns:c="http://www.springframework.org/schema/c"
    5.  
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    6.  
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    7.  
      <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    8.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:cd-ref="jayCompactDisc">
    9.  
      </bean>
    10.  
      </beans>

    解析:c-命名空间的语法:

    c:cd-ref="jayCompactDisc"

    1.c 代表命名空间前缀

    2.cd 代表VCDPlayer类的构造器参数名。当然我们也可以使用参数在整个参数列表的位置 c:_0-ref

     <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="jayCompactDisc">

    使用下划线因为参数不能以数字开头,所以加下划线。

    3.-ref 代表注入bean引用

    4.jayCompactDisc 要注入的bean的id

    注意:

    c-命名需要写在标签内,与constructor-arg写法差别很大

    将字面量注入到构造器中

    上面我们所做的DI通常指的是类型的装配,也就是将对象的引用装配到依赖他们的其他对象中,但是有时候我们传的只是一个字面量值

    1.  
      public class VaeCompactDisc implements ICompactDisc {
    2.  
      private String title;
    3.  
       
    4.  
      public VaeCompactDisc(String title) {
    5.  
      this.title = title;
    6.  
      }
    7.  
       
    8.  
      public void play() {
    9.  
      System.out.println("大家好,我是Vae,下面这首:" + title + "献给大家的");
    10.  
      }
    11.  
      }
    1.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    2.  
      </bean>
    3.  
      <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc">
    4.  
      <constructor-arg value="浅唱"></constructor-arg>
    5.  
      </bean>

    c-命名空间的写法

    1.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    2.  
      </bean>
    3.  
      <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="城府">
    4.  
      <!--<constructor-arg value="浅唱"></constructor-arg>-->
    5.  
      </bean>

    装配集合

    1.  
      public class VaeCompactDisc implements ICompactDisc {
    2.  
      private String title;
    3.  
       
    4.  
      private List<String> tracks;
    5.  
       
    6.  
      public VaeCompactDisc(String title, List<String> tracks) {
    7.  
      this.title = title;
    8.  
      this.tracks = tracks;
    9.  
      }
    10.  
       
    11.  
      public void play() {
    12.  
      System.out.println("大家好,我是Vae,下面这专辑:" + title + "献给大家的");
    13.  
      for (String s : tracks) {
    14.  
      System.out.println(s);
    15.  
      }
    16.  
      }
    17.  
      }

    Spring配置使用constructor-arg。而c-命名的是无法使用装配集合的功能

    1.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    2.  
      </bean>
    3.  
      <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc">
    4.  
      <constructor-arg name="title" value="自定义"></constructor-arg>
    5.  
      <constructor-arg name="tracks">
    6.  
      <list>
    7.  
      <value>有何不可</value>
    8.  
      <value>多余的解释</value>
    9.  
      </list>
    10.  
      </constructor-arg>
    11.  
      </bean>

    2.使用属性Setter方法注入

    1.  
      public class CDPlayer implements IMediaPlayer {
    2.  
       
    3.  
      private ICompactDisc cd;
    4.  
       
    5.  
      @Autowired
    6.  
      public void setCd(ICompactDisc cd) {
    7.  
      this.cd = cd;
    8.  
      }
    9.  
       
    10.  
      public CDPlayer(ICompactDisc cd) {
    11.  
      this.cd = cd;
    12.  
      }
    13.  
       
    14.  
      public void play() {
    15.  
      System.out.println("cd Play:");
    16.  
      cd.play();
    17.  
      }
    18.  
      }

    Spring.xml配置里面

    1.  
      <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer">
    2.  
      <property name="cd" ref="jayCompactDisc"></property>
    3.  
      </bean>

    元素为属性的Setter方法所提供的功能与元素为构造器所提供的功能是一样的。

    与c-命名空间的类似的作为property的替代方案:p-命名空间。使用p-命名空间需要引入:

    xmlns:p="http://www.springframework.org/schema/p"

    Spring.xml配置如下

    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" p:cd-ref="vaeCompactDisc">

    语法解析:

    p:cd-ref="vaeCompactDisc"

    1.p-:命名空间的前缀

    2.cd:属性名称

    3.-ref:注入bean引用

    4.vaeCompactDisc:所注入的bean的id

    将字面量注入到属性中

    字面量注入到属性与上面将字面量注入到构造方法中方式一样。只不过标签名改成了property。

    装配list也是与上面的构造器的装配list一样。

    虽然我们无法使用c-及p-命名空间装配list,但是我们可以使用

    1.  
      <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="自定义" c:tracks-ref="songs">
    2.  
      </bean>
    3.  
      <util:list id="songs">
    4.  
      <value>有何不可</value>
    5.  
      <value>多余的解释</value>
    6.  
      </util:list>

    Spring util命名空间的中的元素:

    元素描述
    util:constant 引用某个类型的public static 域
    util:list 创建一个java.util.List类型的bean,其中包含值或引用
    util:map 创建一个java.util.Map类型的bean,其中包含值或引用
    util:properties 创建一个java.util.Properties类型的bean
    util:property-path 引用一个bean的属性
    util: set 创建一个java.util.Set类型的bean

    四、导入和混合配置

    在Spring应用中,我们可以同时使用自动化和显示配置。

    如果一个JavaConfig配置太臃肿,我们可以把其进行拆分,然后使用@Import将拆分的类进行组合。

    如果希望在JavaConfig里引用xml配置。则可以使用@ImportResource

  • 相关阅读:
    Solr服务在Linux上的搭建详细教程
    Linux服务器上安装JDK小白教程
    request和response中文乱码问题后台处理办法
    Redis的五种数据类型及方法
    Java类装载器ClassLoader
    Git快速入门和常用命令
    redis在Linux上的部署和jedis简单使用
    Linux常用基础命令
    JDK1.7中HashMap底层实现原理
    微信电脑版无法显示图片无法下载文件
  • 原文地址:https://www.cnblogs.com/endv/p/13390514.html
Copyright © 2020-2023  润新知