Spring IOC入门:从Hello world到Spring

从Hello world开始

先上一段代码:

public class HelloWorldTest {

    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

这是Java里面最简单的一段代码了,做的事情非常简单:控制台打印出“Hello world!”字符串。很明显,这段代码很不好拓展,假如我们想打印别的内容呢?

第一步改动

OK,接下来做一点简单的改动:

public class HelloWorldTest {

    public static void main(String[] args) {
        if (args.length > 0) {
            System.out.println(args[0]);
        } else {
            System.out.println("Hello world!");
        }
    }
}

这样当我们运行带参数时,控制台会输出我们的第一个参数。这样我们就取得了第一个小小的进步:我们可以不修改代码就控制了不同的输出。但还有问题,这个类既控制了参数的输入,又控制了参数的输出。换句话说就是:消息的输入和输出是耦合在一起的。

进一步解耦

让我们更进一步。首先我们添加一个获取消息的类:

public class MessageConsumer {

    public String sayHello(String message) {
        if (Objects.isNull(message) || message.length() < 1) {
            return "Hello world!";
        }
        return message;
    }
}

这样当输入的参数不为null或者空字符串时,输出参数,否则输出Hello world!。调用方只需要在调用的时候传入不同的参数,就达到了输出不同内容的目的。OK,现在已经解耦了消息的输出方,但生产方还在main方法里。接下来解耦消息的生产方。添加一个新的类来生产消息:

public class MessageRenderer {
    private MessageConsumer messageConsumer;

    public void render(){
        if (Objects.isNull(messageConsumer)){
            System.out.println("Hello world!");
        }else {
            System.out.println(messageConsumer.sayHello("MessageRenderer"));
        }
    }

    public MessageConsumer getMessageConsumer() {
        return messageConsumer;
    }

    public void setMessageConsumer(MessageConsumer messageConsumer) {
        this.messageConsumer = messageConsumer;
    }
}

这样主函数只需要new出MessageRenderer和MessageConsumer对象即可,对于消息怎么生产和消费则不需要关心。但这样的问题是MessageRender和MessageConsumer耦合在一起。

面向接口

我们更进一步对两个类进行抽象:

public interface MessageConsumer {

    String sayHello(String message);
}
public interface MessageRenderer {

    void render();

    MessageConsumer getMessageConsumer();

    void setMessageConsumer(MessageConsumer messageConsumer);
}

新建实现类:

public class HelloWorldMessageConsumer implements MessageConsumer {

    @Override
    public String sayHello(String message) {
        return message;
    }
}
public class HelloWorldMessageRenderer implements MessageRenderer {

    private MessageConsumer messageConsumer;

    @Override
    public void render() {
        if (Objects.isNull(messageConsumer)) {
            System.out.println("Hello world!");
        } else {
            System.out.println(messageConsumer.sayHello("HelloWorldMessageRenderer"));
        }
    }

    @Override
    public MessageConsumer getMessageConsumer() {
        return messageConsumer;
    }

    @Override
    public void setMessageConsumer(MessageConsumer messageConsumer) {
        this.messageConsumer = messageConsumer;
    }
}

程序入口:

public class HelloWorldTest {

    public static void main(String[] args) {
        MessageRenderer renderer = new HelloWorldMessageRenderer();
        MessageConsumer consumer = new HelloWorldMessageConsumer();
        renderer.setMessageConsumer(consumer);
        renderer.render();
    }
}

至此,消息的生产和消费解耦开来,生产方只依赖消费方的抽象而不是具体实现,主程序只负责new出需要的生产方和消费方即可。三者的关系如如:

《Spring IOC入门:从Hello world到Spring》

运行程序我们可以得到我们想要的输出内容,但还有一点小问题:我们现在要的是HelloWorldMessageConsumer,假如我们需要别的MessageConsumer呢?那就需要改主程序代码了。

简易版IOC

下面我们添加一个类来生产MessageConsumer和MessageRenderer:

public class MessageSupportFactory {

    private static MessageSupportFactory instance;
    private Properties properties;
    private MessageRenderer messageRenderer;
    private MessageConsumer messageConsumer;

    static {
        instance = new MessageSupportFactory();
    }

    public static MessageSupportFactory getInstance() {
        return instance;
    }

    private MessageSupportFactory() {
        properties = new Properties();
        try {
            properties.load(this.getClass().getResourceAsStream("/msf.properties"));
            String rendererClass = properties.getProperty("renderer.class");
            String consumerClass = properties.getProperty("consumer.class");

            messageRenderer = (MessageRenderer) Class.forName(rendererClass).newInstance();
            messageConsumer = (MessageConsumer) Class.forName(consumerClass).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public MessageRenderer getMessageRenderer() {
        return messageRenderer;
    }

    public MessageConsumer getMessageConsumer() {
        return messageConsumer;
    }
}

msg.properties代码如下:

renderer.class=org.chunrun.learn.sp.message.HelloWorldMessageRenderer
consumer.class=org.chunrun.learn.sp.message.HelloWorldMessageConsumer

主程序代码如下:

public class HelloWorldTest {

    public static void main(String[] args) {
        MessageConsumer consumer = MessageSupportFactory.getInstance().getMessageConsumer();
        MessageRenderer renderer = MessageSupportFactory.getInstance().getMessageRenderer();
        renderer.setMessageConsumer(consumer);
        renderer.render();
    }
}

这样,当我们需要不同的MessageRenderer或MessageConsumer时,只需要在配置文件里指定不同的对象即可。实际上,到这里已经完成了一个简易版的IOC实现。

使用Spring重构

这部分只需要添加配置即可,略。

    原文作者:星河
    原文地址: https://segmentfault.com/a/1190000014707572
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