Spring是核心是AOP和IOC,是框架中必不可少的一部分,本文记录了学习笔记。

Spring-1-入门

1. Spring的优势(先了解、使用中感悟)

  1. 方便解耦,简化开发
  2. AOP编程的支持
  3. 声明式事务的支持
  4. 方便程序的测试
  5. 方便集成各种优秀框架
  6. 降低了JavaEE API的使用难度
  7. Java源码是经典学习的范例

1. 方便解耦,简化开发

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

2. AOP编程的支持

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

3. 声明式事务的支持

从单调的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量

4. 方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。

5. 方便集成各种优秀框架

Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Structs、Hibernate、Hessian、Quartz等)的直接支持

6. 降低了JavaEE API的使用难度

简化了如:JDBC、JavaMail、远程调用等的使用难度(对JavaEE API进行了略微封装),使得API使用难度大大降低。

7. Java源码是经典学习的范例

Spring源代码设计精妙、结构清晰、独具匠心。楚楚体现着对Java设计模式的灵活运用以及对Java技术的高深造诣。是学习的典范。

8. Spring的体系结构

spring01-factorystruct

2. IoC的概念及作用

1.什么是耦合

  1. 耦合度

    1. 耦合度,也叫耦合性,是模块间关联程度。在软件工程中体现的是程序与程序之间的依赖程度。(Java中是类与类(或者方法与方法)之间的依赖程度)
    2. 高耦合,耦合越高程序越难以维护。
    3. 低耦合,常与高内聚一起来衡量模块独立程度的标准。
    4. 划分模块的准则是:高内聚、低耦合。

2. 耦合度的体现

程序之间的是必然存在依赖关系的,但是有的依赖是可以通过优化代码来消除的

  1. 以注册驱动为例,演示优化程序间依赖关系

    采用DriverManager的register方法的形式注册驱动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class JdbcDemo01 {
    public static void main(String[] args) throws SQLException {
    //1.注册驱动
    DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    //2.获取连接
    //3.获取预处理对象
    //4.获取结果集
    //5.遍历结果集
    }
    }
    • 分析以上程序可以知道,当com.mysql.jdbc.Driver这个类没有没导入的时候,该程序会在在编译期间就会报错误(注意是Error,而不是异常)

    以Class.forName,即反射的方式注册驱动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class JdbcDemo01 {
    public static void main(String[] args) throws Exception {
    //1.注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    //2.获取连接
    //3.获取预处理对象
    //4.获取结果集
    //5.遍历结果集
    }
    }
    • 以反射的方式加载驱动时,只需要传入全限定类名的字符串表现形式,这种形式下,如果没有导入对应的驱动jar包,肯定也无法正常运行。但是在编译的时候却是可以通过的(运行时抛出异常,ClassNotFoundException)。
    • 由以上两种方式,我们可以明显看出,第二种方式(即是以反射的形式)加载驱动的耦合度要低于直接创建对象的方式
  2. 以往开发中耦合度较高的程序

    • 界面层要创建业务层对象实现业务
    • 业务层要创建接口层对象实现dao
    1
    2
    3
    public class AccountServiceImpl implements AccountService {  
    private AccountDao accountDao = new AccountDaoImpl(); //此处要求存在AccountDaoImpl类
    }

3. 如何解决耦合度(工厂模式、单列模式)

  • 以上注册驱动案例中,我们发现以反射的形式加载驱动类时,即是我们把数据库驱动的依赖(dependency)去除,程序仍然能够正常编译。(运行是肯定不行的了)
  • 但是这种方式也存在一个问题,程序扩展性太差,因为驱动的类名已经写死。当我们需要使用其他数据库时还需要将代码重写编译。
  • 为了解决以上问题,实际中我们常常使用配置文件。
  1. 解决办法:创建Bean对象的工厂

    • Bean:在计算机英语中,有可重用组建的含义。

    • JavaBean:用java语言编写的可重用组件。

      • JavaBean并不仅仅局限于我们知道的实体类
      • JavaBean > 实体类
      • JavaBean包含了service和dao等重用性较高的对象
    • 使用JavaBean工厂对象

      1. 配置文件配置service和dao

        • 配置的内容:唯一标识 = 全限定类名(key = value)
      2. 读取配置文件,通过反射来创建对象

        • 可以使用xml或者properties
  1. 使用工厂模式解耦

    1. 加载包含全限定类名的配置文件。
    2. 根据配置文件中的全限定类名,以反射的方式创建对象。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package top.tobing.beanfactory;
    import java.io.InputStream;
    import java.util.Properties;

    public class BeanFactory {
    private static Properties pro;
    // 加载配置文件
    static{
    try{
    pro = new Properties();
    InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
    pro.load(in);
    }catch (Exception e) {
    throw new ExceptionInInitializerError("没找到配置文件!");
    }
    }

    // 利用反射获取对象
    public static Object getBean(String beanName){
    Object bean = null;
    try{
    String className = pro.getProperty(beanName);
    bean = Class.forName(className).newInstance();
    }catch (Exception e){
    e.printStackTrace();
    }
    return bean;
    }
    }
  2. 工厂模式优化

    • 以上代码中,虽然我们已经通过工厂模式降低了三层之间的耦合度,但是我们每次获取Impl对象的时候都要newInstance的方式(调用默认构造方法),主动申请对象。这样申请的对象每次都不一样。
    • 这种方式的效率低下
    1. 解决办法

      1. 在初始化的时候,加装配置文件。
      2. 通过配置文件的信息,创建容器存储反射创建的对象。
      3. 每次在获取Bean对象的时候通过容器返回
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      package top.tobing.beanfactory;

      import java.io.InputStream;
      import java.util.Enumeration;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.Properties;

      public class BeanFactoryPlus {

      // 1. 读取配置文件
      private static Properties pro;
      private static Map<String,Object> beans;
      static{
      try{
      pro = new Properties();
      beans = new HashMap<>();
      // 获取配置文件
      InputStream in = BeanFactoryPlus.class.getClassLoader().getResourceAsStream("bean.properties");
      pro.load(in);
      // 遍历配置文件信息
      Enumeration<Object> keys = pro.keys();
      while(keys.hasMoreElements()){
      String beanName = (String)keys.nextElement().toString();
      String className = (String)pro.get(beanName);
      // 2. 反射创建对象
      Object obj = Class.forName(className).newInstance();
      // 3. 使用容器存储创建对象
      beans.put(beanName,obj);
      }
      }catch (Exception e){
      throw new ExceptionInInitializerError("配置文件读取异常!");
      }
      }
      // 返回容器中存储的对象
      public static Object getBean(String beanName){
      return beans.get(beanName);
      }
      }

