欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring(一)——简介、IOC(控制反转)、DI(依赖注入)

程序员文章站 2022-07-04 19:38:59
...

Ⅰ、简介

Spring(一)——简介、IOC(控制反转)、DI(依赖注入)
即——Spring框架是一个轻量级、一站式、企业级应用、模块化、非侵入式的框架。

轻量级:其实代码量很大,但是因为它是模块化的框架,所以说它是轻量级框架;
一站式:一步到位,提供全方位服务,spring提供开发整个web企业项目所需要的所有模块;
企业级应用:企业JavaWeb项目开发;
非侵入式:不会因为引入spring框架而影响已经写好的业务逻辑。

相关模块
Spring(一)——简介、IOC(控制反转)、DI(依赖注入)

Ⅱ、核心容器IOC 0

一、简述

控制反转(Inversion of control),自定义类的权力交给IOC容器,由spring容器来创建类,从而降低类与类之间的联系,松耦合性。

1、管理流程是什么样的?
创建实例——>初始化实例——>容器中获取实例——>使用

2、哪些实例对象需要交给IOC?
全局实例对象,需要放在容器中。服务器关闭时,自动销毁(应用在javaWeb中,类似域对象Application(ServletContext),整个服务器内有效,服务器关闭时失效)。

3、spring整合其他框架是什么意思?
将其他框架(工具类)交给IOC管理。



初次接触spring IOC,下面使用案例来说明

pom.xml

<!--测试springIOC,3个jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>

StudentDaoImpl.java

public class StudentDaoImpl implements StudentDao {
    @Override
    public void insertStudent() {
        System.out.println("添加学生成功");
    }
}

springConfig.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop 
https://www.springframework.org/schema/aop/spring-aop.xsd 
http://www.springframework.org/schema/context 
https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="studentDao" class="com.hbw.dao.StudentDaoImpl"></bean>

</beans>

测试

@Test
public void test1(){
    //使用IOC提供的API读取配置文件,完成初始化实例
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");
    //获取实例,并使用
    StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao");
    studentDao.insertStudent();
}

二、IOC中常用的API 0

BeanFactory:核心API,提供了创建并管理所有实例。
*ApplicationContext:是BeanFactory的子接口,提供了创建并管理(生命周期),程序员自定义的所有实例。

其中三个实现类:
	*ClassPathXMlApplication:根据类路径(Resources、Classes文件夹)解析配置文件,初始化容器(实例化)。
	FileSystemXMlApplication:根据文件路径(D://…)解析配置文件。
	AnnotationConfigApplication:通过读取注解配置,初始化容器。
	提供close方法,但是不会手动调用,全局对象在服务器关闭时自动销毁(应用在javaWeb中类似域对象Application(ServletContext),整个服务器内有效,服务器关闭时失效)。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");

三、IOC原理

1)????使用一般的实例化,当该类发生变化时,实例化的地方都需要改变TestDaoImpl tdi = new TestDaoImpl();。耦合性高。
2)????使用接口编程的思想实例化,当该类发生改变时,只需要改变TestDao td = new TestDaoImpl();实例化的一部分。耦合性较高。
3)????使用第三方类(工厂类)实例化需要的类TestDao td = new TestFactory().getTestDaoImpl(),当实例化的类发生改变时,只需要修改工厂里面的部分内容即可。
TestFactory.java

public class TestFactory {
    public StudentDao getStudentDaoImpl(){
        return new StudentDaoImpl();
    }
}

测试

 @Test
    public void test2(){
        StudentDao studentDao = new TestFactory().getStudentDaoImpl();
        studentDao.insertStudent();
    }

4)????上分使用工厂类只能创建一种类,需要创建其他类时,又需要创建新的工厂,效率比较低。所以创建一个生产任意类的工厂,但是在使用该工厂实例化时,需要传入需要实例化类的全类名(反射)进行硬编码,使用时比较麻烦(每次都要传入全类名)。
TestFactory.java

 /*获取任意实例*/
    public Object getObjectImpl(String impl){
        Object object = null;
        try {
            //获取字节码文件
            Class clazz = Class.forName(impl);
            //实例化
            object = clazz.newInstance();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return object;
    }

StudentTest.java

 /*获取任意类型的工厂*/
    @Test
    public void tes3(){
        StudentDao studentDao = (StudentDao) new TestFactory().getObjectImpl("com.hbw.dao.StudentDaoImpl");
        studentDao.insertStudent();

    }

5)????通过属性配置文件或者xml进行实例化。
student.properties配置文件

studentDao=com.hbw.dao.StudentDaoImpl

