接下来这段时间,我将会写一个关于springMVC的博客专栏,首先看看百度百科上是怎么定义springMVC的。
Spring是一个开源框架,Spring是于2003
年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert
One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。
先来看看spring官方为我们提供的一张图片:
是不是看的云里雾里的,什么是IOC,什么又是AOP还有什么又是springMVC,接下来的这个系列的博客,我将会带大家逐步学习spring。我们首先来学习spring 的ioc模块吧。
ioc又名控制反转,说白了就是把对象的创建,销毁以及初始化等一系列操作交给spring容器来处理,由spring来控制对象的声明周期。举个栗子:我们现在写了很多java类,然后书写一个spring的配置文件,将这些类交给spring容器来处理,此时这些对象的初始化以及销毁就会由spring来管理,如果我们需要使用对象的话,只需要遵守spring中的规范来书写代码,就可以得到指定的对象,对于应该遵守什么样的规范,这个以后我们在详细来探讨。这也就是我们ioc(控制反转的来历)。即将对象交给spring来控制管理。那么ioc带给我们的优势又有那些呢??大家仔细想想,到现在我们如果需要用到某一个类对象,只能通过手动new出来,那有人可能会说了,我不是可以使用工厂模式吗?注意:工厂模式只是提供给我们创建对象的一个简单调用,其内部同样是new一个我们需要的对象,但是如果使用spring以后,我们只需要在spring的配置文件里边配置好需要有spring来管理的类,具体的该对象的创建管理等都是由spring来做的。废话不多说,我们先来看一个例子:
我们新建一个java工程,将spring需要的核心jar包拷贝进去。
1.dist/spring.jar
2.lib/jakarta-commons/commons-logging.jar
这两个就是spring需要的核心jar文件,接下来我们新建一个类HelloIoc.java
package com.test.ioc; public class HelloIoc { public void helloIoc() { System.out.println("hello ioc first"); } }
接下来,给大家演示用spring来管理HelloIoc这个类。首先,我新建一个applicationContext.xml文件:内容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" <span style="white-space:pre"> </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <span style="white-space:pre"> </span>xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <span style="white-space:pre"> </span><bean id="helloIoc" class="com.test.ioc.HelloIoc"> <span style="white-space:pre"> </span> <span style="white-space:pre"> </span></bean> </beans>
那么,有人可能会问,这么多的东西我怎么记得住呢,不用急,我也是在官方文档中找到的。可以看到,这里的根节点的名称叫做beans,即包含了很多其他的bean,在这里一个bean就是一个具体的类。
说明一下:这里bean中的id就是唯一标识一个bean的,一般是类名称的第一个字母小写。class顾名思义就是这个类的全类名,大家写的时候,可以按住ctrl键然后点击,如果可以进入,说明class的值是正确的。
spring容器到现在已经创建好了,现在我们写一个测试类,加载spring容器,将HelloIoc从容器中拿出来。
package com.test.ioc; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class HelloIocTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/test/ioc/applicationContext.xml"); HelloIoc helloIoc = (HelloIoc) applicationContext.getBean("helloIoc"); helloIoc.helloIoc(); } }
此时运行我们的main方法,会发现helloIoc()方法已经被执行了,发现我们是没有new HelloIoc这样的方式来创建,而是通过spring容器来为我们创建该对象的。这里需要注意,ApplicationContext就是我们的上下文,通过它来加载配置文件的,然后通过
applicationContext.getBean("helloIoc");来获取我们的实体类,这里getBean中的参数就是我们在spring配置文件中配置的bean的id。
接下来我们在HelloIoc中加上构造方法,如下:
package com.test.ioc; public class HelloIoc { public void helloIoc() { System.out.println("hello ioc first"); } public HelloIoc() { super(); System.out.println("HelloIoc has been init"); } }
然后两次获取该HelloIoc的对象,如下:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/test/ioc/applicationContext.xml"); HelloIoc helloIoc = (HelloIoc) applicationContext.getBean("helloIoc"); HelloIoc helloIoc2 = (HelloIoc) applicationContext.getBean("helloIoc"); System.out.println(helloIoc); System.out.println(helloIoc2);
此时,控制台打印结果是这样的:
HelloIoc has been init
[email protected]
[email protected]
可以发现虽然我们得到了两个HelloIoc对象,可是这两个对象是一样的,同时发现构造方法也执行了一次,这就充分说明spring默认为我们创建对象是用的单例模式。可是这里有一个问题,就是单例模式的时候,会出现线程安全问题,比如我现在在为HelloIoc中添加一个String name变量,并且提供get,set方法:
package com.test.ioc; public class HelloIoc { private String name = ""; public void helloIoc() { System.out.println("hello ioc first"); } public HelloIoc() { super(); System.out.println("HelloIoc has been init"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
然后将测试类的代码修改如下:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/test/ioc/applicationContext.xml"); HelloIoc helloIoc = (HelloIoc) applicationContext.getBean("helloIoc"); HelloIoc helloIoc2 = (HelloIoc) applicationContext.getBean("helloIoc"); helloIoc.setName("xiaoming"); helloIoc2.setName("test"); System.out.println(helloIoc); System.out.println(helloIoc2); System.out.println(helloIoc.getName()); System.out.println(helloIoc2.getName());
此时打印的结果如下:
HelloIoc has been init
[email protected]
[email protected]
test
test
根据结果我们可以看出现在由于是单例模式,所以出现了helloIoc2将helloIoc的name变量修改了。那么如何避免该问题的出现呢,其实在配置文件中添加这样一句话"scope="prototype""就可以取消默认的单例模式创建该bean了。如下:
<bean id="helloIoc" class="com.test.ioc.HelloIoc" scope="prototype"> </bean>
此时的打印结果如下:
HelloIoc has been init
HelloIoc has been init
[email protected]
[email protected]
xiaoming
test
可以发现这个时候,spring为我们创建了两个不同的对象。
这个时候我们已经利用了spring容器来创建我们的对象,现在,我们来演示对象的初始化和销毁的操作。
在spring配置文件中,bean的配置文件中,spring已经为我们提供了对象的初始化和销毁的设置方法:init-method="" destroy-method=""可以看到这样的设置就可以了。接下来我新建一个类,用来演示spring操作对象中初始化和销毁的行为。
package com.test.ioc; public class HelloIocInitDes { public HelloIocInitDes() { super(); System.out.println("HelloIocInitDes runs.."); } public void init() { System.out.println("init runs ..."); } public void destroy() { System.out.println("destroy runs ..."); } }
记住只要我们需要让spring来管理该对象,那么必须在spring的配置文件中配置该bean,这里我加上初始化和销毁方法的设置。
<bean id="helloIocInitDes" class="com.test.ioc.HelloIocInitDes" init-method="init" destroy-method="destroy"></bean>
然后新建一个HelloIocInitDesTest.java来测试初始化和销毁的操作。代码如下:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/test/ioc/applicationContext.xml"); HelloIocInitDes helloIocInitDes = (HelloIocInitDes) applicationContext.getBean("helloIocInitDes");
此时运行该HelloIocInitDesTest.java的main方法,结果如下:
HelloIocInitDes runs..
init runs ...
可以看到init方法是在构造方法之后执行的,可是我们发现执行了init方法,而destroy方法并没有执行,这是怎么回事,因为spring还没有准备销毁我们的对象,我们现在模拟关闭spring容器,来让destroy方法得到执行。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/test/ioc/applicationContext.xml"); HelloIocInitDes helloIocInitDes = (HelloIocInitDes) applicationContext.getBean("helloIocInitDes"); ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext; context.close();
此时打印如下:
可以发现此时destroy方法得到了执行。
可是,如果此时我在HelloIocInitDes中的bean配置文件中加上这样一句话:scope="prototype",即不是用默认单例模式创建对象,会发想destroy-method并没有执行。即使我关闭了spring容器。
总结一下:init-method="init"方法是在构造方法之后由spring容器执行的,我们可以用他来做一些初始化的操作,在destroy-method中做关闭资源等操作,如果该bean不是默认的单例模式创建,此时将不会执行destroy-method。那么关闭资源等操作,将由人为来完成。
那么spring又是什么时候帮我们创建bean对象的呢??在bean的配置文件中有这么一句配置:lazy-init="",该配置存在两个值:
lazy-init="default" 和lazy-init="true"默认是false。这里,当我lazy-init="default"的时候,即spring容器加载进内存以后就会创建该bean对象,如果lazy-init="true",那么只有在执行geBean("")方法的时候才会创建该bean对象。
大家注意一下,目前我们所采用的spring容器中的所有的bean的配置都是采用构造函数来创建bean对象的,接下来我介绍一种利用静态工厂的方式来创建bean对象。首先我新建一个HelloIocFactory.java里边定义一个getInstance方法,用来创建HelloIoc对象。
package com.test.ioc; public class HelloIocFactory { public static HelloIoc getInstance() { return new HelloIoc(); } }
然后再bean中这样配置即可:
<bean id="helloIoc2" class="com.test.ioc.HelloIocFactory" factory-method="getInstance"></bean>
此时如果想要到的HelloIoc对象,只需要像往常那样通过getBean("")方法调用就行了。
今天的springIOC就到这里吧,下一篇我会写一个spring依赖注入的博文,希望大家喜欢。