2、Spring之自动化装配

Spring Context负责创建bean,又使用DI(依赖注入)满足bean之间的依赖。接下来我们谈如何使用。

环境:

所需manven包

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <!-- <scope>test</scope> -->
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${spring.version}</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>${spring.version}</version>
</dependency>

使用的spring.version 是3.2.9

我们注意到junit 的下面有一个<scope>test</scope>,是什么意思呢。说明这个jar只会在你测试的resourse 下才会被使用,正常的代码区域是不会被引用的。所以,在做测试的情况下如果没有建立测试的resourse的话,需要把这个注掉。

  • 使用注解形式:

       之前我们一定接触过Spring,多数是用Spring xml的配置进行的。我们这次使用注解方式进行使用。

        Spring从两个角度来实现自动化装配:

  • 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean
  • 自动装配(autowiring):Spring自动满足bean之间的依赖

      举个例子:

      2、Spring之自动化装配

如图所示,在java文件夹下建立action包逻辑处理,config 配置文件包,service接口包,以及impl实现类包。然后我们像做项目一样,需要一个支付的模块,分别建立一个pay子包。

     先介绍几个spring用到的注解

     @Configuration:spring将这个类设置为config

     @ComponentScan:这个注解在spring中启动扫描

     @Component:使用这个注解,就可以使类能够让spring扫描到。

    先看我们的支付接口Payservice,它只有一个方法,就是支付

package service.pay;

public interface Payservice {
    void pay(Integer num);
}

然后是我们的手机支付的实现类,继承Payservice接口

我们使用@Component使这个类在spring能够发现这个类,并进行创建bean。创建的bean会有名字,如果@Component不写的话,那么就是phonePayServiceImpl,如果写了的话创建的名字就是你写的那个@Component(value = "phonePayServiceImpl")。

package impl.pay;

import org.springframework.stereotype.Component;
import service.pay.Payservice;
@Component
public class PhonePayServiceImpl implements Payservice{
    public void pay(Integer num) {
        System.out.println("使用手机支付了"+num);
    }
}

来写我们的PayConig

@Configuration Spring在启动时会寻找这个注解,知道他是config类,然后再进行相关操作。

@ComponentScan:需要扫描的包,如果不写其他的话,它会扫描的读当前包下的所有文件。我们把PayConfig放在impl.pay下就可以了。如果你想像我一样,将配置类统一管理的话,那么就明确一下包路径。当然你也可以建立一个JavaConfig类,然后设置为它的总包路径impl就可以了。

package config.pay;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "impl.pay")
public class PayConfig {

}

现在我们测试一下是否成功

@Autowired 我们完成以上的操作,spring已经发现了需要创建的bean,但是没有将需要创建的bean的其他对象进行装配,这时候使用@Autowired 就可以完成自动装配

package pay;

import config.pay.PayConfig;
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 service.pay.Payservice;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PayConfig.class)
public class PayTest {

    @Autowired
    private Payservice payservice;

    @Test
    public void test(){
        payservice.pay(100);
    }
}

2、Spring之自动化装配

运行成功。

问题,我们当一个接口有一个实现类的时候,装配成功了。就像之前说的,在PayTest中,我们只是调用了pay接口,它是使用电脑支付、手机支付我们都不知道,完成了解耦。但是如果两个实现类我们建立后,在PayTest会装配到底会装配哪一个实现类呢,我们做一下测试,新建一个实现类computerPayServiceImpl。

package impl.pay;

import org.springframework.stereotype.Component;
import service.pay.Payservice;

@Component(value = "computerPayServiceImpl")
public class ComputerPayServiceImpl implements Payservice{
    public void pay(Integer num) {
        System.out.println("使用电脑支付了"+num);
    }
}

我们再调用一次。

2、Spring之自动化装配

我们发现调用失败了,spring不知道到底该调哪一个。但是这种场景经常出现,我们该怎么办?

这个时候我们就不使用@Autowired这个注解了,使用@Resource注解,并指明name名字就可以了

package pay;

import config.pay.PayConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.pay.Payservice;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PayConfig.class)
public class PayTest {


    @Resource(name = "computerPayServiceImpl")
    private Payservice payservice;

    @Test
    public void test(){
        payservice.pay(100);
    }
}

2、Spring之自动化装配

  • 显示配置Bean之java代码

    当我们有的时候无法为bean添加@component的方法,有时候这个类不是我们创建的,那么就无法使用自动装配的方式了,显而易见,spring就不会发现这个bean了,那么怎么办,spring有两个解决方式,分别是java显示配置和xml显示配置,现在先说一下使用java显示代码配置。

    我们还是这个例子,然后把PhonePayServiceImpl实现类注掉,保证payservice先有一个实现类以便测试。然后将ComputerPayServiceImpl中的@component去掉,这样我们payconfig进行包扫描时,因为ComputerPayServiceImpl没有@component注解,那么spring就不会发现bean。我们测试一下。

2、Spring之自动化装配

2、Spring之自动化装配

测试结果为:

2、Spring之自动化装配

错误信息显示,确实spring无法找到这个bean。

这个时候我们在javaConfig下显示的配置bean。

@bean注解:告诉spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文的bean。方法体中包含了最终产生bean实例的逻辑。

默认情况下,bean的ID与带有@Bean注解的方法名是一样的,如下图的话,bean的名字就是getPayService。也可以使用@Bean的name属性指定。

2、Spring之自动化装配

我们再运行一下我们的测试类,运行成功了(注:这里使用@Autowired注解也会测试成功)

2、Spring之自动化装配

测试结果成功。

接下来同上,两个实现类怎么解决。好了,我们打开另一个实现类PhonePayServiceImpl。

2、Spring之自动化装配

2、Spring之自动化装配

测试结果看一下:

2、Spring之自动化装配

测试成功。

转载于:https://my.oschina.net/WEguo/blog/1584099