下面代码的实现十分简单,但是业务层需要调用数据层的方法,就要在业务层new数据层的对象,如果数据层的实现类发生变化,业务层的代码也需要跟着改变,意味着要编译打包和重新部署
// 数据层实现
public class FoodDaoImpl implements FoodDao{
public void save(){
...
}
}
// 业务层实现
public class FoodServiceImpl implements FoodService{
private FoodDao fd = new FoodDaoImpl();
public void save(){
fd.save();
}
}
针对上述问题,Spring提出了一个解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象(Spring的核心概念)
IOC
?使用对象时,由主动new
产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部Spring
和IOC
之间的关系是什么?
Spring
技术对IOC
思想进行了实现IOC
容器),用来充当IOC
思想中的外部
IOC
容器的作用以及内部存放的是什么?
IOC
容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象IOC
容器中统称为Bean
IOC
容器中创建好service
和dao
对象后,程序能正确执行么?不行!service
运行需要依赖dao
对象,IOC
容器中虽然有service
和dao
对象,但service
对象和dao
对象没有任何关系,需要将二者进行绑定上述提到需要绑定对象间的关系,使用的就是DI
什么是依赖注入DI?在容器中建立bean
与bean
之间的依赖关系的整个过程称为依赖注入
IOC
容器中哪些bean
之间要建立依赖关系?如业务层需要依赖数据层,service
就要和dao
建立依赖关系
充分解耦:
- 使用
IOC
容器管理bean
- 在
IOC
容器内将有依赖关系的bean
进行关系绑定- 使用对象时不仅可以直接从
IOC
容器中获取,并且获取到的bean
已经绑定了所有的依赖关系
Spring
是使用容器来管理bean
对象的,管什么?主要管理项目中所使用到的类对象,比如Service
和Dao
IOC
容器?使用配置文件IOC
容器,要想从容器中获取对象先要获取IOC
容器,如何获取?Spring
框架提供相应的接口IOC
容器得到后,如何从容器中获取bean
?调用Spring
框架提供对应接口中的方法分为思路和代码
IOC
管理bean
Service
中使用new
形式创建的Dao
对象是否保留?删除,因为要使用IOC
容器中的bean
对象Service
中需要的Dao
对象如何进入到Service
中?在Service
中提供方法(set
方法),让IOC
容器可以通过该方法传入bean
对象Service
与Dao
间的关系如何描述?使用配置文件主要掌握:
bean
标签的id
和class
属性的使用- 对于是否设置单例的思考
id
:bean
的id
,在容器中唯一
class
:bean
的类型(即bean
的全路径类名),注意不能使用接口(因为接口无法创建对象)
name
:定义bean
的别名,存在多个就使用,;
或者空格分隔,之后在ref
和getBean
方法中中也可以使用别名
scope
:定义bean
的作用范围,singleton
表示单例(默认),prototype
表示非单例
为什么bean
默认为单例?避免了对象的频繁创建与销毁,性能高
bean
在容器中是单例的,会不会产生线程安全问题?
哪些bean
对象适合交给容器进行管理?
哪些bean
对象不适合交给容器进行管理?
主要掌握:
bean
是如何创建的?- 实例化
bean
的三种方式
bean
如何创建?使用反射,因为把构造方法设置为私有也可以使用bean
,所以使用的是反射
实例化bean
的三种方式:
<bean id="bookDao" class="com.psj.dao.impl.BookDaoImpl"/>
<bean id="orderDao" class="com.psj.factory.OrderDaoFactory" factory-method="getOrderDao"/>
实例工厂实例化(了解即可):和静态工厂的区别在于工厂中的方法一个是静态一个不是,并且配置也不同
<bean id="userFactory" class="com.psj.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
FactoryBean
的使用:上述配置过于复杂,因为factory-method
名称不固定每次都要配置,并且还需要特意创建id=userFactory
的bean
配合使用// FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 代替原始实例工厂中创建对象的方法(相当于统一了方法名为getObject)
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
// 如果要设置为单例/非单例,还可以实现isSingleton方法(不实现就取默认值-单例)
}
<bean id="userDao" class="com.psj.factory.UserDaoFactoryBean"/>
bean
生命周期指bean
对象从创建到销毁的整体过程;bean
生命周期控制指在bean
创建后到销毁前做的事主要掌握:
- 生命周期设置
bean
的生命周期
生命周期设置:
BooDaoImpl
类中分别添加两个方法,方法名任意,BookServiceImpl
类中实现两个接口InitializingBean
和DisposableBean
,并实现接口中的方法afterPropertiesSet
和destroy
init-method
和destroy-method
关闭容器(了解即可,因为交给Tomcat容器管理):不关闭容器无法执行消耗方法,关闭方式分为直接使用close
方法和先注册钩子再使用close
方法
bean
的生命周期:
bean
初始化方法主要掌握:
setter
注入- 构造器注入
- 两个方式的使用选择
setter
注入:
引用类型:详情见代码BookServiceImpl.java
和applicationContext.xml
基本数据类型:和引用类型的区别在于applicationContext.xml
中将ref
改为value
<bean id="bookDao" class="com.psj.dao.impl.BookDaoImpl">
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
bean>
构造器注入:在实体类中添加有参构造器,主要修改在于applicationContext.xml
引用类型:详情见代码中的applicationContext.xml
,对于构造方法中形参名称和类型重复的问题也有说明
基本数据类型:和引用类型的区别在于applicationContext.xml
中将ref
改为value
使用选择:
setter
注入有概率不进行注入导致null对象出现setter
注入进行,灵活性强Spring
框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
IOC
容器根据bean
所依赖的资源在容器中自动查找并注入到bean
中的过程称为自动装配主要掌握:
- 自动装配的方式
- 注意事项
自动装配方式:
<bean id="bookService" class="com.psj.service.impl.BookServiceImpl" autowire="xxx"/>
autowire="byType"
autowire="byName"
,需要保证被依赖的bean
的id
名和类中setter
方法中把set
删除并将首字母大写后的名称一致注意事项:
setter
注入与构造器注入,同时出现时自动装配配置失效setter
方法前面完成的是引用类型和基本数据类型的注入,还有集合类型(既可装基本数据类型也可装引用数据类型)未说明
主要掌握:
- 不同集合类型的注入
不同集合类型的注入:详情见applicationContext.xml
property
标签表示setter
方式注入,构造方式注入constructor-arg
标签内部也可以写、、、
标签List
的底层也是通过数组实现的,所以
和
标签可混用
标签改成
标签即可<property name="array">
<array>
<ref bean="xxx">
array>
property>