美文网首页框架原理
Spring IoC快速入门

Spring IoC快速入门

作者: 花无缺_0159 | 来源:发表于2019-02-04 10:53 被阅读43次

【目录】
2.1 Spring的开发包
2.2 开发环境测试搭建
2.3 业务代码编写
2.4 IoC和DI
  2.4.1 最基本的IoC控制反转的实现
  2.4.2 DI依赖注入的实现
2.5 Spring的工厂

2 Spring IoC快速入门

Spring核心内容的基本开发步骤:

  • 下载开发包,导入jar包
  • 编写代码(基础代码和调用代码)
  • 编写配置文件

2.1 Spring的开发包

下载网址

开发包目录结构

2.2 开发环境测试搭建

回顾利用Maven搭建第一个Spring测试项
新建Web工程:spring_day1。pom.xml代码如下。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>spring_day1</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>spring_day1 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
   <!-- Spring依赖 -->
    <!-- 1.Spring核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.22.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.22.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.22.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.3.22.RELEASE</version>
    </dependency>
  <!-- 2.Spring 日志依赖 -->
    <!-- 日志框架 -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    <!-- 日志 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>spring_day1</finalName>
  </build>
</project>

在接下来的学习中,日志统一采用log4j,日志框架根据整合情况再决定。

2.3 业务代码编写

采用传统方式模拟用户登录,思路如下:

示意图

下面开始具体编写步骤。


在src/main/java目录下创建包和类

具体代码见下:
数据层接口 UserDAO.java

package dao;
//用户操作dao层
public interface UserDAO {
    //从数据库查询数据
    public void findUserByUsernameAndPassword();
}

数据层实体类UserDAOImpl.java

package dao;

public class UserDAOImpl implements UserDAO{
    @Override
    public void findUserByUsernameAndPassword() {
        System.out.println("dao层,向数据库查询数据了");
    }

}

业务层接口UserService .java

package service;
//用户操作
public interface UserService {
    //模拟用户登录
    public void login();
}

业务层实体类UserServiceImpl.java

package service;

import dao.UserDAO;
import dao.UserDAOImpl;

public class UserServiceImpl implements UserService{
public void login() {
    System.out.println("service层被调用了");
    UserDAO userDAO = new UserDAOImpl();
    userDAO.findUserByUsernameAndPassword();
    }
}

测试类SpringTest.java

package test;

import org.junit.Test;

import service.UserService;
import service.UserServiceImpl;

public class SpringTest {
    @Test
    public void test(){
        //测试serivce
        UserService userService = new UserServiceImpl();
        userService.login();
    }
}

完成以上代码以后,进行测试。

测试结果

虽然完成了功能,但是可以看到,代码过于耦合,上层代码过度依赖于下一层代码的实现。例如,通过业务层去查询存在于数据层的数据,先必须现在业务层准备一个数据层的实例对象。

UserDAO userDAO = new UserDAOImpl(); 

