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>