Spring Bean的装配 -- 自动装配

来源:互联网 发布:php blog 模板 编辑:程序博客网 时间:2024/04/28 20:06

        • 什么是装配
        • Spring 装配的方式
        • 三种方式的选择
        • Bean自动扫描创建
          • 补充
        • 自动装配
        • 总结
        • 最后

什么是装配

在spring中,对象无需自己查找或创建与其关联的其他对象,容器负责把需要相互协作的对象引用赋予各个对象。而创建对象之间协作关系的行为通常称为装配。

Spring 装配的方式

在Spring中,有三种主要的方式用来装配Bean:
1. 隐式Bean的发现机制和自动装配
2. 显式装配:
  - 在Java中显式装配
  - 在XML中显式装配

三种方式的选择

在《Spring in action》一书中,作者这样建议道:
首选自动配置的机制,显示配置越少越好。当必须要显式装配Bean时,优先选择类型安全更好的JavaConfig方式。只有想使用XML便利的命名空间并且JavaCofig没有相同的实现的时候,才使用XML的方式显式装配。

Bean自动扫描创建

我们按照推荐的顺序来整理Spring下Bean的装配。首先就是自动装配的方式。
Spring从两个角度来实现自动化配置:

  1. Component Scanning:Spring会自动发现应用上下文中所创建的Bean
  2. Autowiring:Spring自动满足Bean之间的依赖。

接下来我们通过程序的方式来了解这种装配方式:
首先导入Spring-4.2.8的相关jar包.

文章中,我使用Eclipse来作为开发工具。我们所要创建的类大概就只有这些。
所需类
我们需要创建一个Bean类,这个Bean类的特点就只有可被发现,这样在自动装配的时候,可以被自动的扫描到,并且被装配。

  • 创建Human接口
package com.blaze.sherlock.interfacespublic interface Human{  void fuck();}

创建该接口的目的是为了降低耦合,它定义了人类对一个人所能做的事情。同时,创建一个该接口的实现,该接口可以有很多实现,现在我们就只创建一个。

  • 创建Male实现
package com.blaze.sherlock.implementsclass;import org.springframework.stereotype.Component;import com.blaze.sherlock.interfaces.Human;@Componentpublic class Male implements Human{    private String name= "LeiOu";    private String object = "Small monster";    @Override    public void fuck(){        System.out.println(name + " fucked " + object);    }}

这个地方,我们很容易可以注意到Male类被@Component注解标示着,这个注解表示该类会被作为一个组件类,并且由Spring为这个类创建Bean。
既然我们标示了一个类,告诉Spring,你要搞定它并且自动帮我创建Bean,不要老夫亲自去弄。但是,组件扫描默认是不启用的,也就是说,我们必须显示的配置Spring,让它知道扫描带有@Component注解的类,并为它创建bean。
这里我们使用一个简单的配置。

  • 创建HumanFuckConfig配置类
@Configuration@ComponentScan("com.blaze.sherlock.implementsclass")public class HumanFuckConfig {}

这里同样有个地方需要注意一下,对于注解@ComponentScan,这个注解是用于启动Spring中组件扫描,帮助我们去扫描被注解@Component标示的类,在仅有@ComponentScan注解没有其他配置的情况下,默认是扫描当前配置类所在的包。
我们可以通过类似上面的方式来指定所要扫描的包,其实上面@ComponentScan的写法是

“`java
@ComponentScan(basePackages=”com.blaze.sherlock.implementsclass”)

> 的简写,注意,这里的basePackages并不一定代表一个字符串,我们可以通过数组的方式来指定需要扫描的包,例如:> ```java@ComponentScan(basePackages={"implementsclass","anotherimplementsclass"})

同样,我们也可以通过

@ComponentScan(basePackageClasses = Human.class)

的注解方式来锁定所要扫描的类。
这个时候,我们基本已经做到了一个简单的实例,即Spring可以自己查找到我想要它自动创建的bean类,我们需要通过测试来判断Human是不是真的被创建出来了。

  • 创建HumanFuckTest类