在传统的代码中,经常是这样的情况:如果有某个对象A依赖于其他对象B,在使用时,需要先创建所依赖的对象B,传入对象A,然后才能对对象A进行操作。这种方式提高了代码的耦合度,十分不利于重构和维护。(为什么要高内聚低耦合?

为了解决这种耦合,Spring采用了IoC(Inverse of Control,控制反转)的思想。这种思想,简单来说,就是引入工厂(也称第三者/IoC容器),将原来在程序中手动创建管理的对象,交给工厂来创建管理。在Spring框架中,这个工厂就是Spring中的工厂。

示意图

2.4 IoC和DI

提到IoC(控制反转),就不得不提到DI(依赖注入)。
以下是常见的两个问题。

Q1:怎样理解DI?
依赖:所有类的对象,都依赖于IoC容器来进行管理。
注入:类中的某个对象,需要某种外部资源(包括对象、资源、常量数据),无需自己去引用,IoC容器直接注入给它。这个对象不需要关心具体的资源来怎么来的,反正是IoC容器统统搞定。(提一句:Spring通过反射机制来实现注入。)
综上,下个定义,应用程序依赖于IoC容器来注入某个对象所需要的外部资源(包括对象、资源、常量数据),这就是DI(通过配置的方式为对象赋值/初始化/注入)。

Q2:许多人把IoC和DI这两个术语理解为同一个事物。怎样恰当的理解它们的关系?
笔者认为,可以这样理解:
IoC是一种思想,也是一种设计模式——把我们自己创建对象的控制权交给IoC容器,让IoC容器负责创建对象。
在IoC容器创建过程中,有一个重点——在系统运行中,动态的向某个对象提供它所需要的其他外部资源(包括对象、资源、常量数据)。
怎样能完成这个重点?可以通过DI来实现——给对象动态的注入外部资源(包括对象、资源、常量数据)。
综上,DI和IoC的关系就是这样——IoC的实现需要DI技术的支持。

PS:给对象注入一个对象,就实现了对对象间依赖关系的“一键”管理,不需要多个相互依赖的类new来new去。什么是依赖关系,看下面的示意代码。

class B {
           private A a;   //A是B的依赖对象,两者间存在依赖关系
}

在spring_day1工程中,userService依赖于userDAO。现在,仍然使用spring_day1工程来进行下面两个小节的演示。
2.4.1小节展示最基本的IoC控制反转的实现,通过Spring的工厂获取一个Bean,不实现动态的资源管理(UserService得到Spring创建好的bean对象userDAO,而SpringTest仍然使用传统方式新建对象userService)。
2.4.2小节展示DI依赖注入的实现,通过Spring的工厂获取自动注入好的资源的Bean,依赖关系的管理由配置文件实现。(SpringTest直接获取bean对象userService,而在userService这个bean里,已经注入好了userDAO)

2.4.1 最基本的IoC控制反转的实现

效果:UserService得到Spring创建好的bean对象userDAO,而SpringTest仍然使用传统方式新建对象userService。
过程:先添加配置文件,让Spring工厂创建一个bean对象userDAO。再修改UserServiceImpl实体类,从Spring工厂获取bean对象userDAO。

有两种spring配置方式:基于XML配置方式、基于注解配置方式。我们在这里采用前一种进行演示。对于这两种配置方式,后续会有更详细的讲解。

下面开始具体的演示。

1.新建配置文件:applicationContext.xml(位置:src/main/resources目录或者 WEB-INF目录、习惯性命名:applicationContext.xml)。

ApplicationContext直译为应用上下文,用来加载Spring框架配置文件,构建Spring的工厂对象,它也称之为Spring容器的上下文对象,也称之为Spring的容器。

引入xml的头部信息bean schema约束,可以参考规范文档中的的xsd-config.html。在引入之前先本地配置开发包中的xsd文件。

配好以后,在xml文件内的<beans></beans>标签内,按alt加斜杠,会出现提示,说明配置成功了。

i出现提示

也可以参看这里Eclipse安装STS插件使用更便捷的导入方式。

这里提供applicationContext.xml代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:p="http://www.springframework.org/schema/p"
       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">
<!-- 快速入门 -->
<!-- IoC的配置 -->
<bean id="userDAO" class="dao.UserDAOImpl"></bean>
</beans>

在后续讲解中,将详细说明配置文件xml的编写。在这里可以先了解一下Bean元素基本属性

2.通过Spring的工厂获取Bean完成相关操作,基本过程是:在程序中读取Spring配置文件,得到Spring的Bean工厂,通过Spring框架获得Bean,完成相应操作。

修改UserServiceImpl.java代码如下:

package service;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import dao.UserDAO;


public class UserServiceImpl implements UserService{

    @Override
    public void login() {
        System.out.println("service层被调用了");
        //传统方式
        //UserDAO userDAO = new UserDAOImpl();
        
       //IoC方式
       //ApplicationContext认为就是Spring工厂
        //ClassPathXmlApplicationContext:参数就是spring的核心配置文件的名字(我们写的那个xml),这个函数的作用就是自动寻找xml文件
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象(spring帮忙new的对象),参数就是我们写的bean的id
        //applicationContext.getBean("userDAO");然后换对象格式
       UserDAO userDAO=(UserDAO) applicationContext.getBean("userDAO");
       //消除警告: - Resource leak: 'applicationContex' is never closed的处理
       //导入包import org.springframework.context.ConfigurableApplicationContext;
       //添加这条语句
       ((ConfigurableApplicationContext)applicationContext).close();       
       userDAO.findUserByUsernameAndPassword();

    }
}

提示:出现new ClassPathXmlApplicationContext错误,是因为Eclipse默认为我们导入一个不符合当前创建容器所需的ApplicationContext 包,需要手动替换后解除错误。
默认导入的包:

import org.apache.catalina.core.ApplicationContext;

需要手动替换的包:

import org.springframework.context.ApplicationContext;

添加log4j.properties文件后(内容参考这里),进行测试。

测试结果

2.4.2 DI依赖注入的实现

  • 注入方式:set方法属性注入、构造器参数注入、接口注入 (后续再详细展开讲解);
  • 注入类型:值类型(八大基本数据类型)、引用类型(String、自定义对象等)、复杂类型(Array、List、Set、Map、Properties)。

在spring_day1工程中,userService依赖于userDAO,也就说依赖对象是userDAO、注入对象userService,现在用set方法实现DI依赖注入,把bean对象userDAO注入给bean对象userService。

效果:SpringTest直接获取bean对象userService,而在userService这个bean里,已经注入好了userDAO。
过程:先在UserServiceImpl实体类中加一个setUserDAO(),在SpringTest中获取spring工程加工好的userService。然后通过配置文件,让Spring工厂实例化好一个bean对象userDAO、一个bean对象userService,同时,用属性把bean对象userDAO注入给bean对象userService,就结束了。

下面开始具体的演示。

修改业务层代码UserServiceImpl.java如下:

package service;

import dao.UserDAO;


public class UserServiceImpl implements UserService{
      //这里写依赖对象的set方法
    private UserDAO userDAO;
    
    public void setUserDAO(UserDAO userDAO){
        this.userDAO=userDAO;
}
            
    @Override
    public void login() {
        System.out.println("service层被调用了");
       //传统方式
        //UserDAO userDAO = new UserDAOImpl();
        
       //IoC方式
       //ApplicationContext认为就是Spring工厂
        //ClassPathXmlApplicationContext:参数就是spring的核心配置文件的名字(我们写的那个xml),这个函数的作用就是自动寻找xml文件
        //ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象(spring帮忙new的对象),参数就是我们写的bean的id
        //applicationContext.getBean("userDAO");然后换对象格式
       //UserDAO userDAO=(UserDAO) applicationContext.getBean("userDAO");
       //消除警告: - Resource leak: 'applicationContex' is never closed的处理
       //导入包import org.springframework.context.ConfigurableApplicationContext;
       //添加这条语句
       //((ConfigurableApplicationContext)applicationContext).close();       
       userDAO.findUserByUsernameAndPassword();
    }
}

修改测试类SpringTest.java如下:

package test;

import org.junit.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import service.UserService;

public class SpringTest {
    @Test
    public void test(){
        //传统创建
        //UserService userService = new UserServiceImpl();
        
        //IoC方式
        //1.获取Spring工厂
         ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.获取工厂制造的bean对象
        UserService userService = (UserService) applicationContext.getBean("userService");
        //消除警告: - Resource leak: 'applicationContex' is never closed的处理
        //导入包import org.springframework.context.ConfigurableApplicationContext;
        //添加这条语句
       ((ConfigurableApplicationContext)applicationContext).close();
        userService.login();
    }
}

修改applicationContext.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:p="http://www.springframework.org/schema/p"
       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">
<!-- 快速入门 -->
<!-- IoC的配置 -->
<bean id="userDAO" class="dao.UserDAOImpl"></bean>
<!-- 将DAO传入Service -->
    <!-- 将service也交给spring管理(new) -->
    <bean id="userService" class="service.UserServiceImpl">
        <!-- 依赖关系,在这里维护-->
        <!-- userService依赖于userDAO,userService需要用到userDAO,那么创建一个userDAO的bean,并注入给userService的bean里
        name:UserServiceImpl类中被注入对象的setter的名字:例如:setXxx,名字xxx(小写的)
        ref:要注入的具体bean对象的引用,写被依赖的bean的名字
         -->
        <property name="userDAO" ref="userDAO"/>
    </bean>
</beans>

进行测试。

测试结果 示意图

2.5 Spring的工厂

Spring的工厂

前文我们用到的ApplicationContext,直译为应用上下文,它被用来加载Spring框架配置文件,构建Spring的工厂对象。它也称之为Spring容器的上下文对象、Spring的容器。
从图中可以看到,ApplicationContext 只是BeanFactory(Bean工厂,Bean就是一个java对象) 一个子接口,但由于ApplicationContext比它的顶层接口对象BeanFactory 更加强大, 所以现在开发基本没人使用它的顶层接口对象BeanFactory。
提示:后面还有个FactoryBean,注意区别。

Spring工厂有两种直接获取,见下图:

Spring工厂的直接获取(两种方式)

补充:bean的获取除了根据名称获取,也可以根据类型(具体类型、接口类型)获取,见下图:

bean获取的两种方式

相关文章

  • spring-ioc

    [TOC] spring-ioc spring快速入门 1、导包 core、context、expression、...

  • Spring AOP编程实战

    Spring框架的IOC功能之注解的方式 Spring框架的IOC之注解方式的快速入门 Spring框架中Bean...

  • Spring框架的概述和入门

    Spring框架的概述和入门 什么是Spring框架 Spring框架的特点 Spring框架的IOC核心功能快速...

  • Java框架--Spring(一)快速入门

    什么是Spring? 为什么要使用Spring? 快速入门案例 怎样理解IoC和DI 1. 什么是Spring? ...

  • Spring框架的IOC功能之注解

    Spring框架的IOC功能之注解的方式 Spring框架的IOC之注解方式的快速入门 步骤一:导入注解开发所有需...

  • Spring IoC快速入门

    【目录】2.1 Spring的开发包2.2 开发环境测试搭建2.3 业务代码编写2.4 IoC和DI  2.4.1...

  • 【Spring入门】总目录

    【Spring入门第1天】Spring框架入门、IoC控制反转的配置管理1 Spring概述https://www...

  • Spring IOC容器入门(三)

    Spring IOC容器的(一)和(二)主要介绍的是Spring IOC的入门使用方法,在实际工作中,Spring...

  • 01_Spring

    今天内容概述 Spring框架的概述 SpringIOC的快速入门 IoC容器XML的方式 在web项目中集成Sp...

  • Spring目录

    Spring 入门 Spring-Bean管理 Spring快速入门 Spring-Bean管理 Spring属性...

网友评论

    本文标题:Spring IoC快速入门

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