IOC:beans + core支持;践行工厂模式,打造一个工厂,通过工厂完成对项目的管理
案例
- 导入依赖:
<!-- 使用context-support传递依赖引入核心容器jar:beans、context、context-support、core、expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
- 配置文件:
描述哪些组件需要spring生产,管理;文件位置:resources目录
;文件名称:随意. 常用名 :applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 作用:声明需要spring 生产的组件 -->
<!-- UserDAOImpl组件 id="组件标识" class="组件类型" -->
<bean id="userDAO" class="com.xxx.dao.UserDAOImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.xxx.service.UserServiceImpl"></bean>
....
</beans>
- 配置文件Schema:
作用:统一配置方式,开发者和框架采用同一套配置语法。向框架传达开发意图。
格式:xsd文件 (spring-beans-4.1.xsd,spring-context-4.1.xsd,...)
导入方式:spring的每种schema都有namespace作为标识;在配置文件中追加namespace,以及和namespace配套的location即可
每种schema中,都在定义:允许出现哪些标签,标签的层级,标签的先后顺序,标签的属性。
每一种配置意图,都由规范中的 标签、属性 来描述。
<!-- beans-Schema的ns -->
<!-- beans-Schema的location -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 强耦合:
耦合度:类之间的关系紧密程度。关系松散即弱耦合,关系密切即强耦合
关系处理不当时,可能会导致组件之间强耦合;一旦强耦合,组件即陷入不稳健
的状态,不稳健
的组件将导致整个项目的形态极差。项目中的具体体现:Controller 依赖 Service 、Service 依赖 DAO 、....
class A{
public void fn1(){...}
}
class B{
public void fn2(A a){a.fn1();...}
}
//如上B类中 直接关联了A类,则B类只能和A类协作,不能和其他类协作 ==> 强耦合
interface IA{ public void fn1();}
class A implements IA{
public void fn1(){...}
}
class B{
public void fn2(IA a){a.fn1();...}
}
//如上B类中只是和IA接口关联,则此时B类可以使用A类,也可以在完全不需要改动的情况下兼容所有IA的其他实现类。
//则B类 和 A类 的关系是松散的 ==> 弱耦合
- Spring解决强耦合:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 作用:声明需要spring 生产的组件 -->
<!-- UserDAOImpl组件 id="组件标识" class="组件类型" -->
<bean id="userDAO" class="com.zhj.dao.UserDAOImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.zhj.service.UserServiceImpl">
<!-- =========重点==========重点========重点========== -->
<!-- 为userDAO属性赋值,值为id=“userDAO”的组件 -->
<property name="userDAO" ref="userDAO"></property>
</bean>
</beans>
public class UserServiceImpl implements UserService{
//private UserDAO userDAO = new UserDAOImpl(); 不再强耦合UserDAOImpl
private UserDAO userDAO; //替换为接口
// set/get
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
- 启动工厂:
//工厂接口:ApplicationContext
//实现类:ClassPathXmlApplicationContext
// 启动工厂,注意:需要制定配置文件位置
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 从工厂中获取 标识为"userDAO"的组件
UserDAO userDAO = (UserDAO)context.getBean("userDAO")
IOC & DI
IOC(Inverse Of Controll):
控制反转
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
DI(Dependency Injection):
依赖注入
全新的依赖满足方式,体现在编码中就是全新的赋值方式 ==> 在工厂中为属性推送值
如:<property name="userDAO" ref="userDAO"></property>
在spring中关于IOC和DI的描述是这样的: IOC(DI),即,是一码事
IOC 是思想:指导我们在满足依赖时,应该有反转的设计。
DI 是手段:实际操作时,就是在一次次的 注入
DI方式
- set注入:
借助set方法完成注入
<bean id="setDI" class="x.xx.XXX">
<!-- jdk 8中基本类型+String -->
<property name="age" value="18"></property>
<property name="name" value="zhj"></property>
<property name="gender" value="true"></property>
<!-- 引用类型 -->
<property name="userDAO" ref="ud"></property>
<!-- List或数组 -->
<property name="list">
<list>
<value>18</value>
<ref bean="ud"/>
</list>
</property>
<!-- set -->
<property name="xxx">
<set>
<value>xx</value>
</set>
</property>
<!-- map -->
<property name="map">
<map>
<entry key="name" value="zhj"></entry>
<entry key="userDAO" value-ref="ud"></entry>
</map>
</property>
<!-- properties -->
<property name="prop">
<props>
<prop key="url">jdbc:oracle:xxxx</prop>
</props>
</property>
</bean>
<!--
注意:在注入过程中,其实就是一个复制的过程, a=b, a是组件的属性,b是如上配置的value中的值。
若b是String,而a可能是 Integer,Boolean,Double,Date,....;即左值和右值类型不匹配。
spring有自动的类型转换机制,可以保证我们绝大多数的类型转换。
细节:“org.springframework.beans.propertyeidtors”包下定义了大量的Editor。
-->
- 构造注入 (了解):
借助构造方法完成注入
<bean id="consDI" class="com.test.TestConstrutorDIComponent">
<!-- index=构造参数索引 type:构造参数类型 value=构造参数值 -->
<constructor-arg index="0" type="java.lang.Integer" value="18"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="zhj"></constructor-arg>
<constructor-arg index="2" type="java.lang.Boolean" value="true"></constructor-arg>
</bean>
- 自动注入:
spring自动识别属性,并注入;不用在配置中 指定为哪个属性赋值,及赋什么值;由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值
掌握 byName
和 byType
的概念
基于类型 自动注入时,如果存在多个此类型的bean,会报错
<!-- 基于属性名自动注入=将和属性"同名"的bean 赋值给属性 -->
<bean id="xx" class="xxx" autowire="byName"></bean>
<!-- 基于属性类型自动注入=将和属性"同类型"的bean 赋值给属性 -->
<bean id="xx" class="xxx" autowire="bytype"></bean>
Bean
- Bean创建:
/**ClassPathXmlApplicationContext
DeFaultListableBeanFactory#preInstantiateSingletons()
BeanUtils#instantiateClass()*/
// 反射
String classpath="com.zhj.domain.User";
Class user = Class.forName(classpath);
Constructor constructor = user.getConstructor();
User o = (User)constructor.newInstance();
- Bean创建模式:
singleton:单例 ==> 默认
在同一个spring工厂中,一个bean只会创建一次对象。
多次getBean(),或多次注入使用的是同一个对象
随工厂创建而创建,随工厂关闭而销毁
prototype:多例 (原型)
`<bean id=xxx class=xxx scope="prototype">`
每次getBean(),或注入都会重新创建对象
不随工厂创建而创建,不随工厂关闭而销毁
被用到时才会创建对象
对象的状态:对象的成员变量值 即 对象的状态
无状态:不同的用户,不同的请求,对象的属性值不会发生改变
有状态:不同的用户,不同的请求,对象的属性值会发生改变
有状态对象:多例模式
无状态对象:单例模式
- 生命周期:
单例bean:构造(工厂启动)-->set-->init-->User-->destroy(工厂关闭)
多例bean:获取时才创建-->set-->init-->User-->不会随工厂关闭而销毁
工厂Bean
FactoryBean:生产某一类对象;spring工厂中一种特殊的bean,可以生产对象;Spring工厂中的小作坊
在工厂中有些bean,无法直接通过简单的<bean></bean>
生产;比如:Connection,SqlSessionFactory
Spring支持两种方式:
- 1.静态工厂方法
public class MyFactoryBean {
public static User createUser(){
return new User();
}
}
<bean id="user" factory-method="createUser" class="com.zhj.factory.MyFactoryBean" scope="xx"></bean>
- 2、工厂方法:
public class MyFactoryBean {
public User createUser(){
return new User();
}
}
<bean id="userFactory" class="com.zhj.factory.bean.MyFactoryBean"></bean>
<bean id="user" factory-bean="userFactory" factory-method="createUser" scope="xx"></bean>
- 测试:
User user = (User)context.getBean("user");//获取bean,此时获取的并不是FactoryBean,而是其生产的对象。
User user2 = (User)context.getBean("user");//多次获取,测试创建模式
- SqlSessionFactoryBean:
<!-- SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="com.zhj.spring.MySqlSessionFactoryBean" factory-method="createSqlSessionFactory"/>
public class MySqlSessionFactoryBean {
public static SqlSessionFactory createSqlSessionFactory() throws IOException {
Reader reader = Resources.getResourceAsReader("configuration.xml");
return new SqlSessionFactoryBuilder().build(reader);
}
}
@Test
public void testFactoryBean() {
//启动工厂 ApplicationContext
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
User user = (User)context.getBean("user");
User user2 = (User)context.getBean("user");
System.out.println("================");
SqlSessionFactory ssf = (SqlSessionFactory)context.getBean("sqlSessionFactory");
UserDAO mapper = ssf.openSession().getMapper(UserDAO.class);
User user1 = (User) mapper.queryOne(1);
System.out.println(user1);
}
源码解析
new ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent){
//...;
refresh();//创建主流程
//...;
}
AbstractApplicationContext___refresh(){
//...;
finishBeanFactoryInitialization(beanFactory);
//...;
}
AbstractApplicationContext___finishBeanFactoryInitialization(){
//...;
beanFactory.preInstantiateSingletons();//创建所有单例的bean
}
DefaultListableBeanFactory___preInstantiateSingletons(){
for (String beanName : beanNames) {//遍历所有的beanName,挨个创建对象
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//非抽象+单例+非延迟,则创建
if (isFactoryBean(beanName)) {
FactoryBean fb = getBean("&" + beanName);//获得工厂对象本身
//....
getBean(beanName);//创建实际对象
} else {
getBean(beanName);//普通bean,直接创建对象
}
}
}
}
AbstractBeanFactory___getBean(){
return doGetBean(//...);
}
AbstractBeanFactory___doGetBean(){
//....
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);//回调方法,创建bean
}
//...
}
}
}
DefaultSingletonBeanRegistry___getSingleton(beanName,singletonFactory){
synchronized (this.singletonObjects) {//枷锁,防止重复创建
Object singletonObject = this.singletonObjects.get(beanName);//尝试获取,如果有则不再创建
//....
singletonObject = singletonFactory.getObject();//回调doGetBean中内部类的方法,创建单例bean
//....
addSingleton(beanName, singletonObject);//记录已创建的单例bean,下次不再创建
}
}
|-- 接:回调doGetBean中内部类的方法,创建单例bean
AbstractAutowireCapableBeanFactory___createBean{
//.....
doCreateBean(beanName, mbdToUse, args);//创建单例bean
}
AbstractAutowireCapableBeanFactory___doCreateBean{
//.....
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
}
AbstractAutowireCapableBeanFactory___createBeanInstance{
//.....
return instantiateBean(beanName, mbd);//使用无参构造创建bean
}
AbstractAutowireCapableBeanFactory___instantiateBean{
//.....
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
SimpleInstantiationStrategy___instantiate(){
//....
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);//获得构造方法对象
//....
return BeanUtils.instantiateClass(constructorToUse);//反射构建bean
}