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.interfaces
public interface Human{
  void fuck();
}

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

  • 创建Male实现
package com.blaze.sherlock.implementsclass;
import org.springframework.stereotype.Component;
import com.blaze.sherlock.interfaces.Human;
@Component
public 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;
@Component
public 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显式装配的内容。

最后

欢迎大家访问我的博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值