目录
Spring IoC容器的两个接口
依赖注入的类型
Bean的配置
…IOC:控制反转依赖注入。它使程序组件或类之间尽量形成一种松耦合的结构,开发者在使用类的实列之前,需要先创建对象的实列。而IoC是将创建实列的任务交给了IOC容器,这样在开发应用代码的时候只需要直接使用类的实列,而不需要再创建实列。
Spring IoC容器的两个接口
…pring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口。ApplicationContext和BeanFactory的区别在于对Bean的创建时机不同。BeanFactory在初始化的时候,不会被创建,而是在真正获取对象的时候会被创建。ApplicationContext会将其中的所有Bean对象进行创建(即不用的也会被创建)。
1)BeanFactory
BeanFactory ctx=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//通过容器获取配置中的hellospring(id)的实列
Student hello=(Student) ctx.getBean("helpspring");
2)ApplicationContext
…ApplicationContext扩展了BeanFactory容器并添加了对I18N、生命周期事件的发布监听等更加强大的功能。ApplicationContext接口有三个实现类,可以实例化其中任何一个类来创建Spring的ApplicationContext容器。
①ClassPathXmlApplicationContext(将从类路径目录中寻找指定的XML配置文件)
//spring容器初始化,加载applicationContext.xml文件的两种:
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取配置中的hellospring(id)的实列
Student hello=(Student) ctx.getBean("helpspring");
②FileSystemXmlApplicationContext(从指定文件的绝对路径中寻找XML配置文件,找到并装载完成ApplicationContext的实例化工作)
//使用spring的配置文件来创建相应的实列来使用
//spring容器初始化,加载applicationContext.xml文件
ApplicationContext ctx=new FileSystemXmlApplicationContext("E:/applicationContext.xml");
//通过容器获取配置中的hellospring(id)的实列
Student hello=(Student) ctx.getBean("helpspring");
而一般情况下都是用ClassPathXmlApplicationContext来实例化ApplicationContext容器,因为采用加载绝对路径的加载方式将导致程序灵活性差。
③WebApplicationContext 是Spring的Web应用容器,有两种方法可以在Servlet中使用。第一种方法是在Servlet的web.xml文件中配置Spring的ContextLoaderListener监听器;第二种方法同样要修改web.xml的配置文件,在配置文件中添加一个Servlet,定义使用Spring的org.springframework.web.context.Con-textL-oaderServlet类。
依赖注入的类型
…在Spring中实现IoC容器的方法是依赖注入。通常有两种实现方式,一种是使用构造方法注入,另一种是使用属性的setter方法注入。
1)使用属性的setter方法注入
//首先创建JavaBean
public class Student {
private String name;
private int member;
public void setName(String name) {
this.name = name;
}
public void setMember(int member) {
this.member = member;
}
@Override
public String toString() {
return "Student [name=" + name + ", member=" + member + "]";}
}
//applicationContext.xml中的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 如何配置一个bean,将指定类配置给Sprig,让spring来创建其对象的实列 -->
<bean id="helpspring" class="com.spring.ioc01.Student">
<!-- 为属性赋值 -->
<property name="name" value="张三"></property>
<property name="member" value="32"></property>
</bean>
</beans>
//text.java中的代码
@Test
public void test01() {
//使用spring的配置文件来创建相应的实列来使用
//spring容器初始化,加载applicationContext.xml文件
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取配置中的hellospring(id)的实列
Student hello=(Student) ctx.getBean("helpspring");
System.out.println(hello);
//赋值是在xml中。通过spring容器获取实例的对象!
}
//最后的输出结果是:Student [name=张三, member=32]
2)使用构造方法注入
//在用户JavaBean中创建构造方法
public class Student {
private String name;
private int member;
private School school;
public Student(String name, int member, School school) {
super();
this.name = name;
this.member = member;
this.school = school;
}
@Override
public String toString() {
return "Student [name=" + name + ", member=" + member + ", school=" + school + "]";
}}
//school.java中的代码
public class School {
private String name;
public void setName(String name) {
this.name = name;}
@Override
public String toString() {
return "School [name=" + name + "]";
}}
▲constructor-arg元素(直接执行带参构造器)用于定义类构造方法的参数,index用于定义参数的位置(从0开始),ref指定某个实例的应用(指定对BeanFactory其他bean的引用关系)。如果两个或多个构造函数的参数是相同的类型,则唯一的选择是使用index特性来标识每一个< constructor-arg>元素对应的构造函数参数。
//applicationContext.xml中的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 如何配置一个bean,将指定类配置给Sprig,让spring来创建其对象的实列 -->
<bean id="school" class="com.spring.ioc01.School">
<property name="name" value="大学"></property></bean>
<bean id="helpspring" class="com.spring.ioc01.Student">
<!-- 为属性赋值 -->
<!-- value可以为构造方法传参 -->
<constructor-arg index="0" value="张三"/>
<constructor-arg index="1" value="12"/>
<constructor-arg index="2" ref="school"/>
</bean>
</beans>
@Test
public void test02() {
// String name="jiayou";
//使用spring的配置文件来创建相应的实列来使用
//spring容器初始化,加载applicationContext.xml文件
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取配置中的hellospring(id)的实列
Student hello=(Student) ctx.getBean("helpspring");
System.out.println(hello);}}
//赋值是在xml中。通过spring容器获取实例的对象!
//运行的结果:Student [name=张三, member=12]
Bean的配置
…Spring容器创建或管理的应用对象称为bean。在Spring框架的术语中,一个元素代表一个bean定义。
元素的常用属性:
属性的名称 | 描述 |
---|---|
id | 指定bean的唯一名称 |
class | 指定bean的完全限定名 |
name | 指定bean的别名,与id差不多,差别在于可以使用的字符类型不同 |
scope | 指定Bean实例的作用域 |
Bean的作用域
在Bean的作用域中,singleton和prototype是最常用的两种
1)singleton作用域
…当Spring中一个bean的作用域为singleton时,那么Spring IoC容器中只会存在一个共享的该bean的实列,并且所有对该bean的引用,只要id与bean定义相匹配,则只会返回bean的单一实例。而singleton是scope的默认方式,因此有两种方式进行设置:
<bean id="helpspring" class="com.spring.ioc01.Student"></bean>
<bean id="helpspring" class="com.spring.ioc01.Student" scope="singleton"></bean>
在此作用域下,Spring能精确地知Bean何时被创建,何时初始化完成,以及何时被销毁。
2)prototype作用域
当将bean的scope设置为prototype时,Spring IoC容器将为每次请求创建一个新的实列。
<bean id="helpspring" class="com.spring.ioc01.Student" scope="prototype"></bean>
在此作用域下的bean,Spring只负责创建,当容器创建bean的实列后,容器将实例对象的生命周期的管理工作交给请求方之后,就不再拥有当前返回对象的引用,容器将实例对象的生命周期的管理工作交给请求方负责。▲对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用。(这句话自己现在还没有很理解,先记录下来)
Bean的生命周期
…BeanFactory中bean的生命周期分为实例化、初始化、使用和销毁四个阶段。
Bean的实例化
Spring容器有三种方法来管理返回的对象实例。
1)构造方法实例化
Spring容器可以调用Bean对应类中的无参数构造来实例化Bean
public class BeanClass {
public String message;
public BeanClass() {
message="构造方法实例化";
}
}
//在applicationcontext.xml中的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="factory" class="com.spring.ioc02.BeanClass">
</bean>
</beans>
@Test
public void test01() {
///使用spring的配置文件来创建相应的实列来使用
//spring容器初始化,加载applicationContext.xml文件
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取配置中的hellospring(id)的实列
BeanClass hello=(BeanClass) ctx.getBean("factory");
System.out.println(hello.message);
//赋值是在xml中。通过spring容器获取实例的对象!
}
}
//运行的结果:构造方法实例化
2)静态工厂实例化
…在配置Bean时,class属性指定静态工厂类,同时还需要使用factory-method来指定工厂类中的静态方法(不用创建对象)
//创建一个staticfactory 类
public class staticfactory {
public static BeanClass sfactory =new BeanClass("使用静态工厂");
public static BeanClass creatfactory() {
return sfactory; }}
//再创建一个BeanClass类
public class BeanClass(){
public String message;
public BeanClass(String message){
this.message=message;
}
}
<bean id="factory" class="com.spring.ioc02.staticfactory" factory-method="creatfactory"/>
//因为是使用的静态工厂进行实例化,因此不用创建对象
public void test02(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
BeanClass beanf=(BeanClass) ctx.getBean("factory");
System.out.println(beanf.message);
//运行的结果:使用静态工厂
}
3)实例工厂实例化
…使用factory-bean属性指定配置的实例工厂,同时还需要使用factory-method指定实例工厂中的实例方法
创建一个Beanfactory类
public class Beanfactory(){
public BeanClass create =new BeanClass("实例化");
public BeanClass createBeanfactory(){
return create;
}}
▲在applicationcontext.xml文件中,静态工厂与实例化工厂有很大的区别。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置工厂 -->
<bean id="myfactory" class="com.spring.ioc03.Beanfactory"/>
<!-- 使用factory-bean属性指定配置工厂 ,使用factory-method属性指定使用工厂中的哪一个方法实例化bean -->
<bean id="factory" factory-bean="myfactory" factory-method="createBeanfactory"></bean>
</beans>
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//▲注意这里获取配置中的id是哪一个bean中的
BeanClass hello=(BeanClass) ctx.getBean("factory");
System.out.println(hello.message);
//运行结果:实例化
Bean的初始化
…在bean被实例化的过程中,容器会按照JavaBean的定义初始化bean的所有属性和依赖关系。具体初始化步骤:
(1)在bean的定义中,如果< bean>标签使用了autowire属性,Spring会对bean完成自动装配。
(2)通过get()和set()方法配置bean的属性。
(3)如果bean实现了BeanNameAware接口,容器将会调用bean的setBeanName()方法来传递Bean的ID。
(4)同样,如果bean实现BeanFactoryAware接口,容器将会调用bean的setBeanFactory()方法将容器本身注入JavaBean中。
(5)如果在容器中注册了BeanPostProcessor接口的实现类,将调用这个实现类的postProcessBeforeInitialization()方法,完成bean的预处理方法。
(6)如果bean实现了InitialzingBean接口,容器会调用JavaBean的afterPropertiesSet()方法修改JavaBean的属性
(7)在XML中配置bean时,如果用init-method属性指定了初始化方法,那么容器会执行指定的方法来设置属性。
(8)最后,容器中如果注册了BeanPostProcessor的实现类,将调用实现类的postProcessAfternitialization()方法完成bean的后期处理方法。
Bean的销毁
…当关闭容器时,容器会销毁所有bean,如果bean定制了特殊的销毁方法,容器会在销毁该bean之前调用这个方法完成资源回收等操作。
对于销毁方法的执行,有两个条件:(1)当前的Bean需要时singleton的(2)要手工关闭容器