3-Spring-IOC

        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,为属性注入属性值

        掌握 byNamebyType 的概念

        基于类型 自动注入时,如果存在多个此类型的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
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值