关于spring的一些概念,网上已经有很多的说明,本系列不会做太多的描述,重心在如何配置上。
一、准备工作
1、安装JDK,配置环境。(本来不想写这条的…想了想,还是写上)
2、下载开发包
Spring官方网址:http://spring.io/
Spring下载网址:http://repo.spring.io/libs-release-local/org/springframework/spring/
注意每种版本和JDK版本的对应关系,否则可能无法兼容:
选择合适的spring版本,包含三个zip文件和一个pom文件,如下图。
我们下载dist.zip,这个压缩包中有libs目录,docs目录和schema目录。libs目录下包含了spring5.2.10的很多jar包,doc目录里就是docs.zip里面的内容,是spring的各种说明文档,schema目录里就是schema.zip里面的内容,是spring的各种配置约束。pom文件这里先忽略不管。
二、构建项目
1、idea新建一个project
这里新建的是一个web项目。不需要web项目的话,不选2即可,配置的方式都是一样的。然后给项目起个名称,点击finish创建完成。
现在的目录是空荡荡的。
2、导入jar包
新建一个libs目录,一般放在src下面或者WEB-INF下面。将下载的jar包复制到此目录下。不需要全部复制进来,可以先将core、beans\context和expression复制进来,此外,Spring运行还需导入commons-logging的jar包:
com.springsource.org.apache.commons.logging-1.1.1.jar。
复制进去后,需要将libs目录作为项目的libraries。如下图进行配置。
看起来已经完成了,但是打开Product Structure会发现有报错。这时在artifacts右侧的Available Elements中的元素右键选择Put into Output Root,添加至根目录。点击apply即可。
3、添加配置文件
在src目录下添加spring配置文件ApplicationContext.xml。
新建的xml配置文件如下图所示,可以看到配置文件的内容都是在这个闭合标签内的,那么beans后面的xmlns等内容都是代表什么意思呢?
首先xmlns的意思是xml命名空间(name space缩写),xmlns:xsi是指xml所遵守的标签规范,这两者是最基本的命名空间定义,而xsi:schemaLocation声明了之前所有命名空间相配套的schema文档的路径。
因此,简单来说,beans后面这些内容的作用是为了引入校验该xml格式合法性的格式文件,确保配置文件增加的节点遵守一定规范。
4、配置bean
bean的实例化有多种方式,不同方式在配置时的写法不尽相同。在实际开发中,最常用的实例化方式是通过无参构造实例化。因此,这里就讲下这种方式的配置写法。
假设存在一个类User.class,要在配置文件中配置这个bean,只要新增标签,并通过id或name属性指定这个bean的名称,通过class属性指定这个类的类名。需要注意的是,class属性值必须是全类名(即包名+类名)。 这样就配好了名为user的bean。
这种方式的配置必须保证User类中存在无参构造(公有或私有都可以),否则实例化bean时会报错!
除了id、name和class属性外,bean常见的属性值还有scope,init-method,destroy-method,lazy-init属性。我们依次讲下这几个属性分别表示什么。
(1)scope:
scope表示bean的作用域,在spring2.0之前bean只有2种作用域即:singleton(单例)、prototype(原型), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。当不配置scope属性时,默认就是singleton。
(1)singleton,单例,顾名思义,在spring容器中只会创建该bean定义的一个实例,所有对这个bean的请求和引用,容器提供的都是这同一个实例。
(2)prototype,原型,与singleton相对的,每一次请求,容器提供的都是一个新的实例,相当于new了一个实例。
(3)后三种我们暂时先不管,后面将web项目时再说。
需要注意的是,这里的singleton单例与GOF设计模式中的单例是有区别的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean。
(2)init-method 和 destroy-method
init-method表示这个bean实例化时要调用的初始化方法。
destroy-method表示这个bean销毁时要调用的方法。
需要注意的是:
singleton和prototype两种bean的生命周期是不同的。不管何种作用域,容器都会调用所有对象的初始化方法,在销毁bean(例如容器关闭)时,singleton会调用配置的销毁方法,但prototype作用域的bean销毁时,Spring容器不会帮我们调用任何方法,因为Spring容器一旦把这个对象交给你之后,就不再管理这个对象了。
(3)lazy-init
当scope=“singleton”,即默认情况下,bean会在启动容器时(即实例化容器时)时实例化。但我们可以指定Bean节点的lazy-init="true"来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。
如果想对所有的默认单例bean都应用延迟初始化,可以在根节点beans设置default-lazy-init属性为true。
5、后处理Bean
后处理Bean也称之为Bean的后处理器,作用是:在Bean初始化的前后,对Bean对象进行增强。它既可以增强一个指定的Bean,也可以增强所有的Bean,底层很多功能(如AOP等)的实现都是基于它的,Spring可以在容器中直接识别调用。
例如在Bean的初始化前后想要添加一些日志信息,就可以使用。
配置方法是:
(1) 先创建一个类,实现BeanPostProcessor 接口;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object obj, String beanName) throws BeansException {
// 参数1:bean对象,参数2,bean的名字,id、name
System.out.println("名为:" + beanName + ",类型为:" + obj.getClass().getName() + "的Bean实例化完了");
// 这里可以做些事情
return obj;
}
@Override
public Object postProcessBeforeInitialization(Object obj, String beanName) throws BeansException {
System.out.println("名为:" + beanName + ",类型为:" + obj.getClass().getName() + "的Bean初始化之前");
// 这里可以做些事情
return obj;
}
}
(2) 将这个类放入spring容器中;
<!-- 配置后处理bean -->
<bean id="myBeanPostProcessor" class="bean.MyBeanPostProcessor"></bean>
(3) 这样就配好了,当我们实例化bean时,会发现输出了预设的日志内容。
6、多配置文件的开发
开发中,常常会出现一个项目存在多个配置文件的问题,那么如何使多个配置文件同时生效呢?
(1)创建容器时指定多个配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(
new String[] { "applicationContext1.xml", "applicationContext2.xml" });
(2)在一个文件中通过import导入其他的,创建容器时读取最上层的配置文件
在applicationContext1.xml中引入applicationContext2.xml
<import resource="applicationContext2.xml"/>
然后创建容器读取配置文件时只读取applicationContext1.xml:
ApplicationContext ac = new ClassPathXmlApplicationContext(
new String[] { "applicationContext1.xml" });
7、测试配置的spring项目
bean配置完了,可以通过容器获取bean,并测试一下上面提到的一些特性。
(1)singleton作用域的bean的实例化时间和单例特性
package bean;
public class User {
public void init(){
System.out.println("user被初始化了");
}
public void destroy(){
System.out.println("user被销毁了");
}
}
在配置文件中配置User.class中定义的init方法和destroy方法,并默认为singleton。
<bean id="user" class="bean.User" init-method="init" destroy-method="destroy"></bean>
在main方法中,实例化spring容器(这里是在类路径下寻找配置文件来实例化容器)。
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
}
此时直接启动main方法,会发现控制输出了"user被初始化了",说明了singleton作用域的bean会在创建容器实例的时候就会创建出它的实例。
我们请求两次bean,比较是否时同一个实例。结果控制台输出了true,表示是同一个实例。
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml"); //user被初始化了
User user1 = (User)ac.getBean("user");
User user2 = (User)ac.getBean("user");
System.out.println(user1 == user2); // true
}
(2)其他
其他包括prototype作用域的特性,lazy-init属性等都可以测出来,这里就不多说明啦。
三、总结
这一章主要是如何简单的创建一个项目,并进行简单的spring的配置,对应了spring的核心之一:IOC 控制反转。下一章,会涉及到spring另一个核心:DI 依赖注入。