Spring Framework IOC容器 Bean管理
2021-04-18
9 min read
利用XML进行Bean管理
基本注入
基于 xml 配置文件的 Bean 管理有三种基本注入方式:基于 Setter 方法注入、基于有参构造方法注入、基于p命名空间注入
<!-- 通过Setter方法注入 -->
<bean id="book1" class="com.company.po.Book">
<property name="name">
<value><![CDATA[天龙八部]]></value>
</property>
<property name="author" value="金庸"/>
</bean>
<!-- 通过有参构造方法注入 -->
<bean id="order" class="com.company.po.Order">
<constructor-arg name="name" value="电脑"/>
<constructor-arg name="address" value="中国"/>
</bean>
<!-- 通过p命名空间注入 -->
<bean id="book2" class="com.company.po.Book" p:author="古龙" p:name="小鱼儿与花无缺"/>
内外部 Bean 注入
外部 Bean 的注入方式
<!-- 外部bean -->
<bean id="userService" class="com.company.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.company.dao.UserDaoImpl"/>
内部 Bean 的注入方式
<bean id="emp" class="com.company.bean.Emp">
<property name="name" value="张三"/>
<property name="gender" value="男"/>
<!-- 设置内部对象属性 -->
<property name="dept">
<bean id="dept" class="com.company.bean.Dept">
<property name="name" value="法律部"/>
</bean>
</property>
</bean>
集合属性注入
<bean id="stu" class="com.company.bean.collections.Stu">
<property name="courseArray">
<array>
<value>课程1</value>
<value>课程2</value>
</array>
</property>
<property name="courseList">
<list>
<value>课程3</value>
<value>课程4</value>
</list>
</property>
<property name="courseMap">
<map>
<entry key="课程5" value="JAVA"/>
<entry key="课程6" value="MySQL"/>
</map>
</property>
<property name="courseSet">
<set>
<value>课程7</value>
<value>课程8</value>
</set>
</property>
</bean>
FactoryBean
除了普通 Bean之外,还有一种工厂Bean,又称 FactoryBean,返回的对象不是指定类的实例,而是该 FactoryBean的getObject方法返回的对象。
- 普通 Bean:在配置文件中定义的Bean的类型就是返回类型
- 工厂 Bean:在配置文件中定义的Bean的类型可以和返回类型不同
创建自定义 FactoryBean 的方式
- 第一步:创建类,让这个类作为工程Bean,实现接口 FactoryBean
- 第二步:实现 getObject 方法,在实现的方法中定义返回到饿Bean类型
public class MyBean implements FactoryBean<Book> {
// 返回定义的对象
@Override
public Book getObject() throws Exception {
Book book = new Book();
book.setAuthor("刘德华");
book.setName("JAVA核心技术");
return book;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
关于 FactoryBean 的细节可参考 文章,总结以下四点:
- FactoryBean 是 BeanFactory 支持的、用来暴露Bean实例的接口,你可以通过实现接口里面的getObject() 方法来实例化比较复杂的对象;
- 通过 bean name从 Spring 容器中获取 Bean实例时,首先会获取 bean name 直接关联的 Bean实例,如果 Bean实例不是 FactoryBean 类型,则直接返回 Bean实例,否则,调用 getObject() 方法返回;
- 相比于普通 Bean,Spring中会多维护一个FactoryBean的实例,如果想获取FactoryBean实例对象,只需要在FactoryBean的 bean name 前加上 & 符号即可。
<bean id="myBean" class="com.company.factorybean.MyFactoryBean"/>
@Test
public void testFactoryBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
Object book = context.getBean("&myBean");
System.out.println(book);
}
Bean 作用域
- 默认情况是单实例对象,也就是 Singleton 的
- 利用 scope 属性可以配置Bean为单实例还是多实例,singleton 和 prototype
@Test
public void testNamespace() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Order order1 = context.getBean("order", Order.class);
Order order2 = context.getBean("order", Order.class);
System.out.println(order1);
System.out.println(order2);
}
singleton 和 prototype 区别:singleton的实例化在加载配置文件时候完成,prototype则是在getBean的时候才会创建,也就是创建的时机不一样。
Bean 的生命周期
- 通过无参数构造器创建Bean实例
- 为Bean的属性设置值和其他Bean的引用
- 把Bean的实例传递给Bean后置处理器的方法 postProcessBeforeInitialization
- 调用Bean的初始化方法 — 需要配置 init-method
- 把Bean的实例传递给Bean后置处理器的方法 postProcessAfterInitialization
- 使用Bean
- 当容器关闭,调用Bean的销毁方法 — 需要配置 destroy-method
<bean id="dept" class="com.company.bean.Dept" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="法务部"/>
</bean>
<!-- 配置后置处理器,将会对当前配置文件中的所有Bean都添加后置处理器 -->
<bean id="myPostBean" class="com.company.bean.MyPostBean"/>
public class Dept {
private String name;
public Dept() { System.out.println("第一步:无参数构造方法"); }
public void setName(String name) {
this.name = name;
System.out.println("第二步:Set方法设置属性");
}
public void initMethod() { System.out.println("第四步:初始化方法"); }
public void destroyMethod() { System.out.println("第七步:销毁方法"); }
}
@Test
public void testDept() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
Dept dept = context.getBean("dept", Dept.class);
System.out.println("第六步:使用对象");
context.close();
}
最后输出结果:
第一步:无参数构造方法
第二步:Set方法设置属性
第三步:在初始化之前执行的方法
第四步:初始化方法
第五步:在初始化之前执行的方法
第六步:使用对象
第七步:销毁方法
基于XML自动装配
根据指定的装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
Bean 标签属性autowire,包含两种方式:byName、byType
外部属性文件
例如把数据库相关配置放在外部文件中
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
</beans>
基于注解进行Bean管理
注解的格式 @注解名称(属性名称=属性值),可以简化配置
基于注解创建对象
- @Component
- @Service
- @Controller
- @Repository
以上四个注解功能是一样的
基于注解方式属性注入
- @Autowired:把对象根据属性类型
- @Qualifier:把对象根据属性名称
- @Resource:把对象根据属性类型或名称进行注入
- @Value:注入普通类型属性