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之间的依赖
举个例子:
如图所示,在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); } }
运行成功。
问题,我们当一个接口有一个实现类的时候,装配成功了。就像之前说的,在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); } }
我们再调用一次。
我们发现调用失败了,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); } }
-
显示配置Bean之java代码
当我们有的时候无法为bean添加@component的方法,有时候这个类不是我们创建的,那么就无法使用自动装配的方式了,显而易见,spring就不会发现这个bean了,那么怎么办,spring有两个解决方式,分别是java显示配置和xml显示配置,现在先说一下使用java显示代码配置。
我们还是这个例子,然后把PhonePayServiceImpl实现类注掉,保证payservice先有一个实现类以便测试。然后将ComputerPayServiceImpl中的@component去掉,这样我们payconfig进行包扫描时,因为ComputerPayServiceImpl没有@component注解,那么spring就不会发现bean。我们测试一下。
测试结果为:
错误信息显示,确实spring无法找到这个bean。
这个时候我们在javaConfig下显示的配置bean。
@bean注解:告诉spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文的bean。方法体中包含了最终产生bean实例的逻辑。
默认情况下,bean的ID与带有@Bean注解的方法名是一样的,如下图的话,bean的名字就是getPayService。也可以使用@Bean的name属性指定。
我们再运行一下我们的测试类,运行成功了(注:这里使用@Autowired注解也会测试成功)
测试结果成功。
接下来同上,两个实现类怎么解决。好了,我们打开另一个实现类PhonePayServiceImpl。
测试结果看一下:
测试成功。
转载于:https://my.oschina.net/WEguo/blog/1584099