Spring工厂模式,模拟ApplicationContext实现

一、什么是 Spring

        Spring 是一个轻量级的 Java 企业开发解决方案。它集合了众多优秀的设计模式如:单例、代理、工厂模式等。在这其中最基础的也就是工厂模式。

二、Spring 为什么是轻量级

        在 Spring 问世之前 JavaEE 开发主流使用 Enterprise JavaBean (EJB)来进行。但是这个框架是重量级的,扩展性以及移植性都是很大的问题并且运行环境苛刻。EJB 的运行依靠 EJB 容器并且 Tomcat 不支持。而在当时拥有这项服务的公司以及产品有 Oracle 公司的 Weblogic ApplicationService(运行环境) 以及 IBM 公司的 Websphere ApplicationServer。这两款产品 EJB 容器对 EJB代码的接口要求不同所以同样的代码不可以在两个平台运行,这就导致了它的扩展性差。并且因为是付费产品代码是闭源的,所以对于企业的不同个性化要求进行扩展是很难的。

       而 Spring 对于开发环境没有额外的要求,开源以及收费的容器都可以运行,并且移植性强。

三、 Spring 管理的层级

        我们熟知的 MyBatis 是作用在 Dao 数据库控制层的。而 Spring 是管理了从 Controller到Service以及Dao层。几乎所有的对象都可以交给 Spring 进行管理达到控制反转IoC的目的。

四、工厂模式是什么?

        工厂提起来就是批量工的一个“盒子”。只要我们需要的东西,都可以通过给工厂提出要求然后获得对象。工厂模式就是这样的思想。通过特定的如对象获取工厂,只需要传入参数或者不传入就可以得到对象达到解除耦合的效果。下面详细讲解为什么可以解耦。

4.1 耦合代码演示(无 Spring 思想)

UserService :

package com.day1springReflection;

public class UserServiceImpl implements UserService{
    // 通过 new 的方式来获取对象
    private UserDao userDao = new UserDaoImpl();

}

这种方式通过 new 的方式直接获得一个对象,这里的 UserDao 是一个接口,如果他的实现方法 UserDaoImpl 发生了变化的话就需要将所有的 UserDaoImpl 地方换成新的 UserDaoImplNew 方法,可能调用地方很多也可能不好定位,如果耦合高的地方可能不好修改甚至可能大幅度修改代码。

4.2 简易工厂类实现

这里我们需要配合配置文件。

思路: (主)通过反射的方式来获取到类对象。

先将类的名称以及类型以 key-value 形式存储在配置文件中,通过获取配置文件的信息来获取到类的类型,再通过反射的方式将对象创建出来。

application.properties :

# key - value 存储形式
userService = com.day1springReflection.UserServiceImpl

 BeanFactory :

package com.day1springReflection;

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

public class BeanFactory {
    private static Properties env = new Properties();

    static {
        try {
            // 获取IO输入流   BeanFactory.class 通过反射来获取 BeanFactory对象
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
            // 文件内容封装到 properties 中,保存为 key = userService,value = com.day1_Spring反射工厂
            env.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    // 获取方式变为
    public static UserService getUserService() {
        UserService userService = null;

        try {
            Class clazz = Class.forName(env.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            System.out.println("问题1");
            System.out.println(userService);
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }

}

userService获取方式变为:

    // 获取方式变为
    public static UserService getUserService() {
        UserService userService = null;

        try {
            Class clazz = Class.forName(env.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            System.out.println("问题1");
            System.out.println(userService);
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }

4.3 通用工厂的设计

        这时候我们发现每次获取对象都有代码的重复,如Class.forName.....  所以我们考虑写一个   getBean 方法来将冗余的重复代码写在这个方法里,并且 key 通过参数的方式来传入。所以有了下面的代码

package com.day1springReflection;

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

public class BeanFactory {
    private static Properties env = new Properties();

    static {
        try {
            // 获取IO输入流   BeanFactory.class 通过反射来获取 BeanFactory对象
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
            // 文件内容封装到 properties 中,保存为 key = userService,value = com.day1_Spring反射工厂
            env.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String key) {
        Object ret = null;
        try {
            Class clazz = Class.forName(env.getProperty(key));
            ret = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }


}

此时 userService 的获取变成了:

package com.day1springReflection;

public class UserServiceImpl implements UserService{
   private UserDao userDao = (UserDao) BeanFactory.getBean("userDao");

}

这样实现就解除了代码的耦合,如果有新的方法替代只需要在配置文件中写入方法名以及类型就好。这样就只需要最外层的代码中修改就好了。

这个工厂的本质就是 ApplicationContext 。配置文件就是 applicationContext.xml

你可能感兴趣的:(spring,mysql,java)