4. 什么是Ioc?

  • Ioc,全称Inversion of Control,控制反转。可以理解为,把创建对象的权利交给了框架。
  1. 为何说降低耦合是控制反转?

    1. 在创建依赖的对象时,一般的形式是通过new关键字直接创建对象。这种情况要求程序要与资源直接关联(程序对资源有直接控制权)。
    2. 在使用工厂模式解耦的时候,我们通过工厂类作为中间人,将多个资源与程序关联起来。 这时候,我们将程序对资源的控制权交给了工厂。因此成为控制反转。
  2. Ioc 的作用

    降低程序间的耦合度。

3. 使用Spring的Ioc解决程序耦合度

步骤:

  1. 下载spring开发包
  2. 创建业务层接口和实现类
  3. 创建持久层接口和实现类
  4. 基于XML配置(基于Maven)
  5. 获取spring的容器
  6. 通过容器创建对象

1. 下载spring开发包

Spring官网:www.spring.io

Spring开发包下载地址: https://repo.spring.io/release/org/springframework/spring/

  1. 目录结构

    下载之后解压得到:spring-framework-5.0.2.RELEASE-dist文件夹

    -spring-framework-5.0.2.RELEASE

    ​ -docs:API和开发规范

    ​ -libs:jar包和源码

    ​ -schema:约束

  2. 开发注意

    • spring5.0.2是基于jdk8编写的,需要jdk8或者以上的版本

    • tomcat需要8.5以上

2. 创建业务层,持久层接口以及对应的实现类

  1. 资源框架

    spring01-source

  2. 代码

    视图层

    1
    2
    3
    4
    5
    6
    public class UserUI {
    public static void main(String[] args) {
    UserService userService = new UserServiceImpl();
    userService.save();
    }
    }

    业务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface UserService {
    void save();
    }
    public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();
    public void save() {
    userDao.save();
    }
    }

    持久层

    1
    2
    3
    4
    5
    6
    7
    8
    public interface UserDao {
    void save();
    }
    public class UserDaoImpl implements UserDao {
    public void save() {
    System.out.println("UserDao--> 查询用户");
    }
    }

3. 创建spring依赖(导入jar包)

pom.xml文件下添加spring的依赖

1
2
3
4
5
6
7
8
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>

4. 添加bean配置文件

  1. 在资源目录下创建bean.xml文件

  2. 在spring参考文档(Spring Framework Documentation)core中找到bean.xml约束

  3. 配置service和dao

1
2
3
4
5
6
7
8
9
10
11
<?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">
<!--service配置-->
<bean id="userService" class="top.tobing.service.impl.UserServiceImpl"></bean>
<!--dao配置-->
<bean id="userDao" class="top.tobing.dao.impl.UserDaoImpl"></bean>
</beans>

5. 测试配置是否已经成功

将视图层,业务层和持久层的调用从new改为使用spring提供的Ioc

  1. 获取ApplicationContext对象
  2. 通过该对象的getBean获取对象
1
2
3
4
5
6
7
8
9
10
11
12
public class UserUI {
public static void main(String[] args) {
// 1. 使用ApplicationContext接口(获取spring容器)
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据bean的id获取对象
UserService userService = (UserService) ac.getBean("userService");
UserDao userDao = ac.getBean("userDao",UserDao.class);
System.out.println(userDao);
System.out.println(userService);
}
}

评论