zoukankan      html  css  js  c++  java
  • Spring之IOC

    一,前言

    ​ 本篇博客分享一些关于Spring中一个核心概念,IOC。

    IOC: Inversion of Control ,控制反转。

    ​ 通常情况下对于实例化一个对象,我们会通过关键字new创建出来。但是在实际项目开发中不可能有一个实例化对象,而多个对象就需要多个new创建。显然,这势必造成多个对象之间的耦合,以及对程序的维护性带来困难。

    控制反转 ,顾名思义就是将控制权力交给Spring容器。简单理解就是将创建bean的工作交给Spring来做,对于开发人员来说就不需要再手动创建。并且Spring容器会自动维护bean之间的关系,及bean的生命周期等,大大降低了程序之间的耦合。

    ​ 接着再说说和IOC相关的另一个概念:

    DI:Dependency Injection,依赖注入。

    依赖注入,在程序运行时,动态的向对象中注入它所依赖的对象。举例,A对象依赖B对象中的某些属性或方法,但是在Spring容器创建A对象之前,并不知道A的依赖关系。因此在真正创建A对象时,发现依赖了B对象,则此时也会将B对象创建出来并注入到A中,这就是依赖注入。

    我个人的理解就是DI是IOC的一种体现方式,这也是DI和IOC两者的区别。

    二,IOC核心接口

    BeanFactoryApplicationContext是IOC容器体现形态的两大核心接口,请看下图两者之间的联系。

    ​ 两者之间是继承关系,BeanFactory作为最顶层接口,里面只实现了容器的基本功能,是一种简单容器。而ApplicationContext作为最底层的子类,则自然拥有父类的基本功能,并且还增加了很多面向框架的特性,如国际化,时间发布等,是一种高级容器

    ApplicationContext:
    ​ 它在构建容器时,创建对象采用的策略是采用立即加载的方式,也就是说当读取完配置文件时,容器就是马上创建对象。
    BeanFactory:
    ​ 它在构建核心容器时,创建对象采取的策略是延时加载,什么时候根据id获取对象时,容器才会真正创建对象。

    ​ 这里我们只总结关于ApplicationContext接口的使用。

    三,ApplicationContext

    ApplicationContext是一个接口,那么要想使用该接口就要实例化它的实现类,请看如下所示:

    ​ 其中常用的三个实现类为:

    ClassPathXmlApplicationContext:加载类路径下的配置文件。
    FileSystemXmlApplicationContext:加载磁盘中任意位置的配置文件(要有访问权限)
    AnnotationConfigApplicationContext:读取注解标记。

    ​ 以上三种都是获取bean的实例化对象,那么我们又如何定义bean对象呢,同样也是有三种方式。

    第一种:使用默认的构造函数创建

    ​ 在spring的配置文件中使用bean标签,配置id和class属性使用就是默认的构造函数创建的对象。

    ​ 注意:如果类中没有无参构造函数,则创建对象失败。

    ​ 首先定义bean.cml文件:

    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    		
    		<!-- 第一种方式,使用默认的构造函数-->
    		<bean id="userService" class="com.frame.service.impl.UserServiceImpl"></bean>
    
    </beans>
    

    ​ 定义接口IUserService的实现类:

    public class UserServiceImpl implements IUserService {
    	/**
         * 无参构造
         */
        public UserServiceImpl() {
            System.out.println("创建对象");
        }
    	@Override
        public void addUser() {
            System.out.println("添加用户");
        }
    }
    

    ​ 主方法中获取该实例对象:

     public class Demo {
        public static void main(String[] args) {
    	// 1,加载类路径下的配置文件
    	ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    	// 2,通过getBean()获取实例化对象
        IUserService userService = (IUserService) ac.getBean("userService");
    	// 3,通过bean对象调用方法
    	userService.addUser();
    	}
     }
    

    ​ 运行结果为:

    第二种,普通工厂模式

    ​ 使用类中的方法创建对象,并注入到spring容器中。

    思路:模拟一个工厂,创建并返回上述实现类对象。

    // 模拟bean工厂
    public class InstanceBean {
        public IUserService userservice(){
            return new UserServiceImpl();
        }
    }
    
    <bean id="instanceBean" class="com.frame.factory.InstanceBean"></bean>
        <bean id="userService" factory-bean="instanceBean" factory-method="userservice"></bean>
    

    ​ 而主方法中的代码和上面是一样的,这种创建bean的方式比较灵活,通过配置文件去加载自定义的工厂。

    第三种,普通工厂模式中的静态方法

    // 将方法用static修饰
    public class StaticInstanceBean {
        public static IUserService userservice(){
            return new UserServiceImpl();
        }
    }
    
    <bean id="userService" class="com.frame.factory.StaticInstanceBean" factory-method="userservice"></bean>
    

    四,Bean的作用范围

    ​ 通过IOC可以将创建对象这个事交给Spring容器,那么Bean的作用范围容器是怎么定义的。

    bean标签的scope属性:
    singleton:单例模式(默认使用)
    prototype:多例模式
    request:(Spring2.0之后)web应用的请求范围
    session:(Spring2.0之后)web用用的会话范围
    global-session:(Spring2.0之后)全局会话范围。

    ​ 在Spring容器中,默认是使用单例模式,如下代码:

    <bean id="userService" class="com.frame.service.impl.UserServiceImpl" scope="singleton"></bean>
    
    // 1,加载配置文件
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    // 2,获取Bean对象
    IUserService userService = (IUserService) ac.getBean("userService");
    // 3,再次获取
    IUserService userService1 = (IUserService) ac.getBean("userService");
            System.out.println(userService == userService1);
    
    

    ​ 运行结果为:

    ​ 证明多次获取Bean对象,在单例模式下是同一个对象。同样,将配置文件中scope值改为多例模式,如下代码:

    <bean id="userService" class="com.frame.service.impl.UserServiceImpl" scope="prototype"></bean>
    

    ​ 主方法中的代码同上,那么我们直接看运行结果:

    ​ 很明显,在多例模式下IOC创建了两次对象。

    五,DI

    ​ 上面我们总结了DI的概念,那么依赖注入都能注入什么类型呢,又可以使用什么方式进行进入呢。

    注入的数据有三类:
    ​ 1,基本数据类型
    2,其他bean类型
    3,复杂类型(Array,List,Map,Set等)
    注入的三种方式:
    1,使用函数构造
    ​ 2,使用set方法提供
    ​ 3,使用注解提供

    第一种,使用函数构造

    public class UserServiceImpl{
    	private Integer id;
        private String name;
        private Date birthday;
    
        public UserServiceImpl(){}
        public UserServiceImpl(Integer id,String name,Date birthday) {
            this.id = id;
            this.name = name;
            this.birthday = birthday;
        }
    
    }
    
    <bean id="userService" class="com.frame.service.impl.UserServiceImpl">
            <constructor-arg name="id" value="10010"></constructor-arg>
            <constructor-arg name="name" value="小明"></constructor-arg>
            <constructor-arg name="birthday" ref="now"></constructor-arg>
        </bean>
    <!-- 声明Date对象 -->
         <bean id="now" class="java.util.Date"></bean>
    

    ​ 标签中属性使用:

    • type:指定要注入数据的数据类型。
    • index:指定要注入的数据的索引位置的参数进行赋值,索引值从0开始。
    • name:指定给构造函数中指定名称的参数赋值。
    • value:提供基本类型和String类型的数据。
    • ref:引用其他bean类型数据。

    第二种,使用set方法提供

    public class UserServiceImpl{
    
        private Integer id;
        private String name;
        private Date birthday;
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    }
    
    <bean id="userService" class="com.frame.service.impl.UserServiceImpl">
            <property name="id" value="10010"></property>
            <property name="name" value="张三"></property>
            <property name="birthday" ref="now"></property>
        </bean>
    <!-- 声明Date对象 -->
         <bean id="now" class="java.util.Date"></bean>
    

    ​ 标签的属性:

    • name:指定注入时set方法名称。
    • value:提供基本类型和String类型的数据。
    • ref:引用其他bean类型数据。

    第三种,注解形式

    @Autowired:自动注入

    @Qualifier:与@Autowired搭配使用,按照名称进行注入。

    @Resource:通过id进行注入,可单独使用。

    注意:这三种只能注入bean类型。

    @Value:用于注入基本类型和String类型的数据。

    六,总结

    ​ 本篇博客是帮助理解IOC的概念,通过上述总结能有一个更好更简单的理解。对于Spring还有一个核心概念就是AOP思想,这将会在下一篇博客种总结分享。

    ​ 以上内容均是自主学习总结,如有不适之处欢迎留言指正。

    感谢阅读!

  • 相关阅读:
    锚接口(上)——hashchange api 和 $.uriAnchor
    仿B站项目(4)webpack打包第三方库jQuery
    仿B站项目(3)页面配置
    微信小程序:scroll滑到指定位置
    开发微信小程序——古龙小说阅读器
    仿B站项目——(2)环境配置,文件目录
    仿B站项目——(1)计划,前端工程
    腾讯Alloy团队代码规范
    webpack热加载:修改文件自动刷新浏览器并更新
    日时相克,困龙被伤。日落死地
  • 原文地址:https://www.cnblogs.com/fenjyang/p/11520646.html
Copyright © 2011-2022 走看看