Spring的IOC控制反转

作者: 林檎果 | 来源:发表于2018-03-15 14:16 被阅读263次

前置知识:

  • Java

包含知识点

  • IOC
  • Bean

一些名词解释:

  • 业务逻辑:例如:进销存的货品出库入库业务
  • 系统服务:例如:货品出库入库时必须的日志记录
  • 容器:意思是管理应用对象的配置和生命周期

框架

封装了特定的流程,让程序员专注于业务逻辑

IOC和Bean容器

接口

沟通的中介物的抽象化,说明了对外的交互,隐藏具体实现。

面向接口编程

  • 分层,各层间只依赖接口而非实现类。
  • 接口实现的变动不影响各层间的调用
  • 隐藏具体实现和多态

IOC

控制反转:应用程序不负责依赖对象的创建和维护,而是由外部容器负责创建和维护。Martin Fowler指出:“获得依赖对象的过程被反转了”依赖的管理由自身管理,变为IOC容器主动注入。在运行期间,动态的将依赖关系注入到对象里。
DI(依赖注入)是一种IOC的实现方式

  1. 找到IOC容器
  2. 容器返回对象
  3. 使用对象

在Spring中,IOC对象都叫做Bean,
<bean id="oneInterface" class="com.xxxx.XxxImpl"></bean>

IOC实现原理

  • 工厂+反射+XML配置文件

IOC+DI

<bean id="userService" class="top.linxz.java.UserServiceImpl"> <!-- IOC -->
    <property name="name" value="李四"/> <!-- DI,不需要修改源码就注入了属性 --> 
</bean>

Bean

Bean实例化三种方式

  • 使用类构造器实例化(默认无参数)
  • 使用静态工厂方法实例化(简单工厂模式)
  • 使用实例工厂方法实例化(工厂方法模式)

Bean容器

  • BeanFactory提供配置结构和基本功能,加载并初始化Bean
  • ApplicationContext是容器,保存了Bean对象并在Spring中使用
    • 初始化它的方式:
      • 本地文件:new FileSystemXmlApplicationContext("F:/xxx/xxx.xml")
      • Classpath:new ClassPathXmlApplicationContext("classpath:spring-context.xml")
      • Web中则依赖servlet或listener
        • listener: <listener-class>
        • servlet:ContextLoaderServlet

Spring注入方式

注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为
常用两种:

  • 设值注入:Impl需要有injectionDAO的set方法
<bean id="xxx" class="com.xxx.xxxImpl">
    <property name="injectionDAO" ref="injectionDAO"/> 
    <!--这个property就注入了下面那个bean-->
</bean>
<bean id="injectionDAO" class="com.xxx"></bean>
  • 构造注入
<bean id="xxx" class="com.xxx.xxxImpl">
    <constructor-arg name="injectionDAO" ref="injectionDAO"/> 
    <!--这个constructor-arg就在构造器里的对应参数里注入了下面那个bean-->
</bean>
<bean id="injectionDAO" class="com.xxx"></bean>

Bean专题

Bean配置项

  • Id(IOC中唯一)
  • Class
  • Scope
  • Constructor arguments
  • Properties
  • Autowiring mode
  • lazy-initializaion mode
  • Initialization/destruction method

Bean的作用域

  • singleton:单例,一个bean容器(ApplicationContext)中一份,(Sping里默认是这个模式)
  • prototype:每次使用bean时,重新创建新的实例
  • request:每次http,request内有效
  • session:session内有效
  • global session:portlet(用于在多个web应用之间统一一个session)的web中有效

Bean的生命周期

  • 定义:xml定义
  • 初始化:
    1. 配置初始化的方法<bean init-method="init" /> 则调用bean里的public void init()方法
    2. 实现beans.factory.InitializaingBean接口的afterPropertiesSet()方法
    3. 全局的在<beans default-init-method />
    • 三种方法顺序:实现方法比xml优先,全局默认被覆盖
  • 使用:
  • 销毁:
    1. 配置销毁方法<bean destroy-method="cleanup" /> 则调用bean里的public void cleanup()方法,配置了一定要有这个方法
    2. 实现beans.factory.DisposableBean接口的destroy方法
    3. 全局的在<beans default-destroy-method />
    • 三种方法顺序:实现方法比xml优先,全局默认被覆盖

Aware接口

实现了Aware接口的bean初始化后可以获得相应资源

  • BeanNameAware:获得声明bean的名字
  • ...

Bean的自动装配(Autowiring)

  • no
  • byName:根据类的实例名字和属性ID完全一致的bean,在<beans default-autowire="byName">,不再需要<bean><property name="" ref="" />
  • byType:根据类的类型匹配
  • constructor:根据构造方法的参数

Bean装配的Resources

针对资源文件的统一接口

  • ResourceLoader,getResource("")得到文件路径,可用字符串路径如下

Bean的注解实现

classpath扫描和组件管理

使用Java注解定义Bean

  • @Component是一个通用注解,可用于任何bean
  • @Repository,注解DAO类,持久层
  • @Service,注解Service类,即服务层
  • @Controller,Controller,即控制层

元注解

如@Component可以用在一个注解上,

自动检测并注册Bean到ApplicationContext中

在XML配置通常用<context:component-scan base-package="org.example"/>包含了<context:annotation-config/>相当于启动注解。

使用过滤器自定义扫描

例子:把找出Stub和Repository并排除Respository

<beans>
<context:component-scan base-package="org.example">
    <context:include-filter type="regex" expression=".*Stub.*Repository" />
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
</beans>

定义Bean

@xxx("xxxx")显式设置bean名字,默认是类的小写开头

作用域

@Scope("xxx")选择你的scope

@Required

通常用于bean属性的setter方法,必须在配置时就被填入

@Autowired

可用在setter上,也可以用在构造器和成员变量。
如果失败会抛异常,但@Autowired(required=false)就不会

Spring类的注入

可以用在Spring自己的类,如BeanFactory,ApplicationContext,Environment,ResourceLoader

List、Set、Map的注入

@Autowired注入ListSetMap<String,x>的类,这里的String是Bean的ID,如果希望List中的Bean有序,可用@Order

Qualifier

多个实现类时,缩小@Autowired的查找范围,缩小查找的注解的名字,具体指定用哪个实现类

基于Java容器的注解

@Bean是XML配置Bean的java版。通常配合@Configuration使用

@Configuration
public class AppConfig{
    @Bean
    public MyService myService(){
        return new MyServiceImpl();
    }
}

等于

<beans>
    <bean id="myService" class="com.xxx.MyServiceImpl" />
</beans>

@ImportResource

@Configuration
@ImportResource("classpath:/com/acme/jdbc.properties")
public class AppConfig{
    @Value("${jdbc.url}")
    private String url;
    
    @Bean
    public DataSource dataSource(){
        return new DriverManagerDataSource(url)
    }
}

等于在XML

<beans>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties" />
    <bean class="com.xxx.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}" />
    </bean>

参考

  1. Spring入门篇,moocer,https://www.imooc.com/learn/196

关于我:

linxinzhe,全栈工程师,目前供职于某500强通信企业。人工智能,区块链爱好者。

GitHub:https://github.com/linxinzhe

欢迎留言讨论,也欢迎关注我~
我也会关注你的哦!

相关文章

网友评论

    本文标题:Spring的IOC控制反转

    本文链接:https://www.haomeiwen.com/subject/qifqqftx.html