package comb.blaze.sherlock.testclass;import static org.junit.Assert.*;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 com.blaze.sherlock.configuration.HumanFuckConfig;import com.blaze.sherlock.implementsclass.Male;import com.blaze.sherlock.interfaces.Human;@RunWith(SpringJUnit4ClassRunner.class)//@ContextConfiguration(classes=com.blaze.sherlock.configuration.HumanFuckConfig.class)@ContextConfiguration(classes = Male.class)public class HumanFuckTest {    @Autowired    private Male h;    @Test    public void testH(){        assertNotNull(h);        System.out.println(h);    }}

实验结果
这里,我们成功创建了Male的Bean。这里我们简单介绍一下HumanFuckTest中的内容。SpringJUnit4ClassRunner,可以让在测试开始的时候自动创建Spring的应用上下文。而ContextConfiguraion告诉该Test需要在HumanFuckConfig中加载配置,虽然我们现在什么都没有写。

补充

我们不仅可以通过HumanFuckConfig来启动自动扫描,还可以通过XML的方式来启动自动扫描。
主要使用的就是这么一个标签。

<context:component-scan base-package="com.blaze.sherlock.implementclasses"/>

自动装配!!

在应用程序中,如果所有的对象都是孤立的,那就搞不起来事情。很多对象只有依赖其他对象才能搞出事情,这里,我们通过为bean类添加注解,让组件扫描得到的bean类和它们的依赖装配在一起,为了搞事情。
到了这里,最重点的仍然是@Autowired注解,它不仅可以用于构造方法上,还可以用于Setter或是其他方法。话说多容易乱,先上代码:

  • MetalHuman 接口
package com.blaze.sherlock.interfaces;public interface MetalHuman {    void fuck_02();}
  • MetalMale 类
package com.blaze.sherlock.implementsclass;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import com.blaze.sherlock.interfaces.Human;import com.blaze.sherlock.interfaces.MetalHuman;@Componentpublic class MetalMale implements MetalHuman{    private Human h;    @Autowired(required = false)    public MetalMale(Human h){        this.h = h;    }    @Override    public void fuck_02() {        // TODO Auto-generated method stub        if(h != null){            h.fuck();        }    }    @Autowired(required = false)    public void setHuman(Human h){        this.h = h;    }    public void fuck() {        // TODO Auto-generated method stub    }}

这里我们看到,MetalMale类仍然被@Component注解标记着,同时,在该类的构造方法上,我们写上了

@Autowired(required = false)

这样一段代码。通过它,我们完成了对Human的自动装配,实现了MetalMale对Human的依赖。
通过这样,Spring会尝试满足方法参数上所声明的依赖,假如有且只有一个bean匹配这样的依赖需求的话,那么这个bean类就会被装配进来。而如果没有匹配依赖需求的bean,Spring就会抛出异常,这样,通过@Autowired后括号中 required = false 表达式,让Spring在没有匹配依赖需求的bean时可以让这个bean处于未装配状态,而不会去抛出相关异常。这个时候,我们就需要对装配的bean进行判空,所以在通过Human对象h调用fuck方法时,我们先对 h 进行了判空。
写完了装配代码,接着就是对装配是否成功的测试。

  • 编写 HumanFuckTest 类
package comb.blaze.sherlock.testclass;import static org.junit.Assert.*;import org.junit.Rule;import org.junit.Test;import org.junit.contrib.java.lang.system.StandardOutputStreamLog;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 com.blaze.sherlock.configuration.HumanFuckConfig;import com.blaze.sherlock.interfaces.Human;import com.blaze.sherlock.interfaces.MetalHuman;@RunWith(SpringJUnit4ClassRunner.class)//@ContextConfiguration(classes=com.blaze.sherlock.configuration.HumanFuckConfig.class)//@ContextConfiguration(classes = Male.class)@ContextConfiguration(classes = HumanFuckConfig.class)public class HumanFuckTest {    @Rule    public final StandardOutputStreamLog log = new StandardOutputStreamLog();    @Autowired    private MetalHuman mh;    @Autowired    private Human h;    @Test    public void hMustNotBeNull(){        assertNotNull(h);        System.out.println(h);    }    @Test    public void fuck(){        mh.fuck_02();        System.out.println(log.getLog());    }}

测试结果

总结

至此,spring通过隐式的发现机制和自动装配来配置bean的简单实现就完成了。接下面几个博客会依次贡献Java显式装配、XML显式装配的内容。

最后

欢迎大家访问我的博客