• IoC in Spring


      写两个关于Spring中使用IoC的小例子,一个是半动态创建Bean,另一个是全动态创建Bean,它们适合不同的应用场景。

      一、半动态:在一个实际项目中遇到过这样的问题,项目组开发的某个系统具备在LED屏上显示信息的功能。不同客户那里的LED屏各不相同,主要区别是驱动卡和显示格式。如果每次换LED屏时都是靠程序员去替换不同实现的代码,成本可想而知。那么,在不修改既有代码(甚至是不用编译既有工程)的情况下,怎样才能让系统的这个功能适应变化呢?

      首先抽象出一个接口,代表向LED屏打印的功能。

    package com.mmh.printer;
    
    public interface LEDPrinter {
        
        public void print(String content);
    }

      然后根据不同品牌的LED屏,编写具体的打印功能。

    package com.mmh.printer;
    
    public class Brand1LEDPrinter implements LEDPrinter {
    
        @Override
        public void print(String content) {
            // 模拟不同品牌的LED显示屏操作
            System.out.println("这是品牌1的LED显示内容: " + content);
        }
    }

      紧接着编写一个辅助类,客户端程序通过它实现LED屏的打印功能。

    package com.mmh.printer;
    
    public class LEDPrintHelper {
        
        private LEDPrinter printer;
        
        public void setPrinter(LEDPrinter printer) {
            this.printer = printer;
        }
        
        public void print(String content) {
            printer.print(content);
        }
    }

      最后实现一个客户端调用的演示程序。

    package com.mmh.main;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.mmh.printer.LEDPrintHelper;
    
    public class Application {
        
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "appContext.xml");
            
            LEDPrintHelper ledPrintHelper = (LEDPrintHelper) context.getBean("LEDPrintHelper");
            ledPrintHelper.print("业务层产生的数据");
        }
    }

      在LED屏更换时,以上的代码,不管是调用方的还是被调用方的,都不需要做任何的修改。假设现在客户使用的是Brand2品牌LED屏,那么程序员只需要针对这种屏编写具体操作即可。

    package com.mmh.printer;
    
    public class Brand2LEDPrinter implements LEDPrinter {
    
        @Override
        public void print(String content) {
            // 模拟不同品牌的LED显示屏操作
            System.out.println("这是品牌2的LED显示内容: " + content);
        }
    }

    这个具体实现类完全可以封装到一个单独的jar中,那么以前的既有代码对于现在的开发人员可以完全透明。

      应对变化的功能是靠Spring的IoC来实现的。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="LEDPrintHelper" class="com.mmh.printer.LEDPrintHelper">
            <property name="printer" ref="Brand1LEDPrinter" />
        </bean>
    
        <bean id="Brand1LEDPrinter" class="com.mmh.printer.Brand1LEDPrinter" />
        
        <bean id="Brand2LEDPrinter" class="com.mmh.printer.Brand2LEDPrinter" />
    
    </beans>

    该配置文件定义了三个Bean,LEDPrintHelper是调用程序的接口,Brand1LEDPrinter和Brand2LEDPrinter分别代表了两种屏的具体操作。通过属性注入的方式,开发人员手动修改(这就是半动态的意思)LEDPrintHelper的printer属性值,从而更改LED屏的具体操作。

      二、全动态:在实际项目中还遇到过这样的问题,不同类型用户的登录实现方式是不同的,并且在系统的使用过程中用户的类型会不断增加。那么,在不修改既有代码(甚至是不用编译既有工程)的情况下,怎样才能让系统的这个功能适应变化呢?

      首先抽象一个接口,代表用户登录功能。

    package com.mmh.login;
    
    public interface UserLogin {
        public boolean login(String username, String password);
    }

      然后实现不同类型用户的登录过程。

    package com.mmh.login;
    
    public class UserALogin implements UserLogin {
    
        @Override
        public boolean login(String username, String password) {
            System.out.println("根据UserA的业务逻辑处理登录过程");
            
            return true;
        }
    }
    package com.mmh.login;
    
    public class UserBLogin implements UserLogin {
        
        @Override
        public boolean login(String username, String password) {
            System.out.println("根据UserB的业务逻辑处理登录过程");
            
            return true;
        }
    }

      紧接着开放给客户调用端一个统一的接口。这个接口在实际系统中经常会被实现为一个web service。

    package com.mmh.login;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class UserLoginService {
    
        private ApplicationContext context = new ClassPathXmlApplicationContext(
                "appContext.xml");
    
        public boolean login(String username, String password, String logintype) {
            UserLogin userLogin = (UserLogin) context.getBean(logintype);
    
            return userLogin.login(username, password);
        }
    }

      最后还是编写一个客户调用的演示。

    package com.mmh.main;
    
    import com.mmh.login.UserLoginService;
    
    public class Application {
    
        public static void main(String[] args) {
            UserLoginService service = new UserLoginService();
            
            service.login("userA", "123456", "UserALogin");
            
            service.login("userB", "123456", "UserBLogin");
        }
    }

      从上面的代码可以看到,不同的用户可以调用相同的接口进行不同的登录操作,被调用程序根据用户输入的参数自动匹配登录过程(这就是全动态的意思)。并且当系统增加用户类型时,既有代码不需要修改。应对变化的功能仍是靠Spring的IoC来实现的。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="UserALogin" class="com.mmh.login.UserALogin" />
        
        <bean id="UserBLogin" class="com.mmh.login.UserBLogin" />
    
    </beans>
  • 相关阅读:
    队列&栈//最小栈
    队列&栈//最小栈
    队列&栈//完全平方数
    队列&栈//完全平方数
    队列 & 栈//打开转盘锁
    队列 & 栈//打开转盘锁
    队列 & 栈//岛屿的个数
    深入理解计算机系统12——并发编程
    深入理解计算机系统11——网络编程
    深入理解计算机系统10——系统级I/O
  • 原文地址:https://www.cnblogs.com/gofblogs/p/3216293.html
Copyright © 2020-2023  润新知