Spring从入门到入土(解耦的实现过程)

简介: 这篇文章详细讲解了在Spring框架中实现解耦的多种方法,包括使用接口、配置文件、BeanFactory模式以及单例模式,旨在降低代码间的依赖关系,提高程序的可维护性和扩展性。

1. 何为解耦

  • 让引用变量能够指向多个不同的对象(接口)

2. 解耦的优势

  • 能够在不修改源码的基础之上, 切换引用变量中的对象(符合开闭原则)
  • 低耦合意味着维护成本低, 程序的可扩展能力强

3. 未解耦

  • 未解耦的情况下, 要想使用不同的对象就只能修改源码, 重新new出对象

类目录结构

public class Iphone {
    public void sysName(){
        System.out.println("苹果手机!");
    }
}
public class MiPhone {
    public void sysName(){
        System.out.println("小米手机!");
    }
}
public class Man {
    public void usePhone(){
        MiPhone phone = new MiPhone();
        //Iphone phone = new Iphone();
        System.out.print("我使用");
        phone.sysName();
    }
}
public class Demo {
    public static void main(String[] args) {
        Man man = new Man();
        man.usePhone();
    }
}

4. 使用接口解耦

  • 使用接口解耦后, 就可以修改全类名创建不同的对象
public interface Phone {
    void sysName();
}
public class Iphone implements Phone{
    @Override
    public void sysName(){
        System.out.println("苹果手机!");
    }
}
public class MiPhone implements Phone{
    @Override
    public void sysName(){
        System.out.println("小米手机!");
    }
}
public class Man {
    public void usePhone(){
        Object obj = null;
        try {
            //使用全类名获取字节码对象
            Class<?> aClass = Class.forName("org.example.Iphone");
            //通过字节码对象反射创建对象
            obj = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //使用接口对象接上面反射创建的对象
        Phone phone = (Phone)obj;
        System.out.print("我使用");
        phone.sysName();
    }
}
public class Demo {
    public static void main(String[] args) {
        Man man = new Man();
        man.usePhone();
    }
}

5. 使用配置文件(Properties)

  • 配置文件的引入后, 不修改源码的前提下修改配置文件实现不同对象的切换

bean.properties配置文件

#key = value
phone=org.example.MiPhone
public interface Phone {
    void sysName();
}
public class Iphone implements Phone{
    @Override
    public void sysName(){
        System.out.println("苹果手机!");
    }
}
public class MiPhone implements Phone{
    @Override
    public void sysName(){
        System.out.println("小米手机!");
    }
}
import java.io.InputStream;
import java.util.Properties;

public class Man {
    public void usePhone(){
        Object obj = null;
        try {
            //读取配置文件
            Properties ps = new Properties();
            InputStream res =
                    Man.class.getClassLoader().getResourceAsStream("bean.properties");
            ps.load(res);
            //使用key值获取value
            String beanValue = ps.getProperty("phone");

            //全类名获取字节码对象
            Class<?> aClass = Class.forName(beanValue);
            //通过字节码对象反射创建对象
            obj = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Phone phone = (Phone)obj;
        System.out.print("我使用");
        phone.sysName();
    }
}
public class Demo {
    public static void main(String[] args) {
        Man man = new Man();
        man.usePhone();
    }
}

6. BeanFactory模式

