Spring学习--IOC依赖注入

最近在玩SpringBoot,因为要做分享,所以拿出Spring去做个对比,才能感受到使用SpringBoot的简单和快速性。

一.Spring定义

Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但现在已经不止应用与企业应用。

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的容器框架。

--从大小与开销方面看来,Spring都是轻量级的;

--通过控制反转IOC的技术达到松耦合的目的(把控制权交出去,在使用的时候直接用);

--提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发;

--包含并管理应用对象的配置和生命周期,这个意义上是一种容器;

--将简单的组件配置组合成复杂的应用,这个意义上是框架。

二.Spring作用

  • 容器;
  • 提供了多种技术的支持(JMS,MQ支持,UnitTest等);
  • AOP(事务管理,日志管理等);
  • 提供了众多方便应用的辅助类(JDBC Template等);
  • 对主流应用框架提供了良好的支持(Hibernate等)。

三.适用范围

  • 构建企业级应用;
  • 单独使用Bean容器(Bean管理);
  • 单独使用AOP进行切面管理;
  • 其他的Spring功能,如对消息的支持等;
  • 在互联网中的应用。

四.IOC控制反转

控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器来负责创建和维护,DI(依赖注入)是其一种实现方式。

目的:创建对象并组装对象间的关系。

依赖注入:由IOC容器在运行中,动态的将某种依赖关系注入对象中。

五.Spring的常用注入方式

Spring注入是指在启动spring容器加载bean配置时,完成对变量的赋值注入。

(1)设值注入(set注入):

         配置文件如下:

           property 表示InjectionServiceImpl有一个属性(成员变量)injectDAO

           ref表示引用id

           通过set注入,自动调用set方法,InjectServiceImpl中一定有一个setInjectDAO方法。

<?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">

    <bean id="injectionService" class="com.spring.beananocation.InjectionServiceImpl">
        <property name="injectionDAO" ref="injectionDAO"></property>
    </bean>

    <bean id="injectionDAO" class="com.spring.beananocation.InjectionDAOImpl"></bean>

</beans>

使用代码如下:

package com.spring.beananocation;
/**
 * DAO接口
 */
public interface InjectionDAO {
    String save(String string);
}
package com.spring.beananocation;

/**
 * DAO实现类
 */
public class InjectionDAOImpl implements InjectionDAO {
    @Override
    public String save(String string) {
        return "这是一个保存:" + string;
    }
}
package com.spring.beananocation;
/**
 * service 接口
 */
public interface InjectionService {
    void save(String arg);
}
package com.spring.beananocation;

/**
 * service 实现类
 */
public class InjectionServiceImpl implements InjectionService {

    /**
     * 和配置文件中property同名的成员变量
     */
    private InjectionDAO injectionDAO;

    /**
     * set方法
     */
    public void setInjectionDAO(InjectionDAO injectionDAO) {
        this.injectionDAO = injectionDAO;
    }

    @Override
    public void save(String arg) {
        //模拟业务操作
        System.out.println("service接收参数:" + arg);
        arg = arg + " :" + this.hashCode();
        System.out.println(injectionDAO.save(arg));

    }
}

单元测试方法:

    @Test
    public void testSetter() {
        InjectionServiceImpl injectionService = super.getBean("injectionService");
        injectionService.save("这是要保存的数据");
    }

可以看到单元测试执行成功,injectionDAO被成功注入,执行结果如下:

(2)构造注入: 

使用构造方法创建类的实例化时,把相应的injectionDAO注入。

配置文件如下:

<?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">

    <bean id="injectionService" class="com.spring.beananocation.InjectionServiceImpl">
        <constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
    </bean>

    <bean id="injectionDAO" class="com.spring.beananocation.InjectionDAOImpl"></bean>

</beans>

将InjectServiceImpl的set方法变为构造方法来注入:

package com.spring.beananocation;

/**
 * service 实现类
 */
public class InjectionServiceImpl implements InjectionService {

