Spring有两个特性,DI(依赖注入)和AOP(面向切面编程),而想要实现DI,首先得学会如何把Bean装配到容器中,以实现应用对象间保持松散耦合。

为什么需要DI

可能DI(依赖注入)这个词本身就不太好理解,首先我们先来看看官方的定义:

依赖注入会将所依赖的关系自动交给目标对象,而不是让对象自己去获取依赖。

比方说,你所要写的A类需要使用到B类的方法,

  • A自己去获取B依赖:在A类属性中申明B,然后再A的构造函数中new一个B对象。
1
2
3
4
5
6
7
8
9
10
Class A{
private B b;
public A(){
b = new B();
}
public void useB(){
System.out.println("I am A, I use B to do sth.");
}

}
  • B注入到A:在A类属性中申明B,通过带有B参数的构造函数获取B。
1
2
3
4
5
6
7
8
9
10
Class A{
private B b;
public A(B b) {
this.b = b;
}

public void useB(){
System.out.println("I am A, I use B to do sth.");
}
}

我们可以看到,第二种方式(注入方式)灭有自己创建B对象,而是在构造的时候吧B对象作为构造器参数传入。这也是依赖注入方式之一,即构造器注入(construction injection)。

很多小伙伴看到这里就要问了,有差吗?有差。

一方法的B对象是绑定死的;二方法的对象是灵活的,因为B类型可以是接口类型,只要实现了B接口的类都能通过二方法注入到A。我用个图表示一下两者的差别:
DI

从图中局很好理解,主动获取是紧耦合的,而依赖注入是松散耦合的。这就是我们需要DI的原因,不知道各位客官想通了咩有。

装配Bean

到目前为止,因为B没有实例化,所以A还是无法使用B的,而我们同样也还是是用不了A,原因也是一样。如果写一个主类,在主类里头使用A和B,我们应该会很熟悉,代码如下:

1
2
3
4
5
6
public class Main{
public static void main(String[] args){
B b = new C(); // C实现了B接口,见上图
A a = new A(b);
}
}

但是如果有很多个类都需要实例化,都写在main中不免会有些臃肿,如果把这些配置写在另一个统一的类,岂不是更加?我们就把这些配置剥离到一个名为Config类中。

1
2
3
4
5
6
7
8
9
10
class Config{
B b = new C();
A a = new A(b);
}

public class Main{
public static void main(String[] args){
// 怎么拿到b对象和a对象?
}
}

现在的问题是,main函数怎么拿到b对象和a对象呢?我们需要Configure conf = new Configure();,然后从conf中获取。

1
2
3
4
5
6
7
public class Main {
public static void main(String[] args) {
Configure configure = new Configure();
// 别忘了实现a的getter方法
configure.a.useB();
}
}

其实我认为上述就是我们可以用Spring框架解决这个问题。我们修改一下Config类,改成如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class Config{
@Bean
public A a(){
return new A(b());
}

@Bean
public B b(){
return new C();
}
}

我们使用@Configuration注解了Config类,生成了两个bean,Spring就会根据@Bean注解把bean放到它的容器之中,即取即用。
container

具体怎么拿出来,我们看下面的代码:

/**
 * @author wangxiaobin
 */

public class Main {
    public static void main(String[] args) {
          // 申明上下文
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext();
        // 注册Configure类
        context.register(Configure.class);
        context.refresh();
            // 获取A类
        A a = context.getBean(A.class);
        a.useB();
    }
}

我们使用AnnotationConfigApplicationContext申明一个Spring上下文,并且告诉它配置类是Configure.class,这样它就能知道有多少bean是需要被加载到容器中的,然后用getBean()方法取出即可。

Comments

⬆︎TOP