cheatsheet

如果你赶时间,可以只看这一节的内容。

bean 的实例化方式

  • XML 配置时
    • 工厂方法
    • 静态工厂
    • 构造函数
  • 注解方式

关于注解方式:

  1. @Component:可以用于注册所有bean
  2. @Repository:主要用于注册dao层的bean
  3. @Controller:主要用于注册控制层的bean
  4. @Service:主要用于注册服务层的bean

Spring bean 的注入方式

  • XML配置
    • setter 方法注入
    • 构造函数注入
    • 工厂方法/静态工厂
  • 注解方式注入(@AutoWired

Configuration Metadata

container magic

如上图,Spring IoC container 需要 Configuration MetadataPOJO 来完成依赖注入。Configuration Metadata 就是我们配置这些类的依赖关系的地方。

configuration metadata 可以分为三种方式。文档中写到:“The configuration metadata is represented in XML, Java annotations, or Java code. It allows you to express the objects that compose your application and the rich interdependencies between such objects.”

Bean 的实例化方式

不讲清前提的讲解都是耍流氓,JavaEE 的课上,老师一来就讲 Bean 的实例化方式一共有三种,然后一大堆 XML 配置就来了。

首先,要澄清的一点,这里讲的 Bean 的实例化方式是在 configuration metadata 为 XML 的情况下才成立。如果 configuration metadata 是注解形式的话,情况就变得更简单了。

对于使用 XML 配置 configuration metadata 时,实例化 bean 有三种方式:构造方法,静态工厂模式,工厂模式。

用一个例子来说明这三种情况:

首先创建 Bar 和 Foo 这两个POJO,并且 Foo 依赖于Bar,使用setter方法进行依赖注入。

1
2
3
4
5
6
7
public class Foo {
  private Bar dependency1;

  public void setDependency1(Bar dependency1) {
    this.dependency1 = dependency1;
  }
}
1
2
3
4
5
6
7
public class Bar {
  private String foobar;

  public Bar(String foobar) {
    this.foobar = foobar;
  }
}
  • 构造方法是最普通的一种,和其他bean的配置一样。

  • 静态工厂模式利用静态工厂的设计模式,在XML注册工厂方法,而巧妙之处在于被注入的不是工厂的实例,而是bean的实例。Spring会反射调用 getInstance 得到 bean 实例,并进行依赖注入。

  • 普通工厂模式则需要实例化工厂,再实例化bean。

注意三种不能同时使用,要使用其中一种时,需要注释掉下面代码的另外两种即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<bean id="foo" class="leer.moe.springdemo.bean.Foo">
<property name="dependency1" ref="bar"/>
</bean>

<!--静态工厂模式-->
<bean id="bar" class="leer.moe.springdemo.bean.StaticBarFactory" factory-method="getInstance">
<constructor-arg value="static factory"/>
</bean>

<!--工厂方法模式-->
<bean id="barFactory" class="leer.moe.springdemo.bean.NoneStaticBarFactory"/>

<bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>
<!--构造方法-->
<bean id="bar" class="leer.moe.springdemo.bean.Bar">
<constructor-arg value="constructor"/>
</bean>

静态工厂的 Java 代码:

1
2
3
4
5
public class StaticBarFactory {
  public static Bar getInstance(String foobar) {
    return  new Bar(foobar);
  }
}

XML 中 class 属性为leer.moe.springdemo.bean.StaticBarFactory,factory-method 为 getInstance。只要这样设置就可以获得Bar的实例,而不是静态工厂的实例。

工厂方法的 Java 代码:

1
2
3
4
5
public class NoneStaticBarFactory {
  public Bar getInstance() {
    return new Bar("none static factory");
  }
}

工厂方法不是静态的,但是对于Spring来说,他也只是一个普通的Bean可以进行实例化和依赖注入。在 XML 配置中可以看到,我们先配置了barFactory这个工厂的Bean。之后,在bar中,使用 factory-bean="barFactory",使用工厂实例来构建bar实例。

依赖注入

在完成 bean 的实例化后(也就是配置好 bean 的 configuration metadata),我们就可以把 bean 注入到需要使用的地方。依赖注入主要有两种:构造方法注入、setter方法注入和注解方式注入。可以同时使用的。

使用依赖注入的优点?解耦。文档里是这样的说的:“Code is cleaner with the DI principle, and decoupling is more effective when objects are provided with their dependencies.”当然这些都是教条式的,看了一遍不会懂,即使看了很多篇也不会懂。需要不断的练习和在项目中体会。

XML Configuration Metadata :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Bean3 {
  private String dependency1;
  private String dependency2;
  private Bean2 dependency3;

  public Bean3(String dependency1) {
    this.dependency1 = dependency1;
  }

  public void setDependency2(String dependency2) {
    this.dependency2 = dependency2;
  }

  public void setDependency3(Bean2 dependency3) {
    this.dependency3 = dependency3;
  }
}
1
2
3
4
5
6
7
8
9
    <bean id="bean2" class="moe.leer.springdemo.bean.Bean2" scope="prototype">
        <constructor-arg value="111" index="1"/>
        <constructor-arg value="222" index="0"/>
    </bean>
	<bean id="bean3" class="moe.leer.springdemo.bean.Bean3" scope="singleton">
        <constructor-arg value="constructor"/>
        <property name="dependency2" value="setter"/>
        <property name="dependency3" ref="bean2"/>
    </bean>

注解 @AutoWired

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Bean3 {
  private Bean1 dependency1;
  private Bean2 dependency2;

  @Autowired
  public Bean3(Bean1 dependency1) {
    this.dependency1 = dependency1;
  }

  @Autowired
  public void setDependency2(Bean2 dependency2) {
    this.dependency2 = dependency2;
  }
}