spring1-spring概述介绍 程序中的耦合问题降低程序间的依赖关系

一、spring介绍

什么是spring?

Spring框架是一个开源的J2EE应用程序框架,是针对bean的生命周期进行管理的轻量级容器,Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。

在这里插入图片描述

名词介绍

Bean:计算机英语用表示可重用的组件

javaBean:java语言编写的可重用组件,如Serivce,Dao

IOC:控制反转(Inversion of control)

AOP:面向切面编程(Aspext Oriented Programming)

spring的主要优势

  • 通过spring提供的核心容器,可以将对象间的依赖关系交给spring控制。
  • AOP编程的支持
  • 声明式事务的支持:通过声明的方式灵活的进行事务管理

二、程序间的耦合

在学习spring之前,需要先了解一下程序间的耦合。等我们了解了程序间的耦合,对理解sping的核心容器有很大的帮助。

耦合也就是程序间的依赖关系,程序间的依赖关系包括:类之间的依赖,方法之间的依赖关系。

我们先来看类之间的依赖关系。

//Service层
public class UserServiceImpl implements UserService {
    
    
    private UserMapper userMapper = new UserMapperImpl();
    @Override
    public void login(String username, String password) {
    
    
        System.out.println("Service : login");
        userMapper.selectUser(username,password);
    }
}
//Mapper层
public class UserMapperImpl implements UserMapper {
    
    
    @Override
    public void selectUser(String username, String password) {
    
    
        System.out.println("Mapper : selectUser");
    }
}

我们可以看到上面的代码中UserServiceImpl依赖于UserMapperImpl,在UserServiceImpl中需要用new关键字来实例化UserMapperImpl。这样做有很多的局限性,如:UserMapperImpl出错或不存在时程序会直接出错。

一般解决类之间依赖关系需要做到编译期不依赖,运行期依赖,为了达到这一目的我们因该避免使用new关键字。可是不用new关键字怎么实例化对象呢,我们知道除了使用new关键字实例化对象,还可以使用反射的技术来实例化对象。

两者间有什么不同呢?可以解决依赖关系吗?

我们回想在使用反射技术来实例化对象时,我们只需要提供一个全类名,程序会在运行期间动态的实例化一个对象,如果该全类名指向的类不存在时,会发生运行时异常。显然使用反射技术实例化对象可以达到编译期不依赖,运行期依赖的效果。所以new和反射的不同在于,new关键字在编译时期就依赖一个具体的类,而反射在编译时期只依赖于一个全限定类名的字符串,在运行期间才会依赖具体的类。

使用反射创建对象不会存在问题吗?
Class.forName("com.mysql.jdbc.Driver");

上述是使用mysql时注册驱动时代码,使用的就是反射技术。我们想如果想使用另外一种数据库就需要来修改代码,这显然是不合适的。我们可以通过配置文件的方式来配置需要用到的全类名。

综上我们可以总结出解除依赖关系的思路

  • 使用反射技术创建对象,避免使用new关键字
  • 提供配置文件,获取要创建对象的全限定类名

我们可以将上面的代码修改为

public class UserMapperImpl implements UserMapper {
    
    
    @Override
    public void selectUser(String username, String password) {
    
    
        System.out.println("Mapper : selectUser");
    }
}

public class UserServiceImpl implements UserService {
    
    
    private UserMapper userMapper =(UserMapper) BeanFactory.getBean("userMapper");
    @Override
    public void login(String username, String password) {
    
    
        System.out.println("Service : login");
        userMapper.selectUser(username,password);
    }
}

这里的BeanFactory.getBean("userMapper"),BeanFactory是一个用于生产Bean对象的工厂类。

public class BeanFactory {
    
    
    //获取bean.properties中的内容
    private static Properties props;
    //用来存储实例化后的对象,在初始化时将所有的配置中所有的bean实例化并存储可以实现单例效果
    private static Map<String,Object> beanMap;
    static {
    
    
        //获取properties文件流
        InputStream rs = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        props = new Properties();
        try {
    
    
            props.load(rs);
            //实例化Bean 并将其添加到beanMap容器中
            beanMap = new HashMap<>();
            //获取配置文件中所有的key
            Enumeration<Object> keys = props.keys();
            while(keys.hasMoreElements()){
    
    
                String key = keys.nextElement().toString();
                //获取key对应的全限定类名
                String beanPath = props.getProperty(key);
                //实例化并添加到容器中
                beanMap.put(key,Class.forName(beanPath).newInstance());
            }
        } catch (Exception e) {
    
    
            throw new ExceptionInInitializerError("beanFactory初始化错误");
        }
    }

    //用于获取Bean对象的方法
    public static Object getBean(String key) {
    
    
        return beanMap.get(key);
    }
}

该工厂类工作流程:先读取bean的配置文件,获取配置中所有的key,使用key获取对应的全限定类名,使用反射技术实例化该对象并将其添加到map容器中。

userMapper=com.zxwin.mapper.impl.UserMapperImpl
userService=com.zxwin.service.imple.UserServiceImpl

我们通过两张图来看一下上面两种实现方式的区别

  • 使用new关键字创建对象

在这里插入图片描述

  • 使用factory来获取对象

在这里插入图片描述

实际上spring的IOC容器就是通过配置文件+反射来实现对Bean对象的管理,我们可以把上面的例子看作是mini版容器

猜你喜欢

转载自blog.csdn.net/weixin_43311669/article/details/115465662