首页 > 编程知识 正文

什么是spring容器(如何实现ioc)

时间:2023-05-06 11:07:29 阅读:76106 作者:3467

假设您目前正在使用三层体系结构开发项目。 其中有包含登录、注册等功能的用户模块。 现在,您已经创建了User实体类和UserDao数据访问层。

公共类用户{私有Integerid; 私有字符串用户名称; 私有字符串密码; //以下为getter和setter方法}公共接口userdao {//用户user get (字符串用户名,字符串密码); //插入用户voidinsert(useruser ) } publicclassuserdaoimplimplementsuserdao { @ overridepublicusergetbyusername,字符串pape

publicinterfaceuserservice {//userlog in (string username,String password ); 在//void注册器(useruser )中注册} publicclassuserserviceimplimplementsuserservice { @ overridepublicuserlogin (字符串用户) if(user==null(//用户名或密码错误) )返回用户; } @ overridepublicvoidregister (useruser ) userdao.insert ) user; //userDao从哪里来? }很明显,UserServiceImpl需要UserDao的实例UserDao来访问数据库,那么我该如何获得这个UserDao呢?

很多人使用以下代码获取userDao。

publicclassuserserviceimplimplementsuserservice { privateuserdaouserdao=newuserdaoimpl (;如果直接在UserServiceImpl内部新建UserDaoImpl,它看起来很方便,工作正常,但存在一些问题。

目前,用户服务impl依赖于用户服务impl。 如果这两个类是由两个不同的人开发的,则在UserDaoImpl完成之前,UserServiceImpl在编译UserServiceImpl时无法进行测试,因此不能同时工作,以进行单元测试如果有多个数据库实现(即多个UserDao实现类),则无法轻松切换称为依赖注入的技术来解决这些问题。

publicclassuserserviceimplimplementsuserservice { privateuserdaouserdao; //构造函数注入publicuserserviceimpl (userdao userdao ) { this.userDao=userDao; } .}//外部程序userserviceuserservice=newuserserviceimpl (newuserdaoimpl ) ); 当前,userDao不是用UserServiceImpl本身构建的,而是通过UserServiceImpl构造函数传递外部程序。 此操作称为构造函数注入

另一种注入方式—— setter方法注入:

publicclassuserserviceimplimplementsuserservice { privateuserdaouserdao; //setter方法为publicvoidsetuserdao(userdao ) userdao ) { this.userDao=userDao; } .}//外部程序用户服务器

e = new UserServiceImpl();userService.setUserDao(new UserDaoImpl());

不论哪种注入方式,其基本逻辑都是一样的:组件不负责创建自己依赖的组件,而是让外部程序创建依赖组件,然后通过构造函数或setter函数注入进来。其实,这里也蕴含着控制反转的思想,因为创建依赖组件的任务从组件内部转移到了外部程序

使用了依赖注入,前面的几个问题就迎刃而解了,因为UserServiceImpl不再依赖UserDao的具体实现类,我们可以轻松地替换UserDao的实现。

但是问题又来了:该由谁负责对象的组装呢?

答案是:应该由应用的最外层负责对象的组装。例如,在三层架构中,可以在controller层负责service类的组装;如果我们的程序有main函数,也可以在main函数中进行相关组件的组装。

public class UserController{ private UserService userService = new UserServiceImpl(new UserDaoImpl()); public void handleLoginRequest(...) { userService.login(...); ... }}

按照这种方式写程序,项目中的所有组件都按照依赖注入的方式管理自己的依赖,所有组件都由最外层统一组装,如果想替换掉某个组件的实现也很方便,看起来很美好。但是,当项目逐渐变得庞大,组件之间的依赖变多的时候,某个组件可能需要依赖于几十个大大小小的其它组件,创建这样的组件就成了一种折磨:

// 创建一个复杂的组件Component1 c1 = new Component1(new Component2(new Component3()), new Component4(new Component5(), new Component6()), new Component7());

如果这个组件只需要被使用一次,看起来还是可以接受,但是如果这个组件在很多地方都要使用,那么在每个使用的地方都需要写一遍上面创建的代码,这将会产生大量的代码冗余:

public class A{ Component1 c1 = new Component1(new Component2(new Component3()), new Component4(new Component5(), new Component6()), new Component7()); public void f1() { // 使用c1 ... }}public class B{ Component1 c1 = new Component1(new Component2(new Component3()), new Component4(new Component5(), new Component6()), new Component7()); public void f2() { // 使用c1 ... }}public class C{ Component1 c1 = new Component1(new Component2(new Component3()), new Component4(new Component5(), new Component6()), new Component7()); public void f3() { // 使用c1 ... }}

更糟糕的是,如果组件c1依赖的其中一个组件将要被替换,那么上面所有创建c1的代码都要修改,这简直是维护的噩梦!

为了避免这个问题,可以把系统中所有的组件放进一个“容器”中统一管理:

public class Container{ public static Component1 getComponent1() { ... } public static Component2 getComponent2() { ... } public static Component3 getComponent3() { ... } ...}

然后,系统中所有需要使用组件的地方都通过Container类来获取:

public class A{ Component1 c1 = Container.getComponent1(); public void f1() { // 使用c1 ... }}public class B{ Component1 c1 = Container.getComponent1(); public void f2() { // 使用c1 ... }}public class C{ Component1 c1 = Container.getComponent1(); public void f3() { // 使用c1 ... }}

使用这种方法,不论是获取组件还是替换组件都非常方便。但是,现在Container类是通过Java代码来实现的,如果系统中的组件有任何变动,就需要修改代码,然后重新编译项目。在某些场景下,我们可能需要在项目运行时动态地添加、移除或者替换组件。

为了实现组件的动态管理,可以将如何创建组件以及组件之间的依赖关系等信息写入配置文件中,然后项目启动时通过读取配置文件来动态创建所有组件,再放到Container中。这样就可以在项目运行时修改配置文件中的组件信息,而无需重新编译,甚至无需重启服务器:

// 创建ContainerContainer container = new ContainerFactory("container.xml").create();// 获取Component1Component1 c1 = (Component1) container.create("c1");

其实,上面的Container就是一个简单的IOC容器。IOC表示控制反转,意思是创建组件的工作不再由程序员控制,而是由IOC容器控制,程序员只负责告诉IOC容器如何创建某个组件,如果想要这个组件,直接从容器中取就是了,这就是IOC容器的基本逻辑。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。