1. bean的配置
Spring可以看做一个大工厂,用于生产和管理Spring容器中的Bean,需要开发者将Bean配置在Spring的配置文件中。Spring框架支持XML和Properties两种格式的配置文件,实际开发中常用XML格式的配置文件。
从上一篇博客可知XML配置文件的根元素是
属性或子元素名称 | 描述 |
---|---|
id | 是一个Bean的唯一标识符,Spring容器对Bean的配置、管理都通过该属性来完成 |
name | Spring容器同样可以通过此属性对容器中的Bean进行配置和管理,name属性中可以未Bean指定多个名称,每个名称之间用逗号或分号隔开 |
class | 该属性指定了Bean的具体实现类,它必须是一个完整的类名,使用类的权限定名 |
scope | 用来设定Bean实例的作用域,其属性有singleton(单例)、prototype(原型)、request、session、global Session、application 和websocket。其默认值为singleton |
constructor-arg | |
property | |
ref | |
value | |
list | 用于封装List或数组类型的依赖注入 |
set | 用于封装Set类型属性的依赖注入 |
entry | |
map | 用于封装Map类型属性的依赖注入 |
2. bean的实例化
第一种:构造方法实例化(第一种是重点,第二三种已经没太多人用了)
1.创建一个类:
bean1.java:
1 | package com.spring.demo; |
这个bean只有一个print方法
2.在Spring配置文件Bean.xml 中 配置 bean:
1 |
|
id 为 在 xml 里的这个 bean的标识。 class 为xml 里的这个bean 绑定的java类(bean)的全路径(包名+类名)
这个标签会自动寻找 Bean1类中的无参数构造函数来创建对象
3.测试代码从配置文件中取出Bean1对象:
1 | package com.spring.demo; |
getBean() 返回的就是由spring 实例化的对象。
结果是:打印返回的对象b,和调用 b 的print()方法
第二种:使用静态工厂创建
1.创建一个类:
bean2.java:(就是要创建这个类的对象)
1 | package com.spring.demo; |
2.配置spring的配置文件
1 |
|
表示创建的对象(bean)用bean2指代,使用到的class(类)为com.spring.demo 包 下的Bean2Factory类(作为工厂类)
factory-method = “getBean2”表示调用 class 下的 getBean2方法来创建对象(而且factory-method指定的方法必须为static静态方法)
3.定义静态工厂类
1 | package com.spring.demo; |
注意静态工厂类的创建对象方法为静态
4.测试代码:
1 | public class TextIoc { |
第三种:使用实例工厂创建
1 | package com.spring.demo; |
2.配置spring的配置文件:
1 |
|
第八行:
第九行:
在定义一个bean,id 为bean3,生产它的工厂类为 bean3factory,调用 bean3factory生产 bean3的方法为 (bean3factory的)getBean3()方法
3.(非静态)工厂类
1 | package com.spring.demo; |
4.测试代码:
1 | public class TextIoc { |
运行:
打印出对象,和调用bean3的print方法
静态工厂类与非静态工厂类的区别是,前者不需要创建对象,直接可以调用静态方法创建bean;后者则要先创建对象,然后再通过对象调用其方法创建bean。
3. Bean的作用域
在Spring中不仅可以完成Bean的实例化,还可以为Bean指定作用域。
在Spring Framework
中,总共定义了6种bean
的作用域,其中有4种作用域只有当应用为web
应用的时候才有效,并且Spring
还支持自定义作用域。
下表描述了这6种作用域:
Scope | Description |
---|---|
singleton | (默认的)使用singleton定义的Bean在Spring容器中只有一个Bean实例 |
prototype | 一个bean 定义可以有多个bean 实例。 |
request | 一个bean 定义对应于单个HTTP 请求的生命周期。也就是说,每个HTTP 请求都有一个bean 实例,且该实例仅在这个HTTP 请求的生命周期里有效。该作用域仅适用于WebApplicationContext 环境。 |
session | 一个bean 定义对应于单个HTTP Session 的生命周期,也就是说,每个HTTP Session 都有一个bean 实例,且该实例仅在这个HTTP Session 的生命周期里有效。该作用域仅适用于WebApplicationContext 环境。 |
application | 一个bean 定义对应于单个ServletContext 的生命周期。该作用域仅适用于WebApplicationContext 环境。 |
websocket | 一个bean 定义对应于单个websocket 的生命周期。该作用域仅适用于WebApplicationContext 环境。 |
3.1.1 singleton作用域
singleton
作用域表示在整个Spring
容器中一个bean
定义只生成了唯一的一个bean
实例,被Spring
容器管理。所有对这个bean
的请求和引用都会返回这个bean
实例。
下面的图说明了singleton
作用域是如何工作的:
上图中,有3个地方引用了这个
bean
,这3个引用指向的都是同一个bean
实例。
singleton
作用域是Spring
中默认的作用域,可以在定义bean
的时候指定或者不指定都可以,如下:
1 | <!-- 不指定作用域,默认是singleton --> |
3.1.2 prototype作用域
prototype
作用域表示的是一个bean
定义可以创建多个bean
实例,有点像一个类可以new
多个实例一样。
也就是说,当注入到其他的bean
中或者对这个bean
定义调用getBean()
时,都会生成一个新的bean
实例。
作为规则,应该对所有有状态的
bean
指定prototype
作用域,对所有无状态的bean
指定singleton
作用域。
下图描述了prototype
作用域是如何工作的:
上图中,每个引用对应一个新的
bean
实例。请注意,上图中的例子不适用于生产环境。因为
DAO
通常来说是无状态的bean
,应该指定它的作用域为singleton
比较合适。
在xml
中可以这样定义prototype
作用域:
1 | <bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/> |
和其他作用域不同的是,
Spring
并不管理作用域为prototype
的bean
的整个生命周期。Spring
容器实例化它、配置它、组装它,然后就将bean
交给给使用者了,之后就不会对这个bean
进行管理了。因此,Spring
不会调用该bean
的销毁生命周期回调,使用者必须自己销毁 这个bean
并释放资源。如果想让Spring
来销毁它并释放资源,请使用自定义的bean post-processor
。
4. Bean的生命周期
Spring框架可以管理singleton作用域的生命周期,不可以管理prototype的,因为对于prototype作用域的bean,Spring只负责创建,当容器创建了Bean的实例后,Bean实例就交给了客户端的代码管理,Spring容器不再跟踪其生命周期,而且不会管理那些配置作用域为prototype的bean。
Spring中 bean的生命周期是一个很复杂的过程,可借鉴Servlet的生命周期:
1.实例化
2.初始化(init)
3.接受请求(service)
4.销毁(destroy)
Bean的生命周期如下:
1、实例化一个Bean--也就是我们常说的new;
2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
5. Bean的装配方式
Bean的装配可以理解为依赖关系注入Bean的装配方式即Bean依赖注入的方式.Spring容器支持多种形式的Bean的装配方式,如基于XML的装配、基于注解(Annotation)的装配和自动装配(其中最常用的是基于注解的装配),接下来将对前两种进行详细讲解.
1.基于xml的装配
(1)创建Java类,提供有参,无参构造方法,以及属性的set方法.
1 | package xml; |
(2)配置xml
1 | <bean id="user1" class="xml.User"> |
(3)测试类
1 | public class Test { |
运行结果如下:
User{username=’tom’, password=null, list=null}
User{username=’cat’, password=null, list=null}
2.Annotation注解:
基于XML的装配可能会导致XML配置文件过于臃肿,给后续的维护和升级带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。
(1)xml配置
<context:component-scan base-package=”annotation” />
上面为自动扫描包下所有Bean.但是不会自动装配,在此结合注解使用.
(2)UserDao接口的配置(略)以及UserDaoImpl类:
1 | "userDao") ( |
(3)UserService接口的配置(略)以及UserServiceImpl类:
1 | "userService") ( |
(4)UserController
1 | "userController") ( |
(5)测试类
1 | public class Test1 { |
运行结果如下:
userdao…save…
(参考自:<<JavaEE企业级开发应用教程>>)