Spring:IOC之基于XML管理
基本内容
spring框架的三大特性 : IOC \ AOP \ 声明式事务
IOC ** : 首先,IOC是个容器,可以帮我们管理对象的整个声明周期。代码实现IOC之后,可以用spring来管理对象,其管理的对象叫做组件,也叫做bean**。spring管理bean有两种形式 :
- 基于xml管理bean
- 基于注解管理bean
这里讲的主要是基于xml管理bean,主要内容包括 :
- xml配置bean
- xml获取bean
- xml注入依赖
- 为特殊类型赋值(类类型、数据类型、集合类型等)
- bean的作用域
- bean的生命周期
- FactoryBean
- 基于xml的自动装配
配置bean
在一个maven module中,当有了一个类之后(比如helloworld),可以通过在对应目录的resources中右击Xml configuration -spring config来创建一个xml文件,并在其中添加以下内容 :
1 | <!-- |
这样就完成了在xml中配置bean。
获取bean(三种方式)
验证方法 : 创建一个测试类,先获取IOC容器,再通过IOC来获取bean
获取bean有三种方式:
- 根据id获取
- 根据类型获取,此时要求ioc容器中有且只有一个ioc类型匹配的bean(常用)
- 根据类型和id
相应的实现 : 在对应目录的test目录下创建helloworldTest类,加入以下内容:
1 |
|
运行此测试文件,就可以获取bean并且输出hellospring。
扩展 :
- 如果组件类实现接口 ,根据接口类型可以获取 bean 吗?
答 :可以,前提是bean唯一
如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?
答:不行,因为bean不唯一
依赖注入(两种方式)
假如有这样一个Student类,我们来为他进行依赖注入。(依赖指的就是id、name这些属性,因为Student类依赖于这些属性)
DI ,是IOC的一种实现方式,就是为类中的属性进行赋值。依赖注入有两种方式 : setter注入与构造器注入。
1 | public class Student { |
setter注入 :配置bean时为属性赋值,
property
标签1
2
3
4
5
6
7<bean id="studentOne" class="com.atguigu.spring.bean.Student">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)-->
<!-- value属性:指定属性值 -->
<property name="id" value="1001"></property>
<property name="name" value="张三"></property>
</bean>构造器注入(需要添加有参构造),
constrcutor
标签先添加有参构造
1
2
3
4
5
6
7
8public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Student(Integer sorce, String name) {
this.sorce = sorce;
this.name = name;
}再注入
1
2
3
4
5
6
7
8<bean id="studentTwo" class="com.atguigu.spring.bean.Student">
<!-- 这里是按顺序添加,当然也可以通过index属性和name属性进一步描述构造器参数 -->
<!-- 如果有多个构造器,那么会首先匹配参数个数相同的构造器 -->
<!-- 如果有多个构造器参数个数也相同,那么就可以使用name属性了,例如下面就把1002赋给sorce而不是id
<constructor-arg value="1002" name="sorce"></constructor-arg> -->
<constructor-arg value="1002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
</bean>
上面说的value是简单的字符串形式,如果某个实例本身是某个特殊的属性该怎么赋值 ?
为特殊类型赋值
为类类型属性赋值
试想这样一个类 :教室类,其中包含教室号与教室名称
1 | public class Clazz { |
然后要把这个教室类加入到学生类中 :在学生类中添加如下实例域与构造方法 :
1 | private Clazz clazz; |
此时如果要给student类中的class类赋值 ,可以有三种方法 :
引用外部已经声明的bean
首先要在外部声明class类的bean
1
2
3
4<bean id="clazzOne" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="1111"></property>
<property name="clazzName" value="1班"></property>
</bean>然后在student的bean中引用 : 注意是
ref
关键字,不是vaule
1
2
3
4<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
</bean>内部bean
1
2
3
4
5
6
7
8
9
10<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="clazz">
<!-- 在一个bean中再声明一个bean就是内部bean -->
<!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
<bean id="clazzInner" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="2222"></property>
<property name="clazzName" value="2班"></property>
</bean>
</property>
</bean>级联属性赋值
1
2
3
4
5
6<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<!-- 一定先引用某个bean为属性赋值,才可以使用级联方式更新属性 -->
<property name="clazz" ref="clazzOne"></property>
<property name="clazz.clazzId" value="3333"></property>
<property name="clazz.clazzName" value="最强王者班"></property>
</bean>
为数组类型属性赋值
如果student类中有数组类型的实例域 ,比如有若干个爱好:
1 | private String[] hobbies; |
那么配置bean的方法如下 :
1 | <bean id="studentFour" class="com.atguigu.spring.bean.Student"> |
为集合类型属性赋值
比如在class类中 ,有一个students的集合 :
1 | private List<Student> students; |
那么赋值方式如下 :
1 | <bean id="clazzTwo" class="com.atguigu.spring.bean.Clazz"> |
P命名空间
引入p命名空间后,可以通过以下方式为bean的各个属性赋值
1 | <bean id="studentSix" class="com.atguigu.spring.bean.Student" |
bean的作用域
spring IOC所管理的bean,默认是单例模式,可通过如下代码实现 :
1 |
|
如果不想实现单例,在实现DI的时候,把scope
标签写成prototype(原型 :多例)即可 (默认为singleton,单例)
1 | <bean class="com.atguigu.bean.User" scope="prototype"></bean> |
如果是在WebApplicationContext环境下还会有另外两个作用域 (不常用)
request : 在一个请求范围内有效
session : 在一个会话范围内有效
bean的生命周期
什么时候被创建?什么时候被初始化? …… ? 什么时候销毁?
具体的生命周期如下 :
- 实例化
- 依赖注入
- 初始化,需要通过bean的init-method属性指定初始化方法
- IOC容器关闭时销毁,需要通过bean的destory-method属性指定销毁的方法
注意:不同的bean作用域(单例、多例),对生命周期有影响,详见下面的test方法
以下面这个User类来举例 :
1 | public class User { |
配置它的bean:
1 | <!-- 使用init-method属性指定初始化方法 --> |
相应的测试类
1 |
|
FactoryBean
FactoryBean
是一个接口,Spring提供的一种整合第三方框架的常用机制。
和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是它的实现类中getObject()
方法的返回值。
FactoryBean
的源码如下 :
1 | //接口 ,泛型就是工厂所提供的类型 ,需要创建一个类实现该接口 |
实现方法 :
创建类
UserFactoryBean
1
2
3
4
5
6
7
8
9
10
11
12public class UserFactoryBean implements FactoryBean<User> {
//提供的对象
public User getObject() throws Exception {
return new User();
}
//提供的对象类型
public Class<?> getObjectType() {
return User.class;
}
}创建配置文件配置bean
1
2
3**在加载com.atguigu.bean.UserFactoryBean时,实际上是把UserFactoryBean中的getObject()方法所返回的对象交给了IOC**
**因此这里没有配置User类型的bean,在下面的测试文件中却可以获取User类型的bean**
<bean id="user" class="com.atguigu.bean.UserFactoryBean"></bean>测试文件
1
2
3
4
5
6
7
8
public void testUserFactoryBean(){
//获取IOC容器
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-factorybean.xml");
//因此这里可以直接获取User类型的bean,这就是UserFactoryBean的好处
User user = (User) ac.getBean("user");
System.out.println(user);
}
基于xml的自动装配
自动装配:根据指定的策略(byType,byName),在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型
或接口类型
属性赋值
场景模拟
通过经典的三层架构来进行场景模拟 : 控制层、业务层、持久层。控制层调用业务层来处理业务逻辑,业务层调用DAO实现持久化操做。
控制层 :
1 | public class UserController { |
业务层(接口) :
1 | public interface UserService { |
创建类UserServiceImpl实现接口UserService
1 | public class UserServiceImpl implements UserService { |
持久层 :
1 | public interface UserDao { |
创建类UserDaoImpl实现接口UserDao
1 | public class UserDaoImpl implements UserDao { |
在resource下面创建spring的xml配置文件
如果不用自动装配,交给IOC管理:
1 | <bean id="userController" class="com.atguigu.autowire.xml.controller.UserController"> |
创建测试类 :
1 |
|
自动装配的两种方式
通过autowire
来设置自动装配策略。autowire
的属性有 : no & default :都是不匹配 ,byType ,byName
byType (常用):根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
1
2
3
4
5<bean id="userController" class="com.atguigu.autowire.xml.controller.UserController" autowire="byType">
</bean>
<bean id="userService" class="com.atguigu.autowire.xml.service.impl.UserServiceImpl" autowire="byType">
</bean>
<bean id="userDao" class="com.atguigu.autowire.xml.dao.impl.UserDaoImpl"></bean>byName(少用):将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值