  • 将读取配置文件, 创建对象等工作交给BeanFactory类, 简化Man类, Man类直接通过BeanFactory对象获取对象即可
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {
    //定义一个Properties对象
    private static Properties ps = new Properties();
    //静态代码块, 仅在类加载时执行一次
    static{
        //读取配置文件
        InputStream res =
                Man.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            ps.load(res);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static Object getBean(String beanId){
        Object bean = null;
        try {
            //使用key值获取value
            String beanValue = ps.getProperty(beanId);
            //全类名获取字节码对象
            Class<?> aClass = Class.forName(beanValue);
            //通过字节码对象反射创建对象
            bean = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }
}
public class Man {
    public void usePhone(){
        Phone bean = (Phone) BeanFactory.getBean("phone");
        System.out.print("我使用");
        bean.sysName();
    }
}

7. 多例的测试

  • 通过BeanFactory获取两个bean对象, 测试这两个对象是否为同一个对象
public class Man {
    public void usePhone(){
        Phone bean = (Phone) BeanFactory.getBean("phone");
        System.out.print("我使用");
        bean.sysName();

        Phone bean1 = (Phone) BeanFactory.getBean("phone");
        System.out.println("bean : "+bean);
        System.out.println("bean1: "+bean1);
        if(bean == bean1){
            //单例
            System.out.println("单例模式");
        }else{
            //多例
            System.out.println("多例模式");
        }
    }
}

8. 单例的实现

  • 通过将创建的对象存放到HashMap集合之中, 然后通过beanId将HashMap中指定的对象返回, 实现单例
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

//单例工厂
public class BeanFactorySingleton {
    //定义一个Properties对象
    private static Properties ps = new Properties();
    //创建一个hashMap对象存储创建的bean
    private static Map<String,Object> map = new HashMap<>();

    static{
        //读取配置文件
        InputStream res =
                Man.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            ps.load(res);
            //将配置文件中所有的key放入到Set集合中
            Set<Object> objects = ps.keySet();
            //遍历Set集合(遍历所有key)
            for (Object obj : objects) {
                //获取key
                String key = (String) obj;
                //通过key获取value
                String value = ps.getProperty(key);
                //通过value创建字节码对象
                Class<?> aClass = Class.forName(value);
                //通过字节码对象反射创建对象
                Object bean = aClass.newInstance();
                //将key与创建的对象放入HashMap集合中
                map.put(key,bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static Object getBean(String beanId){
       //返回map中的指定对象
       return map.get(beanId);
    }
}
public class Man {
    public void usePhone(){
        Phone bean = (Phone) BeanFactorySingleton.getBean("phone");
        System.out.print("我使用");
        bean.sysName();

        Phone bean1 = (Phone) BeanFactorySingleton.getBean("phone");
        System.out.println("bean : "+bean);
        System.out.println("bean1: "+bean1);
        if(bean == bean1){
            //单例
            System.out.println("单例模式");
        }else{
            //多例
            System.out.println("多例模式");
        }

    }
}

相关文章
|
消息中间件 Java 开发者
【颠覆想象】Spring Boot重构未来:解耦与隔离,打造坚不可摧的微服务帝国!
【8月更文挑战第29天】本文通过构建电子商务平台的具体案例,深入探讨了如何利用 Spring Boot 实现服务间的解耦与隔离。文章详细介绍了依赖注入、模块化设计及异步通信等关键技术,并提供了具体代码示例。通过依赖注入,对象间耦合得以降低;模块化设计使各功能域独立,降低系统复杂度;异步通信则利用消息队列提升系统吞吐量与响应速度。这些方法不仅优化了系统架构,还加快了开发进程。
335 0
|
Java 开发者 Spring
Spring Boot 实现解耦和隔离的技术指南
【6月更文挑战第13天】Spring Boot 作为一种流行的 Java 框架,通过其强大的依赖注入和配置管理功能,使得开发者可以轻松实现模块之间的解耦和隔离
377 3
|
JSON 前端开发 Java
Spring Boot框架中的响应与分层解耦架构
在Spring Boot框架中,响应与分层解耦架构是两个核心概念,它们共同促进了应用程序的高效性、可维护性和可扩展性。
322 3
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
264 0
|
XML Java 数据格式
[Spring 基础] 掌握Spring DI,轻松解耦你的应用
[Spring 基础] 掌握Spring DI,轻松解耦你的应用
170 0
|
设计模式 Java uml
彻底搞懂Spring状态机原理,实现订单与物流解耦
状态模式的UML类图如下图所示。
537 0
|
XML 人工智能 Java
Spring中基于xml的IOC解耦
Spring中基于xml的IOC解耦
|
SQL 人工智能 Java
Spring中使用工厂模式解耦详解
Spring中使用工厂模式解耦详解
|
消息中间件 Java Spring
下单流程解耦新方案-你知道Spring事件监听机制吗
下单流程解耦新方案-你知道Spring事件监听机制吗
193 0
|
Java UED Spring
如何实现业务解耦?spring中事件监听了解一下
耦合这个词在平常的开发工作中应该不陌生,简单理解就是代码中各部分关联度过高。
如何实现业务解耦?spring中事件监听了解一下