装配 Bean 的方式

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

Spring 提供了以上三种方式进行 Bean 的配置,可以根据自己的需求选择一种或者混合使用。但是我的个人建议还是尽可能的使用自动配置机制,毕竟显式的配置越少越方便。但如果必须要显示的配置 bean 的时候,推荐使用比 XML 类型安全更好的 JavaConfig 方式。

自动化装配 Bean

Spring 通过如下两个方式来实现自动化装配:

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

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

实例

1.添加 maven 依赖

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.20.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.20.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

2.创建一个 bean

@Component
public class CompactDisc { public void play(){
System.out.println("开始播放");
}
public void pause(){
System.out.println("暂停播放");
} public void stop(){
System.out.println("停止播放");
}
}

@Component 注解表示申明这个类为组件类。


3.创建一个配置类并开启组件扫描

@Configuration
@ComponentScan
public class ApplicationConfig { }

@Configuration 表示这是一个配置类

@ComponentScan 表示开启组件扫描


4.创建单元测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ApplicationConfig.class})
public class CompactDiscTest { @Autowired
private CompactDisc compactDisc;
@Test
public void test(){
compactDisc.play();
} }

运行,查看控制台输出:

开始播放

bean 命名

在 Spring 中如果没有明确给 bean 指定一个 ID 的话,Spring 会将类名首字母小写作为它的默认 ID。 如果要指定 ID 的话,可以采用如下形式的注解:

@Component("指定ID名")

@ComponentScan

像上面的实例中,没有指定扫描包的路径的话,会默认将当前类所在的包当作基础包来扫描(即:只扫描当前包和子包)。

如果需要扫描其他包的话需要使用 basePackages 或 basePackageClasses 属性,两者的区别在于一个接收的参数是字符型而另一个接收的参数是类。并且它们两个都是复数的形式,表示它们可以接收多个值。

@ComponentScan(basePackages = {"com.marklogzhu.bean","com.marklogzhu.service"})
@ComponentScan(basePackageClasses = {CompactDisc.class,UserService.class})

basePackageClasses 相比于 basePackages 属性更安全,不会因为重构包名导致路径错误,basePackageClasses 申明类所在的包就是作为扫描的基础包。

注:可以在这些包里新建一个与功能无关的空接口来作为 basePackageClasses 的值,避免因为功能重构导致 类/接口 被移除。


自动装配

在实例中我们通过 @Autowired 注解 实现了 bean 的自动装配。除了属性之外还可以在方法上也增加 @Autowired 注解 实现 bean 的注入。

如果没有匹配到 bean 的话,Spring 将会抛出一个 UnsatisfiedDependencyException 异常。为了避免此异常的出现,可以将 **@Autowired ** 的 required 属性设置为 false。当 Spring 匹配不到 bean 的时候会将这个 bean 设置为未装配状态。 要注意的是如果你的代码没有对这个 bean 进行 null 检查的话,就会抛出 NullPointerException 异常,所以请谨慎使用这个属性。

如果匹配到多个 bean 的话,Spring 也会抛出一个 NoUniqueBeanDefinitionException 异常,表示没有明确指明使用哪个 bean 来进行自动装配。

@Autowired 是 Spring 特有的注解,如果你不想使用它的话,也可以使用 jsr330规范 的 @Inject 注解,两者的功能在大多数情况下都是一样的。


JavaConfig 显式装配

在使用第三方库的时候就无法使用自动化配置,只能采用显式装配。显式装配有两种方式:

  • JavaConfig
  • XML

这里我们先讲 JavaConfig。JavaConfig 从语法上和普通的 Java 代码没有区别,但是概念上却有所区别,它不应该包含任何业务逻辑。一般来说都会将这些配置类单独放到一个包下,使其和业务逻辑相分离。


实例

**1.JavaConfig 显式声明 Bean **

我们移除之前的 ApplicationConfig 类上的 @ComponentScan 注解。采用 JavaConfig 的方式申明 Bean。

@Configuration
public class ApplicationConfig { @Bean
public CompactDisc compactDisc(){
return new CompactDisc();
} }

2.运行之前的单元测试类,查看控制台输出

开始播放

可以看到结果跟之前的一致。


通过 @Bean 注解创建的 bean 的 Id 默认就是方法名,如果需要命名成不同的也可以使用 @Bean 注解 的 name 属性。

如果一个 bean 的创建需要另一个 bean 的话,可以采用如下的方式声明:

@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}

XML 显式装配

在 Spring 刚刚出现的时候,XML 是描述配置的主要方式,但是现在已经有了自动化配置 和 JavaConfig 显式配置,XML 的使用应该只是用于维护老项目而不是使用到新的项目中去。

实例

** 1.创建 xml 文件 等同于 @Configuration 注解**

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>

**2.申明 bean 等同于 @Bean 注解 **

