疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

简单模拟Ioc容器


 

  Ioc是一种通用的设计原则,依赖注入则是具体的设计模式,体现了Ioc的设计原则,一个好的获取资源的解决方案是应用IoC(Inversion of Control,控制反转)。它的思想是反转资源获取的方向。传统的资源查找方式是要求组件向容器发起请求来查找资源,作为回应,容器适时的返回资源。而应用了IoC之后,则是容器主动的将资源推送到它所管理的组件里,组件所要做的仅仅是选择一种合适的方式接受资源。以下java培训的老师将为大家简单介绍如何模拟Ioc容器

  在DI模式下,容器全权负责的组件的装配,容器以一些预先定义好的方式(例如setter方法或构造函数)将匹配的资源注入到每个组件里。目前有三种类型的DI:

  setter注入,setter注入会存在一些问题,1. 容易出现忘记调用setter方法注入组件所需要的依赖,将会导致NullPointerException异常。2. 代码会存在安全问题,第一次注入后,不能阻止再次调用setter,除非添加额外的处理工作。但是由于setter注入非常简单所以非常流行(绝大多数Java IDE都支持自动生成setter方法)。

  构造器注入,构造器注入能够一定程度上解决setter注入的问题。但是该中注入方式也会带来一些问题,如果组件有很多的依赖,则构造函数的参数列表将变得冗长,会降低代码可读性。

  接口注入 ,该注入方式使用的非常少,它要求组件必须实现某个接口,容器正是通过这个接口实现注入依赖的。接口注入的缺点比较明显,使用接口注入需要实现特定的接口,而接口又特定于容器,所以组件对容器产生了依赖,一旦脱离容器,组件不能重用。这是一种"侵入式"注入。

  其中"setter注入"和"构造器注入"是被广泛运用的,绝大多数的IoC容器都支持这两种DI类型。

  模仿Spring IoC容器

  假设一个系统的功能之一是能够生成PDF或HTML格式的报表。

  1. /*生成报表的通用接口*/

  2. public interface ReportBuilder

  3. {

  4. public void build(String data);

  5. }

  生成PDF和HTML格式的实现类:

  1. /*生成HTML格式报表*/

  2. public class ReportHtmlBuilder implements ReportBuilder {

  3. @Override

  4. public void build(String data) {

  5. /*示意代码*/

  6. System.out.println("build html report!");

  7. }

  8. }

  9.

  10. /*生成PDF格式报表*/

  11. public class ReportPdfBuilder implements ReportBuilder {

  12. @Override

  13. public void build(String data) {

  14. System.out.println("build pdf report!");

  15. }

  16. }

  报表服务类:

  1. /*报表服务类*/

  2. public class ReportService

  3. {

  4. /*依赖"ReportBuilder"*/

  5. private ReportBuilder builder;

  6.

  7. public ReportBuilder getBuilder()

  8. {

  9. return builder;

  10. }

  11.

  12. /*setter注入*/

  13. public void setBuilder(ReportBuilder builder)

  14. {

  15. this.builder = builder;

  16. }

  17.

  18. public void builderYearReport(int year)

  19. {

  20. this.builder.build("data");

  21. }

  22. }

  IoC容器配置文件"component.properties"

  1. pdfBuilder=com.beliefbitrayal.ioc.inter.imp.ReportPdfBuilder

  2. htmlBuilder=com.beliefbitrayal.ioc.inter.imp.ReportHtmlBuilder

  3. reportService=com.beliefbitrayal.ioc.server.ReportService

  4. reportService.builder=htmlBuilder

  IoC容器:

  1. public class Container

  2. {

  3. /*用于储存Component的容器*/

  4. private Map repository = new HashMap();

  5.

  6. public Container()

  7. {

  8. try

  9. {

  10. /*读取容器配置文件"component.properties"*/

  11. Properties properties = new Properties();

  12. properties.load(new FileInputStream("src/component.properties"));

  13.

  14. /*获取配置文件的每一行信息*/

  15. for(Map.Entry entry : properties.entrySet())

  16. {

  17. String key = (String)entry.getKey();

  18. String value = (String)entry.getValue();

  19.

  20. /*处理配置文件的每一行信息*/

  21. this.handler(key, value);

  22. }

  23. }

  24. catch (Exception e)

  25. {

  26. e.printStackTrace();

  27. }

  28. }

  29.

  30. private void handler(String key,String value) throws Exception

  31. {

  32. /*

  33. * reportService=com.beliefbitrayal.ioc.server.ReportService

  34. * reportService.builder=htmlBuilder

  35. * 第一种情况,key值中间没有"."说明为一个新组件。对它的处理为创建它的对象,将其对象放入Map中。

  36. * 第二种情况,key值中间出现"."说明这个属性条目是一个依赖注入。根据"."的位置将这个key值划分为两部分,第一部分为组件的名字,第二部分为

  37. * 该组件需要设置的属性。

  38. */

  39. String[] parts = key.split("\.");

  40.

  41. /*情况1*/

  42. if(parts.length == 1)

  43. {

  44. /*通过反射的方式创建组件的对象*/

  45. Object object = Class.forName(value).newInstance();

  46.

  47. this.repository.put(key, object);

  48. }

  49. else

  50. {

  51. /*对于情况2,首先用key值的第一部分(组件名)获取组件*/

  52. Object object = this.repository.get(parts[0]);

  53.

  54. /*再使用value值指定的组件名从Map对象中获取依赖*/

  55. Object reference = this.repository.get(value);

  56.

  57. /*将获取的依赖注入到指定的组件的相应属性上,"PropertyUtils"类属于Apache下Commons BeanUtil第三方类库,

  58. * 要使用它还需要下载Commons Logging第三方类库

  59. */

  60. PropertyUtils.setProperty(object, parts[1], reference);

  61. }

  62. }

  63.

  64. public Object getComponent(String key)

  65. {

  66. return this.repository.get(key);

  67. }

  68. }

  根据配置文件,我们在场景类中使用的报表应该是HTML格式的:

  1. public class Client

  2. {

  3. public static void main(String[] args)

  4. {

  5. /*创建容器*/

  6. Container container = new Container();

  7.

  8. /*从容器中获取"报表服务类"*/

  9. ReportService reportService = (ReportService)container.getComponent("reportService");

  10.

  11. /*显示报表*/

  12. reportService.builderYearReport(0);

  13. }

  14. }

  控制台的输出:

  1. build html report!

  我们若需要PDF格式的只需要修改属性文件即可:

  1. pdfBuilder=com.beliefbitrayal.ioc.inter.imp.ReportPdfBuilder

  2. htmlBuilder=com.beliefbitrayal.ioc.inter.imp.ReportHtmlBuilder

  3. reportService=com.beliefbitrayal.ioc.server.ReportService

  4. reportService.builder=pdfBuilder

  场景类不变,控制台输出:

  1. build pdf report!

  以上介绍的就是关于控制反转Ioc的具体介绍了,希望能对你有帮助!Ioc是我们在开发过程中经常使用的,对于我们的开发有着重要的作用。我们在学习java的过程中一定要掌握好这个知识点。如果你也想要找合适的java培训机构,那么就到广州疯狂java了解吧!