20201123黄春跃

20201123黄春跃

知识点

spring 是什么

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

Spring 的发展历程

1997 年 IBM 提出了 EJB(Enterprise JavaBean) 的思想
1998 年,SUN 制定开发标准规范 EJB1.0
1999 年,EJB1.1 发布
2001 年,EJB2.0 发布
2003 年,EJB2.1 发布
2006 年,EJB3.0 发布
Rod Johnson(spring 之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了 J2EE 使用 EJB 开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)
2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)

spring 的优势

方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过
度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于
上层的应用。
AOP 编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过
AOP 轻松应付。
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发
效率和质量。
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事
情。
方便集成各种优秀框架

Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、
Quartz等)的直接支持。
降低 JavaEE API 的使用难度
Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的使用难
度大为降低。
Java 源码是经典学习范例
Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以及对
Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。

spring 的体系结构

IoC 的概念和作用

什么是程序的耦合

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

它有如下分类:
(1)内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而
转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用
之。
(2)公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在
具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参
数表传递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号
值而进行适当的动作,这种耦合被称为控制耦合。
(5)标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和
C 之间存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种
耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某
些模块的输出数据作为另一些模块的输入数据。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调
用来实现的。
总结:
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须
存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
内聚与耦合
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从
功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。
耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访
问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之
间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块
同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
我们在开发中,有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的请看下面的示例:
比如三层架构中视图层需要依赖业务层,要在视图层中定义变量并赋值,业务层需要数据层。如果没有
这些依赖编译就不能通过。而这种编译期依赖关系,应该在我们开发中杜绝。我们需要优化代码解决。
再比如早期我们的 JDBC 操作,注册驱动时,我们为什么不使用 DriverManager 的 register 方法,而
是采用 Class.forName 的方式?

工厂模式解耦

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

使用 spring 的 IOC 解决程序耦合

本章我们使用的案例是,账户的业务层和持久层的依赖关系解决。在开始 spring 的配置之前,我们要
先准备一下环境。由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时
我们没必要写实体类。并且我们在此处使用的是 java 工程,不是 java web 工程。

准备 spring 的开发包

下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring

在pom.xml中加入依赖

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

创建持久层接口和实现类

package com.itlaobing.spring.dao;

public interface IAccountDao {
    int saveAccount();
}
package com.itlaobing.spring;

import com.itlaobing.spring.dao.IAccountDao;

public class IAccountDaoImpl implements IAccountDao {
    @Override
    public int saveAccount() {
        System.out.println("保存了账户信息");
        return 0;
    }
}

创建业务层接口和实现类

package com.itlaobing.spring.service;

public interface IAccountService {
    int saveAccount();
}
package com.itlaobing.spring;

import com.itlaobing.spring.dao.IAccountDao;
import com.itlaobing.spring.service.IAccountService;

public class IAccountServiceImpl implements IAccountService {
    private IAccountDao accountDao = new IAccountDaoImpl();
    @Override
    public int saveAccount() {
        return accountDao.saveAccount();
    }
}

基于 XML 的配置(入门)

第一步:拷贝必备的 jar 包到工程中

第二步:在类的根路径下创建一个任意名称的 xml 文件(不能是中文)写上约束

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

<?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="accountService"
          class="com.itlaobing.spring.IAccountServiceImpl">
    </bean>
    <bean id="accountDao"
          class="com.itlaobing.spring.IAccountDaoImpl">
    </bean>
</beans>


测试配置是否成功

package com.itlaobing.spring;

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

public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("MySpring.xml");
        IAccountService aService = (IAccountService)ac.getBean("accountService");
        System.out.println(aService);
        IAccountDao aDao = (IAccountDao) ac.getBean("accountDao");
        System.out.println(aDao);
    }
}

实例化 Bean 的三种方式

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

创建一个名为Person的类

package com.itlaobing.spring.bean;

public class Person {
    private String name;
    private Integer age;

    public Person() {
        System.out.println("这是一个无参构造函数");
    }

    public Person(String name) {
        this.name = name;
        System.out.println("带有name="+name+"参数的构造函数");
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
        System.out.println("带有name="+name+"和年龄="+age+"参数的构造函数");
    }
}