<bean id="compactDisc" class="com.marklogzhu.bean.CompactDisc"/>

可以没有设置 Id 的话,默认名就会是 com.marklogzhu.bean.CompactDisc#0 。其中 #0 是一个计数的形式,用于和其他 bean 区分。

3.新建单元测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class XmlTest { @Autowired
private CompactDisc compactDisc; @Test
public void test() {
compactDisc.play();
} }

运行查看控制台输出:

开始播放

有这么一个班级类,它里面有班级名称、一个老师、一群学生和课程列表,我们来看看怎么通过 **xml ** 形式注入:

public class Class {

    private String name;

    private Teacher teacher;

    private List<Student> students;

    private List<String> courses;

    public Class(){

    }

    public Class(String name) {
this.name = name;
} public Class(String name, Teacher teacher) {
this(name);
this.teacher = teacher;
} public Class(String name, Teacher teacher, List<String> courses) {
this(name,teacher);
this.courses = courses;
} public Class(String name,Teacher teacher, List<String> courses, List<Student> students) {
this(name,teacher,courses);
this.students = students;
} public String getName() {
return name;
} public Teacher getTeacher() {
return teacher;
} public List<Student> getStudents() {
return students;
} public List<String> getCourses() {
return courses;
}
public void setName(String name) {
this.name = name;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} public void setStudents(List<Student> students) {
this.students = students;
} public void setCourses(List<String> courses) {
this.courses = courses;
}
}

public class Teacher { public String startWorking() {
return "老师教学";
}
} public class Student { public String startWorking() {
return "学生学习";
}
}

构造器注入--字符串

<bean id="aClass" class="com.marklogzhu.bean.xml.Class">
<constructor-arg name="location" value="B栋二楼"/>
</bean>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class XmlTest { @Autowired
private Class javaClass; @Test
public void test_01() {
Assert.assertEquals(javaClass.getName(),"Java学习");
} }

注:constructor-arg 不显式声明 name 属性那么将会按先后顺序赋值。

构造器注入--对象

<bean id="teacher" class="com.marklogzhu.bean.xml.Teacher"/>

<bean id="aClass" class="com.marklogzhu.bean.xml.Class">
<constructor-arg name="name" value="Java学习"/>
<constructor-arg name="teacher" ref="teacher"/>
</bean>
@Test
public void test_02() {
Assert.assertEquals(javaClass.getName(),"Java学习");
Assert.assertEquals(javaClass.getTeacher().startWorking(),"老师教学");
}

构造器注入--字符串 List

<bean id="aClass" class="com.marklogzhu.bean.xml.Class">
<constructor-arg name="name" value="Java学习"/>
<constructor-arg name="teacher" ref="teacher"/>
<constructor-arg name="courses">
<list>
<value>JavaSe</value>
<value>Sql</value>
<value>JS</value>
</list>
</constructor-arg>
</bean>
@Test
public void test_03() {
Assert.assertEquals(javaClass.getName(),"Java学习");
Assert.assertEquals(javaClass.getTeacher().startWorking(),"老师教学");
Assert.assertEquals(javaClass.getCourses().size(),3);
}

构造器注入--对象 List

<bean id="aClass" class="com.marklogzhu.bean.xml.Class">
<constructor-arg name="name" value="Java学习"/>
<constructor-arg name="teacher" ref="teacher"/>
<constructor-arg name="courses">
<list>
<value>JavaSe</value>
<value>Sql</value>
<value>JS</value>
</list>
</constructor-arg>
<constructor-arg name="students">
<list>
<ref bean="student"/>
<ref bean="student"/>
</list>
</constructor-arg>
</bean>
@Test
public void test_04() {
Assert.assertEquals(javaClass.getName(),"Java学习");
Assert.assertEquals(javaClass.getTeacher().startWorking(),"老师教学");
Assert.assertEquals(javaClass.getCourses().size(),3);
Assert.assertEquals(javaClass.getStudents().size(),2);
}

属性注入

<bean id="aClass" class="com.marklogzhu.bean.xml.Class">
<property name="name" value="Java学习"/>
<property name="teacher" ref="teacher"/>
<property name="courses">
<list>
<value>JavaSe</value>
<value>Sql</value>
<value>JS</value>
</list>
</property>
<property name="students">
<list>
<ref bean="student"/>
<ref bean="student"/>
</list>
</property>
</bean>
@Test
public void test_05() {
Assert.assertEquals(javaClass.getName(),"Java学习");
Assert.assertEquals(javaClass.getTeacher().startWorking(),"老师教学");
Assert.assertEquals(javaClass.getCourses().size(),3);
Assert.assertEquals(javaClass.getStudents().size(),2);
}

可以看到我们把之前的 constructor-arg 替换为 property 了,但是单元测试还是可以通过,说明属性注入成功了。

