加我微信公众号,一起夯实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的装配。一起期待吧!!!

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

《Spring实战》读书笔记——如何实现自动化装配的更多相关文章

  1. Spring实战读书笔记

    Spring实战读书笔记 Spring-core Spring之旅 - DI 和 AOP 概念 spring 的Bean容器 spring 的 核心模块 Spring的核心策略 POJO 最小侵入式编 ...

  2. <<Java RESTful Web Service实战>> 读书笔记

    <<Java RESTful Web Service实战>> 读书笔记 第一章   JAX-RS2.0入门 REST (Representational State ransf ...

  3. 机器学习实战 - 读书笔记(13) - 利用PCA来简化数据

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第13章 - 利用PCA来简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. ...

  4. 机器学习实战 - 读书笔记(12) - 使用FP-growth算法来高效发现频繁项集

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第12章 - 使用FP-growth算法来高效发现频繁项集. 基本概念 FP-growt ...

  5. 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...

  6. 机器学习实战 - 读书笔记(07) - 利用AdaBoost元算法提高分类性能

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习笔记,这次是第7章 - 利用AdaBoost元算法提高分类性能. 核心思想 在使用某个特定的算法是, ...

  7. iPhone与iPad开发实战读书笔记

    iPhone开发一些读书笔记 手机应用分类1.教育工具2.生活工具3.社交应用4.定位工具5.游戏6.报纸和杂志的阅读器7.移动办公应用8.财经工具9.手机购物应用10.风景区相关应用11.旅游相关的 ...

  8. Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)

    前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...

  9. spring实战学习笔记(一)spring装配bean

    最近在学习spring boot 发现对某些注解不是很深入的了解.看技术书给出的实例 会很疑惑为什么要用这个注解? 这个注解的作用?有其他相同作用的注解吗?这个注解的运行机制是什么?等等 spring ...

随机推荐

  1. PlantUML + Chrome 联合使用

    之前都是本地下载安装一个PlantUML,安装过程有点复杂,涉及到的其他插件也有些多. 后面发现Chrome浏览器上提供了相关插件,整个过程简直太流畅了.记录下. 安装: 打开Chrome的线上应用商 ...

  2. Vuex学习笔记(-)安装vuex

    什么是Vuex? vuex是一个专门为vue.js应用程序开发的状态管理模式.即data中属性同时有一个或几个组件同时使用,就是data中共用的属性. 安装vuex(前提是已经安装好vue-cli脚手 ...

  3. 关于node_js的比较

    node_js的比较是我自己初学遇到的第一个绕脑的事情. 在比较的函数多了之后,一些函数的调用和变量提升, 搞得自己头晕,有时候函数是没有返回值的,自己还在 用变量值去比较,实际上却是undefine ...

  4. python-并发初学

    一.操作系统简单介绍 1.多道技术:(重点)系统内可同时容纳多个作业.这些作业放在外存中,组成一个后备队列,系统按一定的调度原则每次从后备作业队列中选取一个或多个作业进入内存运行,运行作业结束.退出运 ...

  5. pyCharm-激活码(2018)

    最近使用pycharm的时候,用的是很久以前的激活地址 于是网上到处寻找最新地址,然而 网上之前分享的激活地址已经多半过期, 于是找朋友帮忙,终于找到一个可用的了 1.选择 Activate new ...

  6. 文件操作fopen

    这块所谓的"文件操作"就是把文件的内容读进程序,然后根据具体的格式进行解析,或者是显示,或者是修改. 也就是把一个文件加载到程序里面,然后对其进行修改. 文件操作就三步(固定的三步 ...

  7. Django 安装配置

    1-安装Python3.6.1 Python2.x 与3.x的版本在语法上稍有不同,区别在于输出语句的不同,这个可以看相关的文档. Python3.6.1,可以在Python的官网上下载:https: ...

  8. Java 使用 Redis存储系统

    redis是一个key-value存储系统.它支持存储的value类型很多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希 ...

  9. Day-01

    昨天学习的内容都是一些简单的入门知识 like:二进制,编程语言这些 我觉得二进制还蛮好玩的 对于ascii码 还好,我不是很陌生 因为学函数的时候,老师有讲到这些 嗯 昨天就这些 继续加油~~~

  10. LeetCode 148 排序链表

    题目: 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2 ...