简介

前言

感谢黑马程序员

Spring概述

首先我们来看一张图片

这就是我们将要学习的SSM框架的基本架子,我们可以看到,由SpringMVC去处理视图层,Mybatis去处理持久化层,而Spring干什么呢?其实什么也不做,它不属于我们熟知的三层架构的任何一层,但其实是SSM中的核心。

Spring是什么

Spring,是Java全栈轻量级开发框架,现如今成为了最多的JavaEE企业应用开源框架

Spring官网:https://spring.io

Spring的核心

Spring的核心就两件事:IOC控制反转和AOP面向切面编程,基于这两个特性,可以大大简化我们编写JavaEE应用,实现快速开发

IOC控制反转是什么

  • 控制反转,就是将创建对象的活交给工厂区创建

打个比方,我现在要买个房子

以前的做法是:到处打听谁要买房,然后和具体的人去沟通协商,然后两家签订合同

现在的做法是:让中介去干这个活,我到最后只管签合同

AOP面向切面编程是什么

  • 面向切面编程,就是通过预编译和运行期动态代理的方式实现功能的维护

打个比方,比如现在我的程序从上到下已经全部开发完成了,现在有个需求说我要在哪个过程上加上一个新功能

这个时候我只需要在那个过程范围内添加一个新的功能即可

形象化来说,我们开发过程是从上到下竖向进行的,面向切面编程就是在这基础上横向添加

Spring的优势

  • 解耦
  • AOP
  • 声明式事务支持
  • 方便测试
  • 可以集成各种框架
  • 降低API使用难度
  • Spring源码是学习的范例

Spring的体系结构

问题分析:如何将程序简化

以前的使用案例

package com.howling.Before.Dao;

/**
 * 持久层接口
 */
public interface AccountDao {
    void saveAccount();
}
package com.howling.Before.Dao;

/**
 * 持久层
 */
public class AccountDaoImpl implements AccountDao {
    public void saveAccount() {
        System.out.println("持久化层接口");
    }
}
package com.howling.Before.Service;

/**
 * 业务层接口
 */
public interface AccountService {
    void saveAccount();
}
package com.howling.Before.Service;

import com.howling.Before.Dao.AccountDao;
import com.howling.Before.Dao.AccountDaoImpl;

/**
 * 业务层
 */
public class AccountServiceImpl implements AccountService{

    private AccountDao accountDao = new AccountDaoImpl();

    public void saveAccount() {
        System.out.println("业务层调用持久化层");
        accountDao.saveAccount();
    }
}
package com.howling.Before;

import com.howling.Before.Service.AccountService;
import com.howling.Before.Service.AccountServiceImpl;

public class Before {
    public static void main(String[] args) {
        AccountService accountService = new AccountServiceImpl();
        accountService.saveAccount();
    }
}

以前做法的缺点分析

以前的做法耦合太严重,既然说到耦合,就说一下程序的耦合

耦合:程序之间的依赖关系,其中包括类和类之间的依赖关系,程序和程序之间的依赖关系

我们要做到解耦合,应该做到的程度是:编译器中看不到依赖,但是在运行中能够依赖。

使用工厂和配置文件来简化

工厂模式概述

工厂模式,属于23种设计模式中的一种,属于比较常使用的设计模式之一

工厂模式,顾名思义。

假如我们之前都是手工制品,现在我们要上流水线了。

说到工厂模式在提一嘴JavaBean,Bean这个词在英语单词中有豆子的意思,也有着可重用组件的含义。

之前我们一直说创建一个实体类,一个标准的实体类可以叫做JavaBean,其实JavaBean的含义是包含实体类的。

JavaBean>实体类,JavaBean是可重用组件的一部分


准备工作

1、编写持久化层和业务层

package com.howling.FactoryDecoupl.Dao;

/**
 * 持久层接口
 */
public interface AccountDao {
    void saveAccount();
}
package com.howling.FactoryDecoupl.Dao;

/**
 * 持久化层
 */
public class AccountDaoImpl implements AccountDao {
    public void saveAccount() {
        System.out.println("持久化层");
    }
}
package com.howling.FactoryDecoupl.service;

/**
 * 业务层接口
 */
public interface AccountService {
    void saveAccount();
}
package com.howling.FactoryDecoupl.service;

/**
 * 业务层
 */