TestFactory.java
根据配置文件的key,获取值,实例化并存放在map集合中

 /*最终工厂*/
    //用于存放实例化的类
    Map<String,Object> map;

    public TestFactory(String config) {
        //初始化map集合
        map = new HashMap<>();
        //使用jdk自带的ApI解析配置文件
        ResourceBundle resourceBundle = ResourceBundle.getBundle(config);
        //获取配置文件中的所有key,返回类型是枚举类型
        Enumeration<String> enumeration = resourceBundle.getKeys();
        //根据key获取所有的值
        while (enumeration.hasMoreElements()){
            //获取每一个key
            String key = enumeration.nextElement();
            //获取key对应的value
            String value = resourceBundle.getString(key);
            try {
                Class clazz = Class.forName(value);
                Object object = clazz.newInstance();
                //将实例化的类,存放在map集合中
                map.put("studentDao",object);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    /*提供供外部获取实例的方法*/
    public Object getObjectImplEnd(String impl){
        return  map.get(impl);
    }

测试

 /*最终版工厂*/
    @Test
    public void test4(){
        //扫描属性配置文件student.properties
        TestFactory testFactory = new TestFactory("student");
        //从map集合中,根据键获取值
        StudentDao studentDao = (StudentDao) testFactory.getObjectImplEnd("studentDao");
        studentDao.insertStudent();

    }

编码规则——约束优于配置,配置优于编码;高内聚,低耦合。

总结——IOC也是采取类似的措施(肯定复杂狠多啦),扫描xml或者属性文件进行创建实例

四、IOC XML配置文件 0

使用<bean></bean>标签

1、通过构造方法实例化

 <bean id="studentDao" class="com.hbw.dao.StudentDaoImpl"></bean>

2、通过普通工厂类提供的方法实例化

<bean id="ordinaryFactory" class="com.hbw.util.TestFactory"></bean>
    <bean id="ordinaryFactoryOne" factory-bean="ordinaryFactory" factory-method="getStudentDaoImpl"></bean>

3、通过静态工厂类提供的方法实例化(需要提供一个静态方法)

 <bean id="staticFactory"  class="com.hbw.util.TestFactory" factory-method="getStaticStudentDaoImpl"></bean>

属性 0
id(唯一标识)、name属性(取别名),同一个配置文件中不可重复;多个配置文件中可重复,后解析的覆盖先解析的
init-method属性,指定初始化内容(不管程序员有没有使用那个bean,解析xml配置文件时,都会自动初始化)
destory-method属性,指定销毁方法(spring不会主动调用销毁方法,容器(Tomcat)关闭时,自动调用)

scope属性,指定创建的实例对象的作用范围

*Singleton:默认。以单例模式创建实例,实例作用范围在整个应用当中(调用一次获取一次,不会重复创建)。
prototype:以多例模式创建实例,但是不会管理该实例,实例范围在当前大括号内(局部变量一样,调用一次创建一个)
*单例模式实例是启动Tomcat时就初始化好了(只有一个);多例模式实例是程序员获取时才创建。

Request:创建的实例作用范围只在一次请求内有效
Session:创建的实例作用范围只在一次会话中有效
globalSession:用于分布式项目,表示作用范围在全局session中


下列对多例模式进行测试,单例模式改一下属性值即可
springConfig.xml

 <bean id="studentDao" class="com.hbw.dao.StudentDaoImpl" scope="prototype"></bean>

TestStudent.java

 @Test
    public void test1(){
        //使用IOC提供的API读取配置文件,完成初始化实例
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springConfig.xml");
        //获取实例,并使用
        StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao");
        System.out.println(studentDao);
        StudentDao studentDao1 = (StudentDao) applicationContext.getBean("studentDao");
        System.out.println(studentDao1);
        studentDao.insertStudent();
    }

结果
Spring(一)——简介、IOC(控制反转)、DI(依赖注入)

Ⅲ、核心容器DI

依赖注入(DI:dependency injection),前提——该类提供了 有参构造或set方法。
从容器中获取实例,自动将一个对象注入到另一个对象中(构造注入、setter注入,就是传递参数,初始化实体类)。

setter注入使用<property>标签、构造注入使用<constructor-arg>标签

下列对Student实体类进行初始化

Student实体类有如下属性

private int sid;
private String sname;
private Book book;
private Double[] heightWeight;
private List<Book> bookList;
private Set<Book> bookSet;
private Map<String,Book> bookMap;

1)使用Setter注入

	<bean id="book" class="com.hbw.bean.Book">
        <property name="bid" value="1"></property>
        <property name="bname" value="小学数学上册"></property>
    </bean>
    
	<bean id="student" class="com.hbw.bean.Student">
        <property name="sid" value="1"></property>
        <property name="sname" value="张三"></property>
        <property name="book" ref="book"></property>
        <property name="heightWeight">
            <array>
                <value>175.0</value>
                <value>120.1</value>
            </array>
        </property>
        <property name="bookList">
            <list>
                <bean class="com.hbw.bean.Book">
                    <property name="bid" value="2"></property>
                    <property name="bname" value="小学语文上册"></property>
                </bean>
                <bean class="com.hbw.bean.Book">
                    <property name="bid" value="3"></property>
                    <property name="bname" value="小学英语上册"></property>
                </bean>
            </list>
        </property>
        <property name="bookSet">
            <set>
                <bean class="com.hbw.bean.Book">
                    <property name="bid" value="4"></property>
                    <property name="bname" value="小学美术上册"></property>
                </bean>
            </set>
        </property>
        <property name="bookMap">
            <map>
                <entry key="bookid" value-ref="book"></entry>
            </map>
        </property>
    </bean>

Spring(一)——简介、IOC(控制反转)、DI(依赖注入)

2)使用构造注入

<!--通过构造注入-->
	<bean id="book" class="com.hbw.bean.Book">
        <property name="bid" value="1"></property>
        <property name="bname" value="小学数学上册"></property>
    </bean>
    
    <bean id="studentConstructor" class="com.hbw.bean.Student">
        <constructor-arg name="sid" value="2"></constructor-arg>
        <constructor-arg name="sname" value="李四"></constructor-arg>
        <constructor-arg name="book">
            <bean id="book" class="com.hbw.bean.Book">
                <!--Book中每没有给有参构造方法,只能使用settter注入-->
                <property name="bid" value="1"></property>
                <property name="bname" value="小学数学上册"></property>
            </bean>
        </constructor-arg>
        <constructor-arg name="heightWeight">
            <array>
                <value>165.05</value>
                <value>80.90</value>
            </array>
        </constructor-arg>
        <constructor-arg name="bookList">
          <list>
              <bean id="book" class="com.hbw.bean.Book">
                  <property name="bid" value="2"></property>
                  <property name="bname" value="小学语文上册"></property>
              </bean>
          </list>
        </constructor-arg>
        <constructor-arg name="bookSet">
            <set>
                <bean id="book" class="com.hbw.bean.Book">
                    <property name="bid" value="3"></property>
                    <property name="bname" value="小学美术"></property>
                </bean>
            </set>
        </constructor-arg>
        <constructor-arg name="bookMap">
            <map>
                <entry key="book" value-ref="book"></entry>
            </map>
        </constructor-arg>
    </bean>

Spring(一)——简介、IOC(控制反转)、DI(依赖注入)

依赖注入总结

依赖注入——依赖IOC容器,资源由IOC注入到应用程序中

一、不同点
setter注入
0)前提,该类中提供了set方法
1)setter注入使用<property></property>标签
构造注入
0)前提,该类中提供了有参构造方法(有参构造中的所有参数,都必须初始化)
1)setter注入使用<constructor-arg></constructor-arg>标签

