轻松理解Spring的核心IoC
一说起Spring,都说他最核心的部分就是IoC(Inversion of Control)——控制反转。那么到底什么是控制反转呢,简单的理解就是不用你自己去new一个对象或是根据一个名字向某个地方要对象(后者已经用了IoC单并不彻底),容器会自动给你所要的东西
new对象,需要你自己知道是什么类,而根据名字向容器要对象也需要你知道配置情况,前者完全没有依赖反转,因为需要什么类都是由程序自己决定的。后者已经实现了控制反转,因为只需要配置到Spring的配置文件中,在程序中只需要根据配置的名称来选择即可,具体用那个,是在配置中的。
但是上面两种情况都不是容器给你,都需要某种程度上的“要”。
下面通过Spring和Struts来说明一下容器的“给”:
Struts和Spring集成,如果想让Spring对Action进行注入,那么就必须使得Action是有Spring来创建的,只有这样,Action才能够被容器来管理,里面的对象才能够被容器注入。
上面所说的事情呢,举个喝水的例子吧:
new:你想喝水,那么你需要自己用壶接水,然后烧开,然后自己倒到杯子里面。
向容器要:想喝水了,向别人说一下,我想和谁,于是乎别人就帮你倒了一杯水(好懒啊。。。)
容器给:你把空杯子(接口)放到那,当你拿起杯子的时候,发现有人默默的给你倒好了水(好洋气啊。。)
上面的三个例子只有自己new是没有用IoC的,后两者都用了IoC,只是程度深浅而已,但是推荐使用第三者。
那么用了Spring到底有什么好处呢?
1.我们不再查找、定位、创建和管理对象之间的关系了,都交给了IoC容器来管理,使得代码层次更加清晰
2.Spring的IoC容器是一个轻量级的容器,没有侵入性,不需要依赖容器的API,也不需要实现特殊接口
3.会使框架工作的更好
4.提供了AOP声明式服务能力,可以针对POJO提供声明式服务能力
5.对于资源不再负责开启和关闭,完全由Spring来管理
6.鼓励面向接口编程
7.减少了代码中的耦合,将耦合推迟到了配置文件中,发生了变化也更容易控制
那么下面根据一段代码来看一下Spring到底是如何管理Struts中的Action以及业务逻辑层的注入吧
Web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <context-param> <param-name>contextConfigLocation</param-name> <!--声明spring的配置文件--> <param-value>classpath:applicationContext-beans.xml</param-value> </context-param> <!-- 配置Struts --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置Spring --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
Struts.xml
<struts> <!-- 声明Action是有Spring来管理的 --> <constant name="struts.objectFactory" value="spring"></constant> <!-- 声明登陆的Action --> <package name="textLogin" namespace="/" extends="struts-default"> <!-- 这里的class声明的类是由spring来创建,达到了Action由Spring管理的目的 --> <action name="login" class="loginAction"> <result name="success">success.jsp</result> <result name="error" type="redirect">error.jsp</result> </action> </package> </struts>
applicationContext-beans.xml(Spring的配置文件)
<bean name="loginService" class="com.jianxin.struts2.LoginServiceImpl" /> <bean name="loginAction" class="com.jianxin.struts2.LoginAction"> <property name="loginService" ref="loginService" /> </bean>
LoginAction
public class LoginAction extends ActionSupport { private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private LoginService loginService; public LoginService getLoginService() { return loginService; } public void setLoginService(LoginService loginService) { this.loginService = loginService; } @Override public String execute() throws Exception { String result; if(loginService.Login(name, password)){ System.out.println("登录成功"); result="success"; } else { System.out.println("登录失败"); result="error"; } return result; } }
接口、实现类我就不贴了,自己随便写个就行了,至此可以从Action中看到,只声明了一下接口,并没有具体的实例化,这就是IoC容器的功劳,容器管理对象实例化的工作,更好的支持了面向接口的编程。