04.基于xml的Spring应用
SringBean的配置详解
Bean的基础配置
-
例如配置UserDaoImpl由Spring容器负责管理
<bean id="userDao" class="com.nju.dao.impl.UserDaoImpl"/>
此时存储到Spring容器(singleObjects单例池)中的Bean的beanName是userDao, 值是UserDaoImpl对象, 可以根据beanName获取Bean实例
applicationContext.getBean("userDao");
如果不配置id, 则Spring会把当前Bean实例的全限定名作为beanName
applicationContext.getBean("com.nju.dao.impl.UserDaoImpl");
Bean的别名配置
-
可以为当前Bean指定多个别名, 根据别名也可以获得Bean对象
<bean id="userDao" name="aaa,bbb" class="com.nju.dao.impl.UserDaoImpl"/>
此时多个名称都可以获得UserDaoImpl实例对象
applicationContext.getBean("aaa");
applicationContext.getBean("bbb");
Bean的范围配置
-
singleton: 单例, 默认值, Spring容器创建的时候, 就会进行Bean的实例化, 并存储到容器内部的单例池中, 每次getBean时都是从单例池中获取相同的Bean实例
-
prototype: 原型, Spring容器初始化时不会创建Bean实例, 当调用getBean时才会实例化Bean, 每次getBean都会创建一个新的Bean实例
Bean的延迟加载
-
当
lazy-init
设置为true时为延迟加载, 也就是当Spring容器创建的时候, 不会立即创建Bean实例, 等待用到时再创建Bean实例并存储到单例池中去, 后续在使用该Bean直接从单例池获取即可, 本质上该Bean还是单例的<bean id="userDao" class="com.nju.dao.impl.UserDaoImpl" lazy-init="true"/>
Bean的初始化和销毁方法配置
-
Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作, Bean在销毁之前也可以执行指定的销毁方法完成一些操作
<bean id="userDao" class="com.nju.dao.impl.UserDaoImpl" init-method="init" destory-method="destory"/>
-
还可以通过实现InitializingBean接口, 完成一些Bean的初始化操作
Bean的实例化配置
-
构造方式实例化: 底层通过构造方法对Bean进行实例化
-
无参构造: Spring中配置的<bean>几乎都是
-
有参构造: 需要参数注入
1
2
3
4// 有参构造方法
public UserDaoImpl(String name) {
...
}1
2
3<bean id="userDao" class="com.nju.dao.impl.UserDaoImpl">
<constructor-arg name="name" value="haohao"/>
</bean>
-
-
工厂方式实例化: 底层通过调用自定义的工厂方法对Bean进行实例化
-
静态工厂方法实例化Bean
<bean id="userDao1" class="com.nju.factory.MyBeanFactory1" factory-method="userDao"/>
不是把全限定名对应的类当作bean对象, 而是通过这个类中的
userDao
方法构造一个bean对象可以在Bean创建之前可以进行一些其他业务逻辑操作
-
实例工厂方法实例化Bean
<bean id="myBeanFactory2" class="com.nju.factory.MyBeanFactory2"/>
<bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"/>
先配置工厂对象bean, 再配置实例化对象bean
-
实现FactoryBean规范延迟实例化Bean
1
2
3
4
5
6
7
8
9
10public class MyBeanFactory3 implements FactoryBean<UserDao> {
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
}<bean id="myBeanFactory3" class="com.nju.factory.MyBeanFactory3"/>
第一次调用的时候才会创建Bean, 得到的是工厂getObject方法返回的对象
-
Bean的依赖注入配置
-
对于想要注入的属性值或对象, 都要在类中有相应的set方法
-
对于集合数据类型的注入
1
2
3
4
5
6
7public class UserServiceImpl implements UsreService {
// 注入List
private List<String> stringList;
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
}1
2
3
4
5
6
7
8
9<bean id="userService" class="com.nju.dao.impl.UserServiceImpl">
<property name="stringList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
</bean>
Spring的其他配置标签
Spring的get方法
Spring配置非自定义Bean
Bean实例化的基本流程
看源码
Spring的后处理器
BeanFactoryPostProcessor
-
实现
BeanFactoryProcessor
接口, 重写postProcessBeanFactory
方法进行后处理, 要在xml中配置到spring容器中, 会在适当时机自动调用方法可以在这里修改已有的bean, 或注册新的bean而不用配置在xml中
1
2
3
4
5
6
7
8
9
10
11
12
13public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 注册BeanDifinition
BeanDefinition beanDefinition = new RootBeanDefinition();
// 设置全限定名
beanDefinition.setBeanClassName("com.nju.dao.impl.PersonDaoImpl");
// 强转成DefaultListableBeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
// 注册到beanfactory中
defaultListableBeanFactory.registerBeanDefinition("personDao", beanDefinition);
}
}但是上面的方式需要对beanFactory强转, 可以通过实现
BeanFactoryProcessor
接口的子类接口BeanDefinitionRegistryPostProcessor
解决问题, 调用顺序是: 子类接口的postProcessBeanDefinitionRegistry
-> 子类接口的postProcessBeanFactory
-> 父类接口的postProcessBeanFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.nju.dao.impl.PersonDaoImpl");
registry.registerBeanDefinition("personDao", beanDefinition);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// BeanDefinitionRegistryPostProcessor.super.postProcessBeanFactory(beanFactory);
}
}
BeanPostProcessor
Spring Bean的生命周期
-
Bean的初始化过程包括
-
Bean实例的属性填充
-
注入普通属性时,直接通过set方法的反射设置进去
-
注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,若没有,则先创建被注入对象Bean实例
-
注入双向对象引用属性(循环依赖)
-
三级缓存解决该问题
下图为三级缓存源码剖析,可放大查看
-
-
-
Aware接口属性注入
-
BeanPostProcessor的before()方法回调
-
InitializingBean接口的初始化方法回调
-
自定义初始化方法init回调
-
BeanPostProcessor的after()方法回调
-
Spring Ioc整体流程总结
Spring xml方式整合第三方框架
-
两种整合方案
- 不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,如:MyBatis
- 需要引入第三方框架命名空间,需要使用Spring的配置文件配置第三方框架本身内容,如:Dubbo