• 《Spring实战》读书笔记——如何实现自动化装配


    加我微信公众号,一起夯实Java基础,向着诗和远方出发吧~

    如果所有的装配工作都交给Spring来自动完成,减少人工的干预,是不是就能减少依赖关系配置带来的麻烦呢?认真做自己的事儿吧,装配交给Spring来!

    通过使用Spring的自动装配,我们不再需要去管对象之间复杂的依赖关系,能更加专注于应用核心逻辑的开发。接下来进入个人的free style!各位观众把锅接好了!

    一览众山小

    • Spring开启组件扫描的方式
    • 如何让Bean能够被Spring扫描到
    • 怎么让Bean进行自动装配
    • 总结

    Spring通过组件扫描和自动装配实现自动化装配Bean,通过自动化装配,能最大程度的减少各种显式配置。

    Spring开启组件扫描的方式

    组件扫描默认是不开启的,因此需要我们手动去启动。Spring开启组件扫描有以下两种方式。

    通过Java配置类
    1. 基本示例
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * 通过@Configuration注解,说明该类是一个配置类,配置信息从这里加载
     * 通过@ComponentScan注解,说明开启组件扫描,默认扫描的是该配置类所在包及其子包
     */
    @Configuration
    @ComponentScan
    public class ComponentScanConfig {
    
    }
    
    1. 定义组件扫描的基础包

      如果我们希望把配置类与核心代码类放在不同的包中,这时候默认的加载地址对我们就没有意义了。这时候我们可以自定义组件扫描的基础包。有以下两种方式:

      (1) 指明需要扫描的包的名称

      package com.lurker.springaction.yjiang.autowire;
      
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      //指明扫描com.lurker.springaction.yjiang.autowire包
      //或者不用value,而使用basePackages,效果是一样的
      //value和basePackages都支持以数组的形式配置
      //示例:value={"com.lurker.springaction.yjiang.autowire", "..."}
      @ComponentScan(value = "com.lurker.springaction.yjiang.autowire")
      public class ComponentScanConfig {
      
      }
      

      但是以上方式有个明显的缺陷,其是类型不安全的,如果某次重构代码的时候,包名可能会改变,那么这里设置的valuebasePackages就需要改变了。如果你设置了多个多个配置类,想想,多么可怕?那么我们来个更实用的。

      (2) 指明需要扫描的包中的某个接口

      package com.lurker.springaction.yjiang.autowire;
      
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      
      //通过basePackageClasses属性,指明需要扫描的包中的接口
      //该方式同样支持以数组的形式配置
      //示例basePackageClasses={BasePackageLocation.class, ...}
      @Configuration
      @ComponentScan(basePackageClasses = BasePackageLocation.class)
      public class ComponentScanConfig {
      
      }
      

      以上方式,用basePackageClasses代替了valuebasePackages属性。程序在解析的时候,会以BasePackageLocation类所在的路径作为基础包路径。

      我们一般采用第二种方式进行配置,通常的做法是,在需要扫描的包下建立一个空接口,什么都不写。通过标记接口的形式找到基础包,同时由于是空接口,你在重构时可以不加理会,这种方式是对重构友好的。

    通过XML文件配置

    通过在Spring的xml配置文件中添加如下元素:

    <context:component-scan base-package="com.lurker.springaction.yjiang.autowire">

    通过这种方式能够取得跟Java配置相同的效果。同时,这种方式也支持同时配置多个包。

    如何让Bean能够被Spring扫描到

    开启了Spring的组件扫描之后,可以进行扫描指定的包及其子包了。那么,Spring怎么知道哪些才是Bean呢?实际上,Spring的组件是有一个标志的。

    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.stereotype.Component;
    
    //@Component注解表示该类会作为一个组件类,并告诉Spring要为这个类创建Bean
    @Component
    public class CDPlayer implements Player {
    }
    

    除了@Component注解外,还有三个注解同样拥有@Component的作用,他们分别是:

    • @Controller:注解Controller层
    • @Service:注解Service层
    • @Repository:注解DAO层

    这三个注解继承自@Component注解,因此具有相同的功效。在分层架构体系下,在不同的层级运用不同名称的注解,使项目结构更加清晰。

    然而注意,这些标注组件的注解,会默认给组件一个名称,默认为类名首字母小写,如其上的Bean名称为cDPlayer;Java中是允许在不同的包中有相同类名的,这时候怎么区分具有相同类名的Bean呢?Spring的解决方案是:

    @Component@Controller@Service@Repository这些注解中,填写value字段,如下:

    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.stereotype.Component;
    
    //@Component注解表示该类会作为一个组件类,并告诉Spring要为这个类创建Bean
    @Component(value="player")
    public class CDPlayer implements Player {
    }
    

    以上代码,把这个Bean的名称定义为player,而不再是默认名称cDPlayer了。除此之外,JDI规范(Java Dependency Injection)还定义了@Named注解用于为Bean设置ID,其具有与@Component(value="player")相同的功效。例如:

    @Named(value="player")
    public class CDPlayer implements Player {
    }
    

    如何让Bean实现自动装配

    万事俱备,只欠东风。Spring已经扫描到了进行标注后的Bean,并已经将他们放入容器中了,怎么把Bean装配到需要的地方呢?

    Spring通过@Autowired注解来实现Bean的自动装配。@Autowired注解可以用在类的任何地方。但是,请注意,如果在装配过程中,如果某个需要的Bean不存在,那么Spring会抛出一个异常。如果这个欠缺的Bean不是那么重要,那么你可以尝试通过required设置为false来忽略掉它不存在的事实。

    1. 注解在构造方法上
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer {
    
        private Disk disk;
    
        @Autowired
        public CDPlayer(Disk disk) {
            this.disk = disk;
        }
    
        public Disk getDisk() {
            return disk;
        }
    
        public void setDisk(Disk disk) {
            this.disk = disk;
        }
    }
    
    1. 注解在setter方法上
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer {
    
        private Disk disk;
    
        public CDPlayer(Disk disk) {
            this.disk = disk;
        }
    
        public Disk getDisk() {
            return disk;
        }
    
        @Autowired
        public void setDisk(Disk disk) {
            this.disk = disk;
        }
    }
    
    1. 注解在属性上
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer {
    
        @Autowired
        private Disk disk;
    
        public CDPlayer(Disk disk) {
            this.disk = disk;
        }
    
        public Disk getDisk() {
            return disk;
        }
    
        public void setDisk(Disk disk) {
            this.disk = disk;
        }
    }
    
    1. 注解在任意方法上
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer {
    
        @Autowired
        public void play(Disk disk) {
            System.out.println(disk.toString());
        }
    
    }
    
    1. 忽视某个Bean不存在的事实
    package com.lurker.springaction.yjiang.autowire;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer {
    
        @Autowired(required=false)
        public void play(Disk disk) {
            System.out.println(disk.toString());
        }
    
    }
    

    除此之外,JDI也提供了@Inject来实现和@Autowired相同的功能。如果你不想太依赖Spring的注解的话,也可以使用@Inject注解来实现自动装配。

    总结

    本文,我们与代码结合,实现了Bean的自动化装配。实际上,这样做我们通过极少的配置就能够让Spring帮我们进行Bean的管理,何乐而不为呢?这种配置方式也是我们主推的。

    下一节,我们将一起探讨通过Java配置的方式来进行Bean的装配。一起期待吧!!!

    生命不止,学习不休,加油!!!

  • 相关阅读:
    1414 冰雕
    1475 建设国家(优先队列)
    Digit Division
    Sleep Buddies
    Reverse and Compare(DP)
    1536 不一样的猜数游戏
    Genealogical tree
    网站日志实时分析工具GoAccess使用
    CentOS下一键安装Openstack
    权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现2
  • 原文地址:https://www.cnblogs.com/lurker-yaojiang/p/10372580.html
Copyright © 2020-2023  润新知