二、相同点
1)普通类型参数的值,直接使用value属性进行赋值;
2)引用类型的参数赋值,两种:

使用ref属性,其值需要现在外面使用<bean>标签进行初始化,在通过id引入进来
	<bean id="book" class="com.hbw.bean.Book">
       <property name="bid" value="1"></property>
        <property name="bname" value="小学数学上册"></property>
    </bean>
    <property name="book" ref="book"></property>
在其中直接使用<bean>标签进行赋值
	<constructor-arg name="book">
        <bean id="book" class="com.hbw.bean.Book">
            <!--Book中每没有给有参构造方法,只能使用settter注入-->
            <property name="bid" value="1"></property>
            <property name="bname" value="小学数学上册"></property>
        </bean>
    </constructor-arg>

3)数组类型使用arry标签

<constructor-arg name="heightWeight">
     <array>
         <value>165.05</value>
         <value>80.90</value>
     </array>
 </constructor-arg>

4)list、set、map使用<set><list><map>标签,其中map集合赋值使用entry标签(key属性就是键名,value-ref属性就是其键对应的值)


 <bean id="book" class="com.hbw.bean.Book">
       <property name="bid" value="1"></property>
       <property name="bname" value="小学数学上册"></property>
 </bean>
    
 <constructor-arg name="bookList">
    <list>
         <bean id="book" class="com.hbw.bean.Book">
             <property name="bid" value="2"></property>
             <property name="bname" value="小学语文上册"></property>
         </bean>
     </list>
   </constructor-arg>
   <constructor-arg name="bookSet">
       <set>
           <bean id="book" class="com.hbw.bean.Book">
               <property name="bid" value="3"></property>
               <property name="bname" value="小学美术"></property>
           </bean>
       </set>
   </constructor-arg>
   <constructor-arg name="bookMap">
       <map>
       		<!--value-ref是引入的上方的book实例-->
           <entry key="book" value-ref="book"></entry>
       </map>
   </constructor-arg>
相关标签: spring ioc bean