注:属性注入的前提是类中有 setXX 方法存在。

JavaConfig 显式装配 和 XML 配置混合使用

在 JavaConfig 显式装配中引用 XML 配置

@ImportResource("classpath:applicationContext.xml")

在 XML 配置中引用 JavaConfig 显式装配

  <bean id="compactDisc" class="com.marklogzhu.bean.CompactDisc"/>

Spring学习之旅(三)--装配Bean的更多相关文章

  1. Spring学习笔记(二)之装配Bean

    一,介绍Bean的装配机制 在Spring中,容器负责对象的创建并通过DI来协调对象之间的关系.但是我们要告诉Spring创建哪些Bean并且如何将其装配在一起.,装配wiring就是DI依赖注入的本 ...

  2. Spring 学习指南 第三章 bean的配置 (未完结)

    第三章 bean 的配置 ​ 在本章中,我们将介绍以下内容: bean 定义的继承: 如何解决 bean 类的构造函数的参数: 如何配置原始类型 (如 int .float 等) .集合类型(如 ja ...

  3. Spring学习系列(二) 自动化装配Bean

    一.Spring装配-自动化装配 @Component和@ComponentScan 通过spring注解(@Component)来表明该类会作为组件类,并告知Spring要为这类创建bean,不过组 ...

  4. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  5. Spring入门2. IoC中装配Bean

    Spring入门2. IoC中装配Bean 20131125 前言: 上一节学习了Spring在JavaProject中的配置,通过配置文件利用BeanFactory和ApplicationConte ...

  6. Spring学习之旅(十)--MockMvc

    在之前的 Spring学习之旅(八)--SpringMVC请求参数 我们是通过在控制台输出来验证参数是否正确,但是这样做实在是太耗时间了,我们今天来学习下 MockMvc,它可以让我们不需要启动项目就 ...

  7. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

  8. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  9. Spring学习之旅(四)--高级装配Bean

    条件化 bean 有时候我们要满足某种情况才将bean 初始化放入容器中. 基于环境初始化不同的 bean 1.申明接口并创建两个实现类 public interface Teacher { void ...

随机推荐

  1. 基于ZK的 Dubbo-admin 与 Dubbo-monitor 搭建

    背景 最近项目中使用了 dubbo 在实现服务注册和发现,需要实现对服务提供者和调用者的监控,之前有研究过基于 redis作为注册中心的监控平台,不过本文基于 zk 作为注册中心,进行 dubbo-a ...

  2. 确保Web安全的HTTPS

    HTTP在安全方面主要有以下不足: 1. 通信使用明文不加密,内容可能会被窃听:(TCP/IP就是可能被窃听的网络) 2. 不验证通信方的身份,因此有可能遭遇伪装: (无法判断请求或响应是否正确,是否 ...

  3. Angular JS 中的内置方法之filter

    通过过滤器可以实现很多数据格式化的功能 常用方法形如{{ data | uppercase}} 或者是{{ 123.456 | number:2 }} 也可以通过在控制器中注入$filter来实现功能 ...

  4. android 基于wifi模块通信开发

    这篇文章主要是我写完手机与wifi模块通信后所用来总结编写过程的文章,下面,我分几点来说一下编写的大概流程. 一.拉出按钮控件并设置它的点击事件 二.设置wifi权限 三.打开和关闭wifi 四.扫描 ...

  5. PHP验证身份证格式

    互联网公司对身份证验证的需求越来越多,然而普通的小公司是无法对接公安部门的身份认证系统的.几乎都是在网上买一些大的互联网公司的一些认证服务.即使是便宜一些的认证价格也达到了10万次/万元.也就是一角钱 ...

  6. Something wrong with EnCase v8 index search results

    My friend told me that she installed EnCase v8.05 on her workstation which OS version is Win 10. She ...

  7. linux集群实施与部署-----Nginx

    ( 1 ) 配置基本环境 //安装虚拟工具 #cd /media/VMware\ Tools/ #cp VMwareTools--.tar.gz/tmp/ #cd /tmp/ #tar-xvzf VM ...

  8. CentOS7使用yum安装ceph rpm包

    1. 安装centos7对扩展repo的支持yum install yum-plugin-priorities保证下面的选项是开启的[main]enabled = 1 2. 安装 release.ke ...

  9. Extjs4 combobox hiddenName 后台取不到值

    当我们用 下拉框传值时,有一个问题,就是他有两个值,一个是用来显示的,一个是我们实际往后台需要传递的值,即 name 与 value 所以 combobox 才有了 hiddenName 这个属性,他 ...

  10. java随笔之接口

    /* * 接口大致上可以分为:哑接口,抽象接口,接口类 * 哑接口:就是public,protected(注意protect有包权限,只有本包才开放接口)方法 * 抽象接口:就是哑接口变为抽象方法,在 ...