    /**
     * 和配置文件中property同名的成员变量
     */
    private InjectionDAO injectionDAO;

    /**
     * 构造方法
     */
    public InjectionServiceImpl(InjectionDAO injectionDAO) {
        this.injectionDAO = injectionDAO;
    }

    @Override
    public void save(String arg) {
        //模拟业务操作
        System.out.println("service接收参数:" + arg);
        arg = arg + " :" + this.hashCode();
        System.out.println(injectionDAO.save(arg));

    }
}

单元测试方法和结果同设置注入。

建议以设值注入为主,构造注入为辅的方式来进行注入。

对于依赖关系无需变化的注入,尽量采用构造注入;而其他依赖关系的注入,则优先考虑设值注入。

五.Bean的配置项

  • id:在整个ioc容器中,这个Bean的唯一标识;
  • class:具体要实例化的哪一个类;
  • scope:指范围,作用域;
  • Constructor arguments:构造器的参数(构造注入用)。
  • Properties:属性(设值注入用)。
  • AutoWiring mode:自动装配模式。
  • lazy-initialization mode:懒加载模式。
  • Initialization/destruction method:初始化和销毁方法。

六.Bean的作用域

  • singleton :单例模式,默认选项,指一个Bean容器中只存在一份。(启动时就创建。)
  • prototype:每次请求(每次使用)创建新的实例,destory方法不生效,因为请求完成后,实例就被垃圾回收器回收了,不存在了。(在用到对象时才创建。)
  • request:每次http请求创建一个实例且仅在当前request内有效。
  • session:同request,每次http请求创建,当前session内有效。
  • global session:基于portlet的web中有效(portel定义了global session),如果是在web中,同session。(有时候做系统和应用的集成,单点登录等。)

在配置文件中加scope配置项:

<?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">

    <bean id="injectionService" class="com.spring.beananocation.InjectionServiceImpl" scope="singleton">
        <constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
    </bean>

    <bean id="injectionDAO" class="com.spring.beananocation.InjectionDAOImpl"></bean>

</beans>

修改单元测试用例如下,由于我们打出了hashcode:

    /**
     * 单元测试
     */
    @Test
    public void testSetter() {
        InjectionServiceImpl injectionService = super.getBean("injectionService");
        injectionService.save("这是要保存的数据");
        InjectionServiceImpl injectionService2 = super.getBean("injectionService");
        injectionService2.save("这是要保存的数据");
    }

所以  当 scope="singleton"或者不加scope配置项时,为单例模式。

所以两次输出的hashcode为相同的,如下:

而当scope="prototype",每次使用都是一个新的实例。输出的hashcode不一致,如下:

 

七.Bean 的生命周期 

  • 定义:在Spring的bean的xml文件中配置的bean,定义了一个id和class;
  • 初始化:当ioc容器在启动的时候去加载bean配置文件里面的bean并初始化,生成bean的实例。
  • 使用:从bean容器中取出一个bean的实例,去调用它的方法。
  • 销毁:在bean容器停止的时候,去销毁由当前这个bean创建的所有实例。

Bean初始化和销毁的三种方式:

(1)配置init-method和destroy-method方法。

<?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">


    <bean id="beanLifeCycle" class="com.spring.ioc.impl.BeanLifeCycle" init-method="init"
          destroy-method="beanDestroy"></bean>

</beans>

BeanLifeCycle类:

package com.spring.ioc.impl;

public class BeanLifeCycle {
    public void init() {
        System.out.println("bean start");
    }

    public void beanDestroy() {
        System.out.println("bean stop");
    }


    public void hello() {
        System.out.println("hello~");
    }

}

单元测试方法:

    @Test
    public void beanLifeCycle(){
        BeanLifeCycle beanLifeCycle = super.getBean("beanLifeCycle");
        beanLifeCycle.hello();
    }

单元测试执行结果如下:

可以看到是先初始化,再使用,再销毁。

