zoukankan      html  css  js  c++  java
  • 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注解

    @Component("zhoujielun")
    public class JayDisc implements ICompactDisc {
    ...
    }
    如果不使用@Component注解的话,则使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解bean的ID。

    需要引入:

    <dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
    </dependency>
    @Named("zhoujielun")
    public class JayDisc implements ICompactDisc {
    ....
    }
    设置组件扫描的基础包
    前面再给CDPlayerConfig类设置@ComponentScan,我们并没有设置任何属性,这个时候默认扫描默认包是:CDPlayerConfig类所在包及其包的子包。

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

    @Configuration
    @ComponentScan(basePackages = {"com.stalkers.soundsystem"})
    public class DiscConfig {
    }
    basePackages使用的是复数,则意味着可以设置多个基础包。

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

    @Configuration
    @ComponentScan(basePackageClasses = {com.stalkers.soundsystem.JayCompactDisc.class})
    public class DiscConfig {
    }
    通过为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()都是同一个实例。

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

    @Bean
    public IMediaPlayer cdplayer(ICompactDisc disc) {
    return new VCDPlayer(disc);
    }
    三、通过XML装配Bean
    在xml配置中,创建一个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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

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

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

    <?xml version="1.0" encoding="utf-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    </beans>
    1.借助构造器注入初始化bean

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

    <?xml version="1.0" encoding="utf-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer">
    <constructor-arg ref="jayCompactDisc"/>
    </bean>
    </beans>
    2.使用Spring3.0所引入的c-命名空间

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

    xmlns:c="http://www.springframework.org/schema/c"
    <?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:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean>
    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:cd-ref="jayCompactDisc">
    </bean>
    </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通常指的是类型的装配,也就是将对象的引用装配到依赖他们的其他对象中,但是有时候我们传的只是一个字面量值

    public class VaeCompactDisc implements ICompactDisc {
    private String title;

    public VaeCompactDisc(String title) {
    this.title = title;
    }

    public void play() {
    System.out.println("大家好,我是Vae,下面这首:" + title + "献给大家的");
    }
    }
    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    </bean>
    <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc">
    <constructor-arg value="浅唱"></constructor-arg>
    </bean>
    c-命名空间的写法

    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    </bean>
    <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="城府">
    <!--<constructor-arg value="浅唱"></constructor-arg>-->
    </bean>
    装配集合

    public class VaeCompactDisc implements ICompactDisc {
    private String title;

    private List<String> tracks;

    public VaeCompactDisc(String title, List<String> tracks) {
    this.title = title;
    this.tracks = tracks;
    }

    public void play() {
    System.out.println("大家好,我是Vae,下面这专辑:" + title + "献给大家的");
    for (String s : tracks) {
    System.out.println(s);
    }
    }
    }
    Spring配置使用constructor-arg。而c-命名的是无法使用装配集合的功能

    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc">
    </bean>
    <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc">
    <constructor-arg name="title" value="自定义"></constructor-arg>
    <constructor-arg name="tracks">
    <list>
    <value>有何不可</value>
    <value>多余的解释</value>
    </list>
    </constructor-arg>
    </bean>
    2.使用属性Setter方法注入

    public class CDPlayer implements IMediaPlayer {

    private ICompactDisc cd;

    @Autowired
    public void setCd(ICompactDisc cd) {
    this.cd = cd;
    }

    public CDPlayer(ICompactDisc cd) {
    this.cd = cd;
    }

    public void play() {
    System.out.println("cd Play:");
    cd.play();
    }
    }
    Spring.xml配置里面

    <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer">
    <property name="cd" ref="jayCompactDisc"></property>
    </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,但是我们可以使用

    <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="自定义" c:tracks-ref="songs">
    </bean>
    <util:list id="songs">
    <value>有何不可</value>
    <value>多余的解释</value>
    </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
    在此我向大家推荐一个架构学习交流群。交流学习群号:895244712 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

    四、导入和混合配置
    在Spring应用中,我们可以同时使用自动化和显示配置。

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

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

     
    ————————————————
    版权声明:本文为CSDN博主「鹿‘s」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_43277643/article/details/84253237

  • 相关阅读:
    Python疑难杂症:SyntaxError: NonASCII character Python中文处理问题
    程序员健康大全透视身体24小时工作时间表
    ConnectionTimeout,CommandTimeout和executionTimeout的理解
    google map api 与jquery结合使用(3) 图标样式,使用xml和异步请求【转帖】
    新手8周跑步训练计划
    57商城温州地区最大本土网上超市
    7 款仿照 Sinatra 思路的 .NET 框架
    线程池的原理和连接池的原理
    免费网站模版:一个黑色系的公司网站模版(flash幻灯)
    深入浅出REST
  • 原文地址:https://www.cnblogs.com/bootdo/p/11393279.html
Copyright © 2011-2022 走看看