public class AccountServiceImpl implements AccountService{
    public void saveAccount() {
        System.out.println("业务层");
    }
}

因为要使用工厂来创建,所以业务层没有调用持久化层,表现层根本没写

2、通过反射来创建对象,从而避免使用new关键字

  • bean.properties
## 在resources下面创建bean.prpperties
accountDao=com.howling.FactoryDecoupl.Dao.AccountDaoImpl
accountService=com.howling.FactoryDecoupl.service.AccountServiceImpl
使用工厂

创建Bean工厂

package com.howling.factory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 静态工厂
 */
public class BeanFactory {

    private static Properties properties;

    static {

        try {
            properties = new Properties();

            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");

            properties.load(inputStream);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 工厂模式创建bean工厂
     *
     * @param beanName bean的名称
     * @return bean
     */
    public static Object getBean(String beanName) {

        Object bean = null;

        try {
            String property = properties.getProperty(beanName);

            bean = Class.forName(property).newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return bean;
    }

    /**
     * 创建一个对应类型T的对象
     *
     * @param beanName bean的名称
     * @param tClass   类型参数
     * @param <T>      类型
     * @return 对象
     */
    public static <T> T getBean(String beanName, Class<T> tClass) {

        T bean = null;

        try {
            String property = properties.getProperty(beanName);

            bean = (T) Class.forName(property).newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return bean;
    }
}
package com.howling;

public class People {
    public void eat() {
        System.out.println("吃饭");
    }
}
people=com.howling.People

现在我们可以来进行配置文件和工厂的测试了


工厂模式的问题

现在的工厂模式是不完美的

  • 多例:工厂每次启动都会产生不同的实例,每次调用的实例均不相同,这样会导致内存大幅消耗

思路:

为了解决这个问题,我们引入单例模式,单例模式也是设计模式中的一种

1、我们使用单例模式对工厂进行改造,这样工厂每次返回的实例都是一个

2、之前我们每次创建一个新的对象都是使用Class.forName(beanName).newInstance();来进行创建的,假如我们要返回一个实例,那么这个语句只能执行一次

3、语句执行一次创建对象之后,我们将初始化的值存储起来以作备用,以后就不用创建,直接返回即可

单例工厂

package com.howling.factory;

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

public class SingleBeanFactory {

    private static Properties properties;

    private static Map<String, Object> factories = new HashMap<>();

    static {

        try {
            properties = new Properties();
            InputStream inputStream = SingleBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            properties.load(inputStream);


            // 获得所有的Key
            Enumeration<Object> enumeration = properties.keys();

            // 根据key进行遍历,将所有的东西装载进工厂中
            while (enumeration.hasMoreElements()) {

                String key = enumeration.nextElement().toString();

                String property = properties.getProperty(key);

                Object o = Class.forName(property).newInstance();

                factories.put(key, o);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得bean对象
     *
     * @param name bean对象的名称
     * @return bean对象
     */
    public static Object getBean(String name) {

        Object o = null;

        try {
            o = factories.get(name);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return o;
    }

    /**
     * 获得bean对象
     *
     * @param name   bean对象的名称
     * @param tClass bean对象类型
     * @param <T>
     * @return bean对象
     */
    public static <T> T getBean(String name, Class<T> tClass) {

        T o = null;

        try {
            o = (T) factories.get(name);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return o;
    }
}

懒加载静态单例工厂

我们可以看到,在上面的过程中,单例工厂是没有办法进行按需加载的,也就是说它必须要一次性加载完成,即使配置文件中存放有很多的类,所以我们必须要对他进行简化,让它懒加载

package com.howling.factory;

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

public class LazySingleBeanFactory {
    private static Properties properties;

    private static final Map<String, Object> factories = new HashMap<>();

    static {
        try {
            properties = new Properties();
            InputStream inputStream = LazySingleBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static Object getBean(String name) {
        Object o;
        if ((o = factories.get(name)) != null) {
            return o;
        }
        try {
            String value = properties.getProperty(name);
            o = Class.forName(value).newInstance();
            factories.put(name, o);
            return o;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T getBean(String name, Class<T> tClass) {
        T o;
        if ((o = (T) factories.get(name)) != null) {
            return o;
        }
        try {
            String value = properties.getProperty(name);
            o = (T) Class.forName(value).newInstance();
            factories.put(name, o);
            return o;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。