我在上一篇博客中讨论了Spring中的IOC和AOP,本篇文章通过代码来演示一下Spring到底是如何实现IOC的。本篇博客我会介绍在Spring中如何定义和装载Java Bean。
#业务场景
还是人开车的例子。首先,定义一个Car接口和两个实现了Benz和BMW,然后定义一个Person类,Person类依赖Car接口。
public interface Car {
void go();
}
public class Benz implements Car {
public void go() {
System.out.println("benz go......");
}
}
public class BMW implements Car {
public void go() {
System.out.println("bmw go......");
}
}
public class Person {
String name = "";
Car car = null;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Person(String name) {
this.name=name;
}
public void Drive(){
System.out.println(name+" is driving ...");
car.go();
}
}
在Person类中我们可以看到,car对象是该类的依赖对象,需要通过构造方法注入到Person类中。以上的代码还完全没有Spring的影子,下面看看Spring是如何来注入
#添加Spring依赖
现在很多项目都适用maven来管理依赖,本项目也是如此。我在pom.xml中加入一下依赖节点
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.6.RELEASE</version>
</dependency>
将这些dependency节点放入pom.xml文件的dependencies节点下,eclipse会自动下载相关的包到默认位置。
#手动定义和装配Bean
在项目的根目录中新建一个名叫bean.xml的xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="car" class="kite.springProj1.BMW" />
<bean id="tom" class="kite.springProj1.Person">
<constructor-arg value="Tom" />
<property name="car" ref="car" />
</bean>
</beans>
上面的XML文件首先定义了一个id为car的bean,又定义了一个id为tom的bean,car作为tom的依赖,通过<property name="car" ref="car" />
的方式被手动地装配到了tom的car属性中。
创建应用对象之间协作关系的行为被称为装配(wiring),这也是依赖对象注入的本质。
接下来我们在main方法中实例化一个应用上下文对象,并获取bean中的tom节点
public class App
{
public static void main( String[] args )
{
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Person tom=(Person) context.getBean("tom");
tom.Drive();
}
}
运行程序,输出结果为:
Tom is driving ...
bmw go......
#自动装配
再重复一遍,创建应用对象之间协作关系的行为被称为装配(wiring),而不是实例化对象的过程。在上面的xml文件中,我通过<property name="car" ref="car" />
的方式来装配了依赖对象,但是随着应用的不断发展,xml配置文件肯定会越来越复杂,我们通过ref="car"
来关联id为car的bean的这种方式已经开始落后了。下面我来介绍一下Spring如何实现自动装配bean。
##自动装配的类型
Spring共四种装配策略,为了降低本文的复杂性,我介绍两种常用的策略,byName方式和byType方式。顾名思义,byName方式就是看属性的名字和bean的id是否相同,在本例中,Person类有一个名叫car的属性,如果将该类或改属性设置为自动装配且装配策略为byName的话,Spring会去找id为car(必须是同名)的bean。byType方式是比较类型是否相同。就本例而言,如果将Person类或Person类的car属性设置为自动装配且装配策略为byType的话,由于car属性是Car类型,所以,Spring在进行自动装配时,会去找类型为Car或其子类的bean。
##使用XML实现自动装配
下面我来修改代码,使用xml配置的方式来实现自动装配。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="car" class="kite.springProj1.BMW" />
<bean id="tom" class="kite.springProj1.Person" autowire="byName">
<constructor-arg value="Tom" />
</bean>
</beans>
Person类无需做任何修改。
首先,我去掉了<property name="car" ref="car" />
这行代码,因为它是手工的方式。然后,我将id为tom的bean增加一个属性autowire="byName"
,将其设置为通过名字自动装配依赖,在获取Person对象时,Person的所有属性名称就都有了特殊的含义。Spring监测到了Person类有一个名叫car的属性,并且在配置文件中发现了一个id为car的bean,于是乎,就将其自动装配给了Person的car属性。
上面的代码只设置了spring对一个bean进行自动装配,也可以设置一个全局的默认装配方式,spring就会对所有的bean都使用这种方式来自动装配。在<beans>
节点上设置一个default-autowire
属性即可。这个属性的默认值是no
。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byType">
<bean id="car" class="kite.springProj1.BMW" />
<bean id="tom" class="kite.springProj1.Person">
<constructor-arg value="Tom" />
</bean>
</beans>
设置了一个全局的默认装配方式,并不意味着所有的bean都不能使用别的装配方式进行自动装配,每个bean仍然可以指定另外的装配方式来覆盖全局的方式。
##通过注解实现自动装配
spring还支持使用注解的方式来装配bean的属性,想要使用注解来装配的话,需要先在配置文件中开启它。
我们将bean.xml做如下修改
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="car" class="kite.springProj1.BMW" />
<bean id="tom" class="kite.springProj1.Person">
<constructor-arg value="Tom" />
</bean>
</beans>
我没有在bean中声明自动装配方式,也没有声明全局的自动装配方式,仅仅是添加了一行<context:annotation-config />
,来告诉spring我要使用注解来装配bean的依赖属性。然后对Person 类做一点修改,在car的setter方法上加上@Autowired注解,来通知Spring对该属性进行自动装配。重新运行代码,输出结果不变。
@Autowired
public void setCar(Car car) {
this.car = car;
}
当spring创建一个bean的实例时,如果发现某个属性使用了@Autowired
注解,就会尝试使用byType的方式来装配它。@Autowired
不仅可以标注setter方法,还可以标注私有的属性。
在上面的所有代码中,我们在配置文件中都是使用的org.zdk.springProj1.BMW
类作为Person类的依赖,如果由于业务需要,Person类不需要开宝马车而改开奔驰车了,只需要将该配置修改为org.zdk.springProj1.Benz
即可,无需修改任何Java代码,这就是Spring作为IOC容器的强大之处。
另外,spring支持三个类型的注解用来标注自动装配,除了@Autowired
以外,还有JSR-330的@Inject
注解和JSR-250的@Resource
注解,他们的作用都是类似的。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://laozhu.blog.csdn.net/article/details/49227951
内容来源于网络,如有侵权,请联系作者删除!