向MySpring.xml配置文件中添加如下:

    //无参构造
    </bean>
    <bean id="person" class="com.itlaobing.spring.bean.Person">
    </bean>
     //一个参数的构造  
    <bean id="personWithParam" class="com.itlaobing.spring.bean.Person">
        <constructor-arg name="name" value="黄大"></constructor-arg>
    </bean>
    //两个参数的构造 
    <bean id="personWithParams" class="com.itlaobing.spring.bean.Person">
        <constructor-arg name="name" value="黄二"></constructor-arg>
        <constructor-arg name="age" value="22"></constructor-arg>
    </bean>

创建一个PersonTest类用于测试

package com.itlaobing.spring.bean;

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

public class PersonTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("MySpring.xml");
        Person p = (Person) ac.getBean("person");//不带参数

        Person p1 = (Person) ac.getBean("personWithParam");//带一个参数

        Person p2= (Person) ac.getBean("personWithParams");//带多个参数
    }
}

得到结果如下:

第二种方式:spring 管理静态工厂-使用静态工厂的方法创建对象

先创建一个名为PersonStaticFactory的类

package com.itlaobing.spring.bean;

public class PersonStaticFactory {
    /*
     * 静态工厂方法实例化bean
     */
    public static Person createInstance() {
        return new Person();
    }

    public static Person createInstance(String name) {
        return new Person(name);
    }

    public static Person createInstance(String name,Integer age) {
        return new Person(name,age);
    }
}

在MySpring.xml设置

<!-- 此种方式是:
使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
-->

<bean id="personStaticFactory" class="com.itlaobing.spring.bean.PersonStaticFactory" factory-method="createInstance"></bean>
    <bean id="personStaticFactoryWithParam" class="com.itlaobing.spring.bean.PersonStaticFactory" factory-method="createInstance">
        <constructor-arg name="name" value="黄大"></constructor-arg>
    </bean>
    <bean id="personStaticFactoryWithParams" class="com.itlaobing.spring.bean.PersonStaticFactory" factory-method="createInstance">
        <constructor-arg name="name" value="黄二"></constructor-arg>
        <constructor-arg name="age" value="23"></constructor-arg>
    </bean>

创建PersonStaticFactoryTest类测试

package com.itlaobing.spring.bean;

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

public class PersonStaticFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("MySpring.xml");
        context.getBean("personStaticFactory");

        context.getBean("personStaticFactoryWithParam");

        context.getBean("personStaticFactoryWithParams");
    }
}

结果如下:

第三种方式:spring 管理实例工厂-使用实例工厂的方法创建对象

先创建InstanceFactory类

package com.itlaobing.spring.bean;

public class InstanceFactory {
    public Person createInstance() {
        return new Person();
    }

    public Person createInstance(String name) {
        return new Person(name);
    }

    public Person createInstance(String name,Integer age) {
        return new Person(name,age);
    }
}

在MySpring.xml中添加配置

<bean id="instancefactory" class="com.itlaobing.spring.bean.InstanceFactory"/>
    //这个bean的id 使用在在之后的factory-bean中,无需再配置class
    <!-- 此种方式是:
使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
-->
    
    <bean id="personInstance" factory-bean="instancefactory" factory-method="createInstance"></bean>
    <bean id="personInstanceWithParam" factory-bean="instancefactory" factory-method="createInstance">
        <constructor-arg name="name" value="黄大"></constructor-arg>
    </bean>
    <bean id="personInstanceWithParams" factory-bean="instancefactory" factory-method="createInstance">
        <constructor-arg name="name" value="黄二"></constructor-arg>
        <constructor-arg name="age" value="12"></constructor-arg>
    </bean>

创建InstanceFactoryTest来测试

package com.itlaobing.spring.bean;

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

public class InstanceFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("MySpring.xml");
        context.getBean("personInstance");
        context.getBean("personInstanceWithParam");
        context.getBean("personInstanceWithParams");
    }
}

测试结果如下:

懒加载

懒加载(Lazy)是指在启动Spring容器时不实例化bean对象,而是在需要对象时实例化bean对象。懒
就是不提前准备好bean对象,需要bean对象时才实例化bean对象,有懒惰的表现。
当Scope="singleton"时,表示Spring容器启动时实例化Bean对象;Scope="prototype"时,表示调用
getBean()时初实例化Bean对象,而不是在容器启动时实例化Bean对象。
编写单元测试方法,在单元测试方法中只加载Spring容器,不获取bean对象

为了方便 将就在之前的代码做改动

得到结果如下:

总结

后面的依赖注入没看明白,晚自习看了看数据库

标签

评论

© 2021 成都云创动力科技有限公司 蜀ICP备20006351号-1