spring01-引入

Posted ann-zhgy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring01-引入相关的知识,希望对你有一定的参考价值。

耦合


  1. 什么是耦合?
    • 耦合表示类与类之间的联系, 类与类之间的联系越强, 耦合度越高
  2. 通过例子来说明
    • 我们写了两个类, 其中beanService中需要用到beanDao来实现功能
      • beanDao接口和实现类

        public interface BeanDao {
            // 模拟add方法
            void add();
        }
        
        public class BeanDaoImpl implements BeanDao {
            @Override
            public void add() {
                System.out.println("添加bean信息");
            }
        }
      • beanService接口和实现类

        public interface BeanService {
            void add();
        }
        
        public class BeanServiceImpl implements BeanService {
            BeanDao dao = new BeanDaoImpl();
            @Override
            public void add() {
                dao.add();
            }
        }
      • 测试类及运行结果

        public class Demo {
            @Test
            public void demo01() {
                BeanService service = new BeanServiceImpl();
                service.add();
            }
        }

        技术图片

      • 从代码结构中可以看出: beanService中没有beanDao的耦合度很高, 如果没有BeanDao的实现类, 编译时就会报错

    • 改造一下, 我们可以用工厂模式来解耦
      • 工厂类代码:

        public class BeanFactory {
            public static Object getInstance(String className) {
                try {
                    Class<?> clazz = Class.forName(className);
                    Object obj = clazz.newInstance();
                    return obj;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
      • 有了工厂类代码以后我们就可以改造一下beanServiceImpl

        public class BeanServiceImpl implements BeanService {
            BeanDao dao = (BeanDao) BeanFactory.getInstance("cn.ann.dao.impl.BeanDaoImpl");
        
            @Override
            public void add() { dao.add(); }
        }
      • 运行结果还是一样的


      • 通过改造, BeanServiceImpl和BeanDaoImpl的耦合已经降低, 最直观的效果就是如果没有BeanDaoImpl这个类的话, 程序在编译期间不会报错
      • 但是, 还有一些问题: className是写死的, 如果我们的实现类不在这个路径, 或者是不叫这个名字, 就没办法通过工厂获取这个类的对象了


  • 继续改造, 加配置文件是不错的选择
    • 配置文件bean.properties

      beanDao=cn.ann.dao.impl.BeanDaoImpl
    • beanFactory

      public class BeanFactory {
          private static Map<String, String> props = new HashMap<>();
      
          static {
              try (InputStream is = BeanFactory.class.getClassLoader().
                      getResourceAsStream("bean.properties")) {
                  Properties prop = new Properties();
                  prop.load(is);
                  Set<String> keys = prop.stringPropertyNames();
                  keys.forEach((key) -> props.put(key, prop.getProperty(key)));
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          public static Object getInstance(String key) {
              if (props.containsKey(key)) {
                  try {
                      Class<?> clazz = Class.forName(props.get(key));
                      Object obj = clazz.newInstance();
                      return obj;
                  } catch (Exception e) {
                      e.printStackTrace();
                      return null;
                  }
              } else {
                  throw new RuntimeException("配置文件中不存在该key");
              }
          }
      }
      • 通过改造, 我们可以将BeanServiceImpl中成员变量的初始化改成BeanDao dao = (BeanDao) BeanFactory.getInstance("beanDao");

    • 通过加配置文件, 我们可以通过修改配置文件的方式来修改BeanDao的实现类. 那么还有什么问题呢?
      • 如果出现了频繁使用beanServiceImpl的场景的话, 我们是不是要创建很多类呢? 或许我们可以让创建出来的对象成为单例的


  • 再次改造
    • BeanFactory

      public class BeanFactory {
          private static Map<String, Object> instances = new HashMap<>();
      
          static {
              try (InputStream is = BeanFactory.class.getClassLoader().
                      getResourceAsStream("bean.properties")) {
                  Properties prop = new Properties();
                  prop.load(is);
                  Set<String> keys = prop.stringPropertyNames();
                  keys.forEach((key) -> {
                      try {
                          instances.put(key, Class.forName(prop.getProperty(key)).newInstance());
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  });
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          public static Object getInstance(String key) {
              if (instances.containsKey(key)) {
                 return instances.get(key);
              } else {
                  throw new RuntimeException("配置文件中不存在该key");
              }
          }
      }
    • 运行结果:
      技术图片
      • 通过运行结果可以看出, BeanDaoImpl是同一个对象

本篇到此结束, 这篇文章的重点是关于耦合这方面的, 所以并没有考虑关于线程的问题
本篇代码下载链接: 点击此处 的 spring01-introduce



以上是关于spring01-引入的主要内容,如果未能解决你的问题,请参考以下文章

spring01-引入

Spring MVC 3.2 Thymeleaf Ajax 片段

使用 Git 来管理 Xcode 中的代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

thymeleaf引入公共页面的某个片段