(2)实现InitializingBean和DisposableBean接口,并重写他们的afterPropertiesSet()和destroy()方法。不用修改配置文件。

package com.spring.ioc.impl;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class BeanLifeCycle implements InitializingBean, DisposableBean {


    public void hello() {
        System.out.println("hello~");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("bean DisposableBean");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("bean InitializingBean");
    }
}

(3)在配置文件配置全局默认初始化销毁方法:

配置default-init-method和default-destroy-method属性。

<?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"
       default-init-method="defaultInit" default-destroy-method="defaultDestory">

    <bean id="beanLifeCycle" class="com.spring.ioc.impl.BeanLifeCycle"></bean>

</beans>

BeanLifeCycle类:

package com.spring.ioc.impl;

public class BeanLifeCycle{

    public void defaultInit() {
        System.out.println("defaultInit start");
    }

    public void defaultDestory() {
        System.out.println("defaultDestroy stop");
    }

    public void hello() {
        System.out.println("hello~");
    }
}

当3种方式都实现的时候,先执行实现接口的方法,再执行单独配置的init,destory方法,全局默认的方法不实现。

(只要实现了单独配置的init和destory方法,就不再实现全局默认方法了。)

八.Bean的自动装配(Autowiring)

  • NO:不做任何配置(默认选项);
  • byName:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。bean id重复,会启动失败,提示同一个XML下不能存在相同的bean。
  • byType:如果容器种存在一个与指定属性类型相同的bean,那么将与该属性自动装配,如果存在多个该类型的bean,那么抛出异常,并指出不能使用byType方式进行自动装配,如果没找到相匹配的bean,则什么事都不发生。
  • Constructor:与byType方式类似,不同之处在于它应用于构造器参数。如果容器种没有找到与构造器参数类型一致的bean,那么抛出异常。

在配置文件中加入配置default-autowire="byName"或者default-autowire="byType",都是通过set方法来赋值的。

<?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"
       default-autowire="byName">

    <bean id="autoWiringService" class="com.spring.ioc.autowiring.AutoWiringService"></bean>

    <bean id="autoWiringDAO" class="com.spring.ioc.autowiring.AutoWiringDAO"></bean>
</beans>
AutoWiringService:
package com.spring.ioc.autowiring;

public class AutoWiringService {
    private AutoWiringDAO autoWiringDAO;


    public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
        System.out.println("走set方法");
        this.autoWiringDAO = autoWiringDAO;
    }

    public void say(String words) {
        this.autoWiringDAO.say(words);
    }
}
AutoWiringDAO:
package com.spring.ioc.autowiring;

public class AutoWiringDAO {
    public void say(String word) {
        System.out.println("AutoWiringDAO:" + word);
    }
}

单元测试:

    @Test
    public void autoWiringServiceTest() {
        AutoWiringService autoWiringService = super.getBean("autoWiringService");
        autoWiringService.say("This is a test!");
    }

 执行结果:

在配置文件中加入配置default-autowire="constructor"或者default-autowire="byType",是通过构造方法来赋值的。

AutoWiringService:

package com.spring.ioc.autowiring;

public class AutoWiringService {
    private AutoWiringDAO autoWiringDAO;

    public AutoWiringService(AutoWiringDAO autoWiringDAO) {
        System.out.println("走构造方法");
        this.autoWiringDAO = autoWiringDAO;
    }

    public void say(String words) {
        this.autoWiringDAO.say(words);
    }
}

九.Bean装配之Resources

Resources为针对资源文件的统一接口

  • UrlResource:URL对应的资源,根据一个URL地址即可构建。
  • ClassPathResource:获取类路径下的资源文件。
  • FileSystemResource:获取文件系统里面的资源。
  • ServletContextResource:ServletContext封装的资源,用于访问ServletContext环境下的资源。
  • InputStreamResource:针对于输入流封装的资源。
  • ByteArrayResource:针对于字节组封装的资源。

猜你喜欢

转载自blog.csdn.net/third_/article/details/85040992