我们可以把 Spring 看作一个大型的工厂,而 Spring 容器中的 Bean 就是该工厂的产品。要想使用这个工厂生产和管理Bean,就需要在配置文件中告诉它需要哪些 Bean,以及需要使用何种方法将这些 Bean 装配到一起。
首先,分清楚 JavaBean 和 Spring 中的 Bean 区别在哪里,二者是两个概念不同的东西
1.用处不同:传统 javabean 更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean。
2.写法不同:传统 javabean 作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法。
3.生命周期不同:传统 javabean 作为值对象传递,不接受任何容器管理其生命周期;spring 中的 bean 有 spring 管理其生命周期行为。
总结:在 Spring 中,所有可以被 IOC容器 实例化并管理的 Java类 都可以称为 Bean。
Spring 中 Bean 的装配方式有两种:XML 装配和 注解 装配,先说 XML 的方式,下节再写注解装配的方式
Bean的装配(XML方式)
在Spring中,实例化Bean有三种方式,分别为 全类名配置(常用),工厂方法配置(静态工厂方式 和实例工厂方式),配置Bean(基于FactoryBean)
由于第一种方法比较常用,这里只写第一种方法
准备一个 POJO
package com.how2java.pojo;
public class Product {
private int id;
private String name;
private Category category;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
然后通过 全类名配置 的方式配置 XML
<bean id="c" class="com.how2java.pojo.Category">
<!--这种属性注入方式会调用Category类中setName方法-->
<property name="name" value="category 1" />
</bean>
<bean name="p" class="com.how2java.pojo.Product">
<property name="name" value="product1" />
<property name="category" ref="c" />
</bean>
注: 1)id 属性 在 IOC 容器中指的是 Bean 的名称,且在 IOC 容器中必须是唯一的;
2)如果 id 属性和 name 都没有指定,Spring 则会自动将 全类名(即class中的值) 作为 Bean 的名称。
name (指的是Bean的name)和 id 一样,Spring都可以通过这这两个属性对容器中 Bean 进行配置和管理。不同的是,name属性可以为 Bean 指定多个名称,每个名称用逗号或分好隔开,但Bean的 id 在 Spring 中却是唯一的。
依赖注入(DI)的方式
在上面配置 XML 时,DI 用的是 属性注入
<!--这种属性注入方式会调用Category类中setName方法-->
<property name="name" value="category 1" />
这里写两种比较 常用 的注入方式:
1.属性注入(就如上面的代码)
2.构造器注入
使用构造器注入属性值时,可以指定参数的位置和参数的类型,以区分重载的构造器,它依赖于类中的 构造方法。
<bean id="car" class="com.sun.bean.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="203" type="int"></constructor-arg>
</bean>
调用的构造器如下:
public Car(String brand, String carp, int maxSpeed) {
this.brand = brand;
this.carp = carp;
this.maxSpeed = maxSpeed;
}
关于属性注入的更多细节请参考:
https://blog.csdn.net/sun8112133/article/details/80192817
从IOC容器中获取Bean
从 IOC 容器中获取 Bean,调用的是 getBean() 方法,getBean() 方法是在 BeanFactory 接口中定义的,而 ApplicationContext 接口继承了 BeanFactory 接口,它提供了BeanFactory所有功能,同时还以一种更加面向框架的方式增强了BeanFactory的功能,主要体现在Context包使用分层和有继承关系的上下文类。
ApplicationContext在初始化上下文时就实例化所有单例的 Bean,也就是在创建 IOC 容器的时候就实例化所有的单例 Bean。
创建ApplicationContext接口实例,通常采用两种方法
- ClassPathXmlApplicationContext:从类路径下加载 xml 配置文件 (常用)
- FileSystemXmlApplicationContext:从文件系统中加载配置文件
最常用的两种获取 Bean的方式
1.通过id获取IOC中的Bean
Product p = (Product) context.getBean("p");
2.通过 全类名 获取IOC容器中的Bean:
Product p = (Product) context.getBean(Product.class);
package com.how2java.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.how2java.pojo.Product;
public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
Product p = (Product) context.getBean("p");
System.out.println(p.getName());
System.out.println(p.getCategory().getName());
}
}