zoukankan      html  css  js  c++  java
  • Spring实战——无需一行xml配置实现自动化注入

      已经想不起来上一次买技术相关的书是什么时候了,一直以来都习惯性的下载一份电子档看看。显然,如果不是基于强烈的需求或强大的动力鞭策下,大部分的书籍也都只是蜻蜓点水,浮光掠影。

      就像有位同事说的一样,有些书没有真真切切的经历过,你去看,看了就是看了,只是没有留下多少印象。我回头仔细想了想,大概就是这样,好比你去看设计模式相关的书籍,了解到了适配器模式,但是还是不够深刻。比如说某天你去面试的时候别人会问你,"你了解过适配器模式么,你有过这个模式的开发经历么,你能否画出你使用适配器模式的UML图..." 如果当时看书的时候没有动手,你可能会先“让懵逼飞一会儿”, 然后一直懵逼-_-! 设想面试之后,你便迫不及待的回去重新翻了一遍什么是设配器模式,有哪几种适配器模式,连抄代写的画出了自己的UML图。这时候书上的适配器模式就成了你自己的适配器模式。

      上面大概说了下电子档书籍可能会让你带来看书上面的懈怠,毕竟大部分电子档书籍都是唾手可得的,近乎免费(偶尔有些网站需要积分来兑现),而人却又这样的一个认知惯性,就是这样越容易得到的往往不太会珍惜,所以读书往往不能物尽其用。当然了,电子档数据有其先天的优势,比如便宜,比如方便易携带,比如你猛地一天想起一个知识点,就可以全局搜索一把来精准定位等等。说到这些优点也真是纸质书籍相形见绌的,一本800页的大部头书籍让你装在包里用来乘坐地铁时打发时间,我想能坚持下来的体力应该都还不错。对于动辄就是好几十甚至好几百的书籍,再查看下这个月的消费账单,想想还是先填饱自己的肚子吧。或者哪天你突然想起来需要找到一句在书中出现的至理名言,好吧,准备瓶眼药水可劲的找吧,但愿你当时做了笔记或者折了书角。但是纸质书籍也有他的好,首先不上眼,其次可以做笔记,当你真真切切的翻过某一页的时候,你可能会谨慎的问自己,过去的一夜我真的懂了么。

      说了这么多闲话,只是为了引出——我买了一本《Spring 实战(第四版)》

      理由很简单:一是学习需要;二是支持下知识产权。

      看了第一章和第二章,发现其实在Spring 4版本中有很多的新特性了,但是网上流传的还是传统的用法,所以决定有必要梳理分享下。

    环境介绍

      Intellij Idea:14.0.2

      Gradle:2.7

      JDK:1.8.0_60

      Spring-framework: 4.0.7.RELEASE

      这篇开始主要讲的是依赖注入,值得一提的是,从作者的文字看来是极力推崇自动化装配方案的,而不是稍显臃肿的基于xml配置。

    环境搭建

      Gradle 

      Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。

      这个东东以前从来没有接触过,但是因为Spring提供的代码是基于这个构建工具来解决依赖管理的,我暂且认为它和maven的作用等同,某种程度上来说,比maven来的要简洁(源于maven是基于xml方式配置依赖的),具体看后面就知道是不是名副其实的简洁style了。真的看下来,其实也没有什么特别的地方,起码示例项目跑起来并不那么复杂。

      首先来一睹Spring实战的某个项目中用于自动化构建的文件

    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin: 'idea'
    
    jar {
        baseName = 'stereo-autoconfig'
        version =  '0.0.1-SNAPSHOT'
    }
    
    repositories {
        mavenLocal()
        mavenCentral()
    }
    
    dependencies {
    	compile "org.springframework:spring-context:${springVersion}"
    
    	testCompile "org.springframework:spring-test:${springVersion}"
    	testCompile "com.github.stefanbirkner:system-rules:${systemRulesVersion}"
    }
    
    task wrapper(type: Wrapper) {
    	gradleVersion = '1.11'
    }

      这里的repositories实际上除了添加maven仓库以外,还支持Ivy和Ant仓库

      dependencies中就是你们熟悉的maven配置,乍一看,着实简洁了太多,不用在写GroupId,ArtifactId,Version等等。这个简洁范儿,我喜欢。

      还有就是gradleVersion,就是Gradle版本。

      备注:本来准备自己机子上装个Gradle,但是发现机子上不知什么时候已经装好了,好吧,就不再介绍安装了,网上一查资料很多跟配置Maven差不多。

      项目导入

      1. 打开Intellij Idea,选择File->Import Project

      2.选择导入的项目

      3. 选择Gradle项目类型

      4. 进入下一步选择Gradle点击finish

      5. 完成build compile等步骤后,完成项目导入

      6. 项目目录结构

      备注:在构建项目的过程中遇到类似这样的错误

    19:25:19: Executing external task 'build'...
    :compileJava
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Could not resolve all dependencies for configuration ':compile'.
    > Could not resolve org.springframework:spring-context:4.0.7.RELEASE.
      Required by:
          :stereo-mixedconfig:unspecified
       > Could not HEAD 'http://maven.oschina.net/content/groups/public/org/springframework/spring-context/4.0.7.RELEASE/spring-context-4.0.7.RELEASE.pom'.
          > Connection to http://maven.oschina.net refused
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    
    Total time: 24.733 secs
    Connection timed out: connect
    19:25:45: External task execution finished 'build'.
    

     

      主要就是中央仓库慢或者ping不通,无法下载依赖的jar包,最后通过更改中央仓库的地址为

    repositories {
        mavenLocal()
        maven { url "http://maven.aliyun.com/nexus/content/groups/public" }
    }
    

     

    Spring装配Bean的方式有三种:

      在XML中进行显示配置;

      在Java中进行显示配置;

      隐式的bean发现机制和自动装配。

      书中作者推荐的顺序依次是隐式的bean发现机制和自动装配->在Java中进行显示配置->在XML中进行显示配置,理由也很简单,尽可能的减少显示配置,好比在XML文件中声明这种。这里首先来介绍这种自动化装配方式(基于XML的方式已经在《学习Spring——依赖注入》中介绍过了)。

    Spring实现自动化化装配需要从以下两个方面:

      组件扫描(component scanning): Spring会自动发现应用上下文中所创建的bean。

      自动装配(autowiring):Spring自动满足bean之间的依赖。

    代码

      这里的应用场景是CD机播放光盘,所以需要准备几个bean。类的关系图如下

      首先需要CompactDisc类,再次一个CDPlayer类,我们需要Spring将CompactDisc bean注入CDPlayer来实现真正的播放音乐。

    public interface CompactDisc {
      void play();
    }
    

      这是一个接口,其定义了CD播放机对于光盘的操作。

      这时候我们还有一个实现CompactDisc接口的实现类SgtPeppers(《Sgt. Pepper's Lonely Hearts Club Band》 是英国摇滚乐队The Beatles发行于1967年6月1日的第8张录音室专辑)。

    @Component
    public class SgtPeppers implements CompactDisc {
    
      private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
      private String artist = "The Beatles";
      
      public void play() {
        System.out.println("Playing " + title + " by " + artist);
      }
      
    }
    

      这个@Component注解很关键,有了这个注解,好比该类自动告诉Spring,SgtPeppers就是一个组件类,Spring会自动为其创建bean。

      使用@Component注解,Spring会默认为其创建名为sgtPeppers的bean(第一个字母小写),你也可以自定义bean的名字比如通过配置@Component("lonelyHeartsClub“”)就能创建名为lonelyHeartsClub的bean。

      关于Spring会自动为其创建bean,并不完全正确,因为我还需要多做一步才能真正达到这样的效果。我们需要让Spring的组件扫描配置并开启,使得Spring能够扫描这些带有@Component或者其他注解的类。

    @Configuration
    @ComponentScan
    public class CDPlayerConfig { 
    }
    

      @Configuration表明了它是一个配置类;

      @ComponentScan表明该类启用Spring的组件扫描机制,或许你看到最多或者用的最多的应该是这种<context:component-scan base-package="soundsystem">,有了@ComponentScan,我们就不需要这种方式了,是不是简洁了很多。

      另外,@ComponentScan默认是扫描与配置类在相同包下面的类,当然,你也可以自定义扫描一个或多个包路径。比如配置如下

    @Configuration
    @ComponentScan(basePackages={"soundsystem", "video"})
    public class CDPlayerConfig { 
    }
    

      

      也可以指定扫描一个或多个类和接口比如

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

      

      下面来看看Spring是如何将CompactDisc注入到CDPlayer中的

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

      首先必不可少需要一个@Component注解以示该类收Spring管辖。

      再者,我们看到在CDPlayer的构造函数上,我们使用了@Autowired注解,该注解是用来在Spring为CDPlayer创建bean的时候,通过这个构造器传入一个可设置给CompactDisc的bean,从而解决CDPlayer类对于CompactDisc的依赖问题。

      除了通过构造函数注入bean还有通过setter方法注入,比如

    @Autowired
    publicvoidsetCompactDisc(CompactDisc cd) {
          this.cd = cd;
    }

      甚至还可以通过将@Autowired注解用在任何类的方法上来实现依赖注入问题。

    测试验证

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CDPlayerConfig.class)
    public class CDPlayerTest {
    
      @Rule
      public final StandardOutputStreamLog log = new StandardOutputStreamLog();
    
      @Autowired
      private MediaPlayer player;
      
      @Autowired
      private CompactDisc cd;
      
      @Test
      public void cdShouldNotBeNull() {
        assertNotNull(cd);
      }
    
      @Test
      public void play() {
        player.play();
        assertEquals(
            "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles
    ",
            log.getLog());
      }
    
    }
    

      这一个测试类基本就能验证上面的知识点。

      首先运行cdShouldNotBeNull()方法得到结果如下

      该测试方法,表明通过自动化装配的方法,注入到CDPlayerTest类中的CompactDisc确实是经过Spring实例化后的bean,而不是空对象。

      运行play()方法

      该测试方法表明,注入到测试方法类中的MediaPlayer也是被Spring实例化过后的bean,而且可以调用该类中的play方法。

      以上测试说明,Spring的自动化装配就是这么简洁高效。

      另外我觉得将CDPlayer类改写如下

    @Component
    public class CDPlayer implements MediaPlayer {
    
      @Autowired
      private CompactDisc cd;
    
      public CDPlayer() {
    
      }
    
      public void play() {
        cd.play();
      }
    
    }
    

      也是可行的,并且也通过了测试,这种方式是工作中做常见的场景之一。

    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。


    如果你觉得博主的文章对你那么一点小帮助,恰巧你又有想打赏博主的小冲动,那么事不宜迟,赶紧扫一扫,小额地赞助下,攒个奶粉钱,也是让博主有动力继续努力,写出更好的文章^^。

      1. 支付宝                             2. 微信

                          

  • 相关阅读:
    mysql_config 问题
    软考倒计时3天
    软考倒计时5天
    Pdf 解密后复制文字乱码
    软考倒计时7天:题目书中的易混点
    应急储备和管理储备
    软考倒计时9天:100个主要知识点
    软考倒计时10天
    软考倒计时15天
    软考倒计时18天
  • 原文地址:https://www.cnblogs.com/bigdataZJ/p/SpringInAction1.html
Copyright © 2011-2022 走看看