Spring解耦的简单演示

0、相关类

User

package com.yusian;

public class User {

    private String username;
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

UserDao

package com.yusian;

public interface UserDao {

    void register(User user);

    boolean login(String username, String password);
}

UserDaoImpl

package com.yusian;

public class UserDaoImpl implements UserDao {

    @Override
    public void register(User user) {
        System.out.println("user " + user + " register success!!");
    }

    @Override
    public boolean login(String username, String password) {
        System.out.println("user " + username + " login success!!");
        return false;
    }
}

UserService

package com.yusian;

public interface UserService {

    void register(User user);

    boolean login(String username, String password);

}

UserServiceImpl

package com.yusian;

public class UserServiceImpl implements UserService{
    private UserDao userDao = new UserDaoImpl();
    @Override
    public void register(User user) {
        userDao.register(user);
    }

    @Override
    public boolean login(String username, String password) {
        return userDao.login(username, password);
    }
}

1、构造函数方式创建对象

  @Test
  public void userTest() {
      UserService userService = new UserServiceImpl();
      User user = new User("sian", "123456");
      userService.register(user);
      userService.login("sian", "12345");
  }

此时,接口UserService的实现对象与业务是耦合的,因为如果要更换接口的实现类是需要在调用处去修改new出来的类名,为了解决这个问题,我们可以将创建接口实例的过程进行封装,通过一个工具类创建出来,这样就可以将创建对象的过程从业务代码中释放出来。

2、工厂模式创建对象

package com.yusian;
public class BeanFactory {
    public static UserService getUserService() {
        return new UserServiceImpl();
    }
}

虽然通过构造函数创建实例的过程从业务中抽离出来,但只是转移了位置而已,并没有从根本上解决问题,如果需要更换接口实现类,还是需要修改代码重新编译,能不能不编译改了就生效呢?可以的!

3、通过配置文件及反射方式创建实现

3.1、反射创建实例

public static UserService getUserService() {
    try  {
        Class cls = Class.forName("UserServiceImpl");
        return (UserService) cls.newInstance();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

反射机制可以动态创建对象,给定类名就能实现,这种方式奠定了通过配置就能修改接口实例的基础。目前类名还是在写在代码中的,接下来只需要将这个字符串从代码中解脱出来,从配置文件读取即可。

ApplicationContext.properties

userService = com.yusian.UserServiceImpl

BeanFactory

package com.yusian;

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

public class BeanFactory {

    private static Properties prop = new Properties();

    static {
        ClassLoader classLoader = BeanFactory.class.getClassLoader();
        try (InputStream is = classLoader.getResourceAsStream("ApplicationContext.properties")) {
            prop.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static UserService getUserService() {
        try  {
            Class cls = Class.forName(prop.getProperty("userService"));
            return (UserService) cls.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

搞定,打完收工!现在如果有UserService的其他实现类,只需要将ApplicationContext.properties中的字符串修改成对应的类名即可,将耦合从代码中解脱出来,通过配置文件完成切换。

3.2、封装反射方法为工厂

public static Object getBean(String name) {
    try  {
        Class cls = Class.forName(prop.getProperty(name));
        return cls.newInstance();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

4、Sping创建对象的基本使用

回顾以上解耦的步骤,大致分为:

  1. 准备POJO类、配置文件;
  2. 读取配置文件,获取需要创建对象的全限定类名;
  3. 通过反射机制创建实例对象

Sping其实也一样:

  1. 准备POJO类、配置文件(applicationContext.xml);

  2. 读取配置文件,获取上下文对象;

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
  3. 通过反射机制创建实例对象
    Object obj = ctx.getBean("object");
    

最简单的Spring使用及其原理解析就是这么简单,重点在这种思想,理解了就知道为什么会是这样了!

Leave a Reply