• 装配Bean—自动化装配Bean


    1.0  自动化装配Bean

    Spring配置可选方案:

    ​ 装配是依赖注入DI的本质,Spring提供了以下三种注入的装配机制:

    • 在XMl中进行显式配置
    • 在java中进行显式配置
    • 隐式的Bean发现机制和自动装配

    自动化装配Bean:

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

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

    实例:

    CD和CDPlayer,如果你不将CD放入(注入)到播放器中,那么CD播放器其实是没多大用处的,所以说,CD播放器是依赖于CD才能完成它的使命.

    package com.CDDemo;
    //CD的接口
    public interface CompactDisc {
       public void play();
    }
    package com.CDDemo;
    import org.springframework.stereotype.Component;
    //CD的实现类 歌曲
    @Component
    public class SgtPeppers implements CompactDisc {
        private String title = "sgt";
        private String song = "Twinkle, twinkle, little start";
        public void play() {
            System.out.println("title:" + title + "song:" + song);
        }
    }
    package com.CDDemo;
    import org.springframework.stereotype.Component;
    //CD的实现类 歌曲
    @Component
    public class SgtPeppers implements CompactDisc {
        private String title = "sgt";
        private String song = "Twinkle, twinkle, little start";
        public void play() {
            System.out.println("title:" + title + "song:" + song);
        }
    }
    package com.CDDemo;
    //测试类
    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;
    import static org.junit.Assert.assertNotNull;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = CDPlayerConfig.class)
    public class CDTest {
        @Autowired
        private CompactDisc cd;
        @Test
        public void cdShouldNotBeNull() {
          assertNotNull(cd);
          cd.play();
        }
    }

    上面需要注意的是:

    @Configuration

    定义了Spring的装配规则

    @ComponentScan

    这个会默认扫描与配置类相同的包.(这里扫描package com.CDDemo;同包以及下面的所有的子包)

    查找出带有@Component注解的类 这样就能发现CompactDisc(因为注解了它的实例) 并为它在Spring中创建一个Bean.

    当然你也可以通过配置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:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
                 http://www.springframework.org/schema/aop
                 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!--扫描包的配置-->
    <context:component-scan base-package="com.CDDemo"/>
    </beans>

    2.2.1.为组件扫描的Bean命名

    通过Spring的注解可以让Spring给注入的Bean一个ID,这个ID默认为类名(首字母小写);

    当然你也可以通过命名来明确给这个类注入的时候带有什么名称的ID;

    1.@Componment("test_SgtPeppers")

    2.@Name("test_SgtPeppers")

    当然我们一般情况下直接用@Componment使用ID默认为类名(首字母小写)就可以了,因为这样用起来比较整洁,特殊情况可以在@Componment()的括号中加入指定ID名称.

    2.2.2.设置组件扫描的基础包

    ​ 在上面的@ComponentScan默认扫描注解类所在的包,那么有没有一种方式能够更为精准有效的扫描我们所需要的包呢?在Spring中有如下几种方式可供选择:

    1.在ComponentScan的Value中直接指明包的名

    //在ComponentScan中直接指明包的名称
    @ComponentScan("com.CDDemo")
    public class CDPlayerConfig {
    
    }

    2.在ComponentScan中basePackages的直接指明包的名称 是复数 可以指定扫描多个包

    @ComponentScan(basePackages = "com.CDDemo")
    public class CDPlayerConfig {
    
    }
    @ComponentScan(basePackages = {"com.CDDemo","com.aop"})
    public class CDPlayerConfig {
    
    }
    @ComponentScan(basePackages = "com.CDDemo.*")
    public class CDPlayerConfig {
    
    }

    3.在ComponentScan中的basePackageClasses加入扫描的类名(会自动扫描类所在的包)

    @ComponentScan(basePackageClasses = {SgtPeppers.class,CDTest.class})
    public class CDPlayerConfig {
    
    }

    2.2.3.通过为Bean添加注解实现自动装配

    ​ 在Spring中还有种方便而且应用广泛的方法,在需要依赖注入的地方加上@Autowired,这个表明当Spring创建CompactDisc Bean的时候,会通过这个传入该接口的实例类的Bean.

    public class CDTest {
        @Autowired
        private CompactDisc cd;
    }

    ​ @Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上,(但是虽然用在Getter方法上不报错,但没有实际意义, 请看下文的解释)

    @Autowired
        public void setTitle(String title) {
            this.title = title;
        }

    先看一下bean实例化和@Autowired装配过程:

    1. 一切都是从bean工厂的getBean方法开始的,一旦该方法调用总会返回一个bean实例,无论当前是否存在,不存在就实例化一个并装配,否则直接返回。(Spring MVC是在什么时候开始执行bean的实例化过程的呢?其实就在组件扫描完成之后)
    2. 实例化和装配过程中会多次递归调用getBean方法来解决类之间的依赖。
    3. Spring几乎考虑了所有可能性,所以方法特别复杂但完整有条理。
    4. @Autowired最终是根据类型来查找和装配元素的,但是我们设置了<beans default-autowire="byName"/>后会影响最终的类型匹配查找。因为在前面有根据BeanDefinition的autowire类型设置PropertyValue值得一步,其中会有新实例的创建和注册。就是那个autowireByName方法。

    另外@Autowired注解还可以用在方法上面,能和Setter方法上使用该注解发挥相同的作用

     @Autowired
        public void insertDisc() {
            System.out.println("注解在方法名上");
        }

    以上方法都是有匹配的Bean的情况下有效的,那如果找不到匹配的Bean的话,Spring会抛出一个异常.为了避免出现这种异常,你可以将@Autowired的require属性设置为false,但还是建议根据实际情况找到相应的问题并解决:

    @Autowired(required = false)
        public void insertDisc() {
            System.out.println("注解在方法名上");
        }

    但是把required改为false需谨慎,如果在你的代码中没有进行null检查的话,这个处于未装配状态的属性随时可能出现NullPointerException.

    ​ 但你不想在代码中导出使用@Autowired的时候可以考虑用@Inject替换,但这两个之间有些许差别,一般可以相互替换.

    import javax.inject.Inject;
    import javax.inject.Named; 
    @Named
    public class SgtPeppers implements CompactDisc {
        private String title = "sgt";
        private String song = "Twinkle, twinkle, little start";
        public void play() {
            System.out.println("title:" + title + "song:" + song);
        }
        @Inject
        public void insertDisc() {
            System.out.println("注解在方法名上");
        }
    }

    请注意:

    1、@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject;实现注入。

    2、@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;

    3、@Inject可以作用在变量、setter方法、构造函数上。

  • 相关阅读:
    20170225-ALV tree 显示
    20170225-第一件事:SAP模块清单
    20170225 ABAP获取字符串长度/字节长度
    记录001:AS11 BAPI
    Ghost wenjian目录
    20170223-问题001,增强中的E消息 显示为 S模式消息,
    孩子教育分析
    笔记:智能分类
    从市电接信号串联电阻聊到电阻的耐压
    锂聚合物电池和液态锂电池
  • 原文地址:https://www.cnblogs.com/socketqiang/p/11316466.html
Copyright © 2020-2023  润新知