04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI

04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第1张图片 三层架构

spring共四天
第一天:spring框架的概述以及spring中基于XML的IOC配置

第二天:spring中基于注解的IOC和ioc的案例
----------------------------------------------------------------------------------

1、spring的概述
    spring是什么
    spring的两大核心
    spring的发展历程和优势
    spring体系结构
2、程序的耦合及解耦
    曾经案例中问题
    工厂模式解耦
3、IOC概念和spring中的IOC
    spring中基于XML的IOC环境搭建
4、依赖注入(Dependency Injection)

  01.Spring框架简介

1.1.1 spring 是什么

Spring 是分层的 Java EE 企业应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:
反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring
MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多
著名的第三方框架和类库。

2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)
 

1.1.3 spring 的优势

方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造
成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可
以更专注于上层的应用

AOP 编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付

声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,
提高开发效率和质量。
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可
做的事情
方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架( Struts、 Hibernate、 Mybatis
等)的直接支持。
降低 JavaEE API 的使用难度

Spring 对 JavaEE API(如 JDBC、 JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的
使用难度大为降低

Java 源码是经典学习范例

1.1.4 spring 的体系结构
04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第2张图片

第2章 IoC 的概念和作用

2.1 程序的耦合和解耦[理解]

2.1.1 什么是程序的耦合

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立
性)。 耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。
在软件工程中, 耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计
应使类和构件之间的耦合最小。 软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。 划分模块的一个
准则就是高内聚低耦合。

内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。 内聚是从
功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件
结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通
过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之
间的相互依存度却要不那么紧密。

 


我们在开发中,有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。
 

//比如:
//早期我们的 JDBC 操作,注册驱动时,我们为什么不使用 DriverManager 的 register 方法,而是采
//用 Class.forName 的方式?


public class JdbcDemo1 {
/**
* @author 
* 
* @Version 1.0
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1.注册驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
//3.获取预处理 sql 语句对象
//4.获取结果集
//5.遍历结果集
}
}


//原因就是:
//我们的类依赖了数据库的具体驱动类(MySQL) ,如果这时候更换了数据库品牌(比如 Oracle) ,需要
//修改源码来重新数据库驱动。这显然不是我们想要的。

2.1.2 解决程序耦合的思路

当是我们讲解 jdbc 时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串
此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译(运
行就不要想了,没有驱动不可能运行成功的) 。
同时,也产生了一个新的问题, mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改
源码。解决这个问题也很简单,使用配置文件配置。
 

2.1.3 工厂模式解耦
 

在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候, 让一个类中的
方法通过读取配置文件,把这些对象创建出来并存起来。
在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件, 创建和获取三层对象的类就是工厂

/**
 * 一个创建Bean对象的工厂
 *
 * Bean:在计算机英语中,有可重用组件的含义。
 * JavaBean:用java语言编写的可重用组件。
 *      javabean >  实体类
 *
 *   它就是创建我们的service和dao对象的。
 *
 *   第一个:需要一个配置文件来配置我们的service和dao
 *           配置的内容:唯一标识=全限定类名(key=value)
 *   第二个:通过读取配置文件中配置的内容,反射创建对象
 *
 *   我的配置文件可以是xml也可以是properties
 */

 

2.1.4 控制反转-Inversion Of Control

04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第3张图片

04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第4张图片

明确 ioc 的作用:
削减计算机程序的耦合(解除我们代码中的依赖关系)。
 

第3章 使用 spring 的 IOC 解决程序耦合

3.1 案例的前期准备[会用]

由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体
类。并且我们在此处使用的是 java 工程,不是 java web 工程。
04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第5张图片

3.1.1 准备 spring 的开发包

官网: http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解压:(Spring 目录结构:)
* docs :API 和开发规范
* libs :jar 包和源码
* schema :约束
特别说明:
spring5 版本是用 jdk8 编写的,所以要求我们的 jdk 版本是 8 及以上。
同时 tomcat 的版本要求 8.5 及以上。

3.1.2 创建业务层接口和实现类

package com.itheima.service;

/**
 * 账户业务层的接口
 */
public interface IAccountService {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
package com.itheima.service.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao ;


    public void  saveAccount(){
        accountDao.saveAccount();
    }
}

3.1.3 创建持久层接口和实现类

package com.itheima.dao;

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
package com.itheima.dao.impl;

import com.itheima.dao.IAccountDao;

/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了账户");
    }
}

3.2 基于 XML 的配置(入门案例) [掌握]


3.2.1 第一步:在maven项目的pom.xml导入依赖坐标
 

    com.itheima
    day01_eesy_03spring
    1.0-SNAPSHOT
    jar

    
        
            org.springframework
            spring-context
            5.0.15.RELEASE
        
    

3.2.2 第二步:创建一个任意英文名称的 .xml 文件在目录 src/main/resources

bean.xml

给配置文件导入约束:
/spring-framework-5.0.2.RELEASE/docs/spring-framework-reference/html5/core.html

 





3.2.3 第三步: 让 spring 管理资源,在配置文件中配置 service 和 dao
 





3.2.4 测试配置是否成功
 

package com.itheima.ui;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {

    /**
     * 获取spring的Ioc核心容器,并根据id获取对象
     *
     * ApplicationContext的三个常用实现类:
     *      ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
     *      FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
     *
     *      AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。
     *
     * 核心容器的两个接口引发出的问题:
     *  ApplicationContext:     单例对象适用              采用此接口
     *      它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
     *
     *  BeanFactory:            多例对象使用
     *      它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
     * @param args
     */
    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        as.saveAccount();


        //--------BeanFactory----------
//        Resource resource = new ClassPathResource("bean.xml");
//        BeanFactory factory = new XmlBeanFactory(resource);
//        IAccountService as  = (IAccountService)factory.getBean("accountService");
//        System.out.println(as);
    }
}

3.3Spring 基于 XML 的 IOC 细节[掌握]

3.3.1 spring 中工厂的类结构图

ApplicationContext 接口的实现类
04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI_第6张图片

3.3.2 IOC 中 bean 标签和管理对象细节
bean 标签

作用:
用于配置对象,让 spring 来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。

id: 给对象在容器中提供一个唯一标识。用于获取对象。
class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。

scope:指定对象的作用范围。

* singleton :默认值,单例的.
* prototype :多例的.
* request :  WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
* session : WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.

* global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session

init-method: 指定类中的初始化方法名称。
destroy-method: 指定类中销毁方法名称。

bean 的作用范围和生命周期
单例对象: scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象: scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
 

实例化 Bean 的三种方式

第一种方式:使用默认无参构造函数
 


第二种方式: 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}

第三种方式: spring 管理实例工厂-(使用某个类中的方法创建对象,并存入spring容器)- 基于接口的动态代理

/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}


 

3.3.3 spring 的依赖注入

依赖注入: Dependency Injection。 它是 spring 框架核心 ioc 的具体实现。

IOC的作用:降低程序间的耦合(依赖关系),但不会消除。
依赖关系的管理: 在使用 spring 之后, 就交给 spring 来维护了。
                                 在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明。
                                 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

依赖关系的维护:就称之为依赖注入。

依赖注入:
             能注入的数据:有三类
                基本类型和String
                其他bean类型(在配置文件中或者注解配置过的bean)
                复杂类型/集合类型
             注入的方式:有三种
                第一种:使用构造函数提供
                第二种:使用set方法提供
                第三种:使用注解提供(明天的内容)

第一种:构造函数注入

package com.itheima.service.impl;

import com.itheima.service.IAccountService;

import java.util.Date;

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    //如果是经常变化的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

    public AccountServiceImpl(String name,Integer age,Date birthday){
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
    }


}
    
    
        
        
        
    

    
    

更常用的方式: set方法注入

 
    
        
        
        
    

  AccountServiceImpl3.java

package com.itheima.service.impl;

import com.itheima.service.IAccountService;

import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Map;

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl3 implements IAccountService {

    private String[] myStrs;
    private List myList;
    private Set mySet;
    private Map myMap;
    private Properties myProps;

    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    }

    public void setMyList(List myList) {
        this.myList = myList;
    }

    public void setMySet(Set mySet) {
        this.mySet = mySet;
    }

    public void setMyMap(Map myMap) {
        this.myMap = myMap;
    }

    public void setMyProps(Properties myProps) {
        this.myProps = myProps;
    }

    public void  saveAccount(){
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(mySet);
        System.out.println(myMap);
        System.out.println(myProps);
    }


}
 
    
        
            
                AAA
                BBB
                CCC
            
        

        
            
                AAA
                BBB
                CCC
            
        

        
            
                AAA
                BBB
                CCC
            
        

        
            
                ccc
                ddd
            
        

        
            
                
                
                    BBB
                
            
        
    

end

你可能感兴趣的:(计算机的编程)