spring基于xml配置
spring容器
- 1、在springIOC 容器读取 Bean 配置,创建 Bean 实例之前,需要先对spring 容器进行实例化。只有在容器实例化之后,才可以 IOC 容器中获取 Bean 实例,并且使用。
- 2、spring提供了两种类型的springIOC容器实现。
- BeanFactory: IOC容器的底层实现。
- ApplicationContext: 提供了更多得高级特性,是BeanFactory的子接口。
- BeanFactory是Spring框架的基础设施,面向spring本身。ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都是使用ApplicationContext,而不是BeanFactory.
- 无论使用何种方式,配置文件都相同。
- 3、spring容器接口ApplicationContext
- ConfigurableApplicationContext 扩展于 ApplicationContext, 新增两个主要方法:refresh(),close(),让ApplicationContext具有启动,刷新和关闭上下文的能力。
- ClassPathXmlApplicationContext: 实现 ConfigurableApplicationContext接口,从类路径下加载配置文件。
- FileSystemXmlApplicationContext:实现 ConfigurableApplicationContext接口,从文件系统中加载配置文件。
- ApplicationContext 在初始化上下文时就实例化所有单例的Bean。
- WebApplicationContext 是专门为Web应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
# 1.创建iOC容器,并且读取配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
# 2.从容器中获取bean
HelloWorld helloWorld = (HelloWorld) applicationContext.getBean("helloworld");
# 3.获取bean的属性
helloWorld.hello();
关于xml中的文件头
- xmlns : 表示默认的命名空间,对于默认的namespace中的元素,可以不使用前缀。
- xmlns:xsi : 表示使用xsi作为前缀的命名空间,前缀xsi需要在文档中声明。
- xsi:schemaLocation : 表示是namespace为xxx的schemaLocation属性。它定义了xml Namespace和对应的XSD(xml schema Defination)文档的位置的关系。由多个URI组成,由空格或者换行分隔。第一个URI是定义xml Namespace的值,第二个URI给出schema文档的位置,schema处理器将从这个位置读取schema文档,该文档的targetNamespace必须与第一个URI相匹配。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
一、配置Bean,以及从spring容器中获取Bean
- 1、在xml中配置bean。
# 一个 <bean> 标签就表示一个bean对象,至少要含有id,class属性。
# id 表示 bean 对象的名称。 class 表示 bean 的类型。
<bean id="xxx" class="xxxxx"></bean>
- 2、根据 id 获取 bean。
#在容器中,通过 id 获取 bean。
Object bean = contex.getBean("id");
- 3、 根据 class 获取 bean。
#在容器中,通过 class 获取 bean。
#通过 class 类型获取 bean ,需要保证 IOC 容器中,该类型实例只存在一个。
Object bean = context.getBean("Hello.class");
二、注入Bean属性
- 1、通过构造方法配置 bean 的属性。
#<constructor-arg> 标签来设置构造器注入
#value属性: 表示基础类型/string注入。
#ref属性: 表示对象类型注入。
#index属性: 表示参数的索引位置。
#type属性: 表示参数的类型.
<bean id="car" class="com.mz.Car">
#<constructor-arg></constructor-arg>标签进行构造器方法注入
<constructor-arg value="BYD" index="0" type="float"></constructor-arg>
<constructor-arg value="1200" index="1" type="java.lang.String"></constructor-arg>
</bean>
- 2、通过 setter 方法配置 bean 的属性。
#<property>标签来设置 setter 方法注入。
#使用 <ref> 标签或者 ref 属性进行注入属性对象。
<bean id="person" class="com.mz.Person">
<property name="name" value="meng"></property>
<property name="age" value="20"></property>
<property name="car" ref="car"></property>
</bean>
- 3、关于字面值,以及特殊字符的注入 value属性
- 字面值:可以用字符串表示的值,可以通过 标签或者 value 属性进行注入。
- 基本数据类型及其封装类, String 等类型都可以采取字面值注入方式。
- 若字面值中包含特殊字符,可以使用 <![CDATA[]]> 把字面值包裹起来 。
<bean id="car1" class="com.mz.Car">
<property name="name">
<value><![CDATA[shanghai&&]]></value>
</property>
<property name="price" value="22000.3"></property>
</bean>
- 4、关于对象类型的值的注入 ref属性
#使用 <ref> 标签或者 ref 属性进行注入属性对象。
<bean id="person" class="com.mz.Person">
<property name="name" value="meng"></property>
<property name="car" ref="car"></property>
</bean>
三、内置Bean
- 内置Bean:即在中定义的bean。
- 内置Bean,即使写有id属性,依然无法被外部bean所引用。
<bean id="person" class="com.mz.Person">
<property name="name">
<value>meng</value>
</property>
<property name="age" value="24"></property>
<property name="car" >
<bean id="car" class="com.mz.Car">
<property name="name" value="audi"></property>
<property name="price" value="30000"></property>
</bean>
</property>
</bean>
四、 级联属性赋值
- 级联属性赋值:为成员属性对象的成员属性赋值。
- 注意:属性需要先创建后才可以为可以为级联属性赋值。
<bean id="person" class="com.mz.Person">
<property name="name" value="meng"></property>
<property name="age" value="20"></property>
<property name="car" ref="car"></property>
<!--级联属性赋值: 为属性对象的成员属性赋值。注意:属性需要先初始化后才可以为级联属性赋值。-->
<property name="car.price" value="2000"></property>
</bean>
五、集合属性赋值
- 基础类型/string类型的属性注入使用 value 属性或者 标签。
- 对象类型的属性注入使用 ref 属性或者标签。
- 关于集合属性有: 数组,List,Set; Map; Properties;
数组,List,Set 集合属性注入
数组,List,Set 作为属性参数时,SpringIOC中配置都是用标签。
- 格式
<property name="car">
<list>
<ref bean = "xxx" />
<ref bean = "xxx" />
</list>
</property>
- 举例
@Data
public class Person {
private String name;
private Integer age;
private List carList;
}
#xml配置
<bean id="person" class="com.mz.Person">
<property name="name" value="meng"></property>
<property name="age" value="24"></property>
<property name="carList">
<list>
<ref bean="car"/>
<ref bean="car1" />
</list>
</property>
</bean>
Map 集合属性注入
- 使用
- 也可以使用
<bean id="person" class="com.mz.Person">
<property name="name" value="meng"></property>
<property name="age" value="24"></property>
<property name="carMap">
<map>
<entry key="car1" value-ref="car1"></entry>
<entry key="car2">
<ref bean="car"></ref>
</entry>
</map>
</property>
</bean>
Properties 集合属性注入
- properties类型,继承自HashTable,继承于Map接口。
- 使用标签来定义j’a’va.util.properties,该标签使用作为子标签。每个中都必须定义key属性。
- properties的特征是: key,value都是基础类型/string。
<bean id="person" class="com.mz.Person">
<property name="name">
<value>meng</value>
</property>
<property name="age" value="24"></property>
<property name="datasource">
<props>
<prop key="user">root</prop>
<prop key="password">1234</prop>
<prop key="jdbcUrl">jdbc://mysql://test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
配置公共的集合对象,以便于其他对象的属性引用
- 使用基本的几个标签定义集合时,不能将集合作为独立的bean定义,导致其他Bean无法引用该集合,所以无法在不同Bean之间共享集合。可以使用util schema里的集合 标签定义独立的集合Bean。需要在标签中加入util schema定义。
- 配置单例的集合bean,以方便其他的bean作为属性引入,需要导入util命名空间。
<util:list id="cars">
<ref bean="car1"></ref>
<ref bean="car2"></ref>
</util:list>
六、Bean属性的自动装配
xml配置的自动装配不建议使用
-
SpringIOC容器可以自动装配Bean,需要做的仅仅是在中设置autowire属性为指定自动装配的模式即可。
Bean属性的自动装配,仅仅针对Bean的成员属性是对象类型的属性。- autowire = “byType” 是根据类型自动装配,若IOC容器中有多个与目标Bean的属性对象一致的Bean,Spring将无法判定那个Bean最适合该属性,自动装配将失效。
- autowire =”byName”是根据名称自动装配,必须将目标Bean的名称和属性名设定的完全相同。根据Bean的"id属性"和"当前Bean的setter风格的属性名"进行自动装配,若有匹配,则进行自动装配,若没有匹配的,则不自动装配。
-
Bean自动装配的缺点:
- 在Bean配置文件里面设置autowire属性进行自动装配,将会装配Bean的所有属性对象。不能单独指定某个属性。
- autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼有。
- 在实际的项目中很少使用自动装配功能,因为配置也会不清晰。
#如果配置有autowire自动装配,那么该Bean的所有对象类型的属性,都会自动进行属性装配。
<bean id="person" class="com.mz.Person" autowire="byName">
</bean>
七、P命名空间直接代替来直接为属性设置初始化的值
- 使用P命名空间,需要引入xmlns:p命名空间。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/p ">
- 在标签中,使用p:属性 来代替
<bean id="person1" class="com.mz.Person" p:name="meng" p:age="24">
<property name="carMap">
<props>
<prop key="key">value</prop>
</props>
</property>
</bean>
- 使用 p:属性名=“xxx” 设置基础类型或者字符串,或者含有特殊字符的字符串。
#特殊字符串赋值,不需要[!CDATA[<SpecialString>]]
<bean id="xxx" class="xxx" p:name="meng" p:age="24"></bean>
<bean id="xxx" class="xxx" p:name="meng^&"></bean>
- 使用 p:属性名-ref = “xxx” 来引入对象
<bean id="xxx" class="xxx" p:car-ref="car"></bean>
八、Bean的抽象和继承配置
Spring允许继承Bean的配置,被继承的Bean被称为父Bean,继承这个父Bean的Bean称为子Bean。子Bean从父Bean中继承配置,包括Bean的属性配置。并不是元素里的所有属性都会被继承。比如:autowire,abstract等。子Bean也可以覆盖父Bean继承过来的配置。父Bean可以作为配置模板,也可以作为Bean的实例。若只想把父Bean作为模板,可以设置的abstract属性为true,这样Spring将不会实例化这个Bean。也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同的属性配置,但此时abstract必须设为true。
- Bean的继承使用 parent属性
如果使用parent属性,那么子Bean会继承父Bean的所有属性配置。除了autowire,abstract。
<bean id="person" class="com.mz.Person"></bean>
<bean id="person1" class="com.mz.Person" parent="person"></bean>
- 使用parent继承其他bean的配置的同事,也可以使用同名属性来覆盖继承来的bean属性。
<bean id="person2" parent="person" p:name="meng1" p:age="23"></bean>
- 对于父类Bean,可以使用abstract属性来设置其是一个抽象bean。如果abstract=true,则SpringIOC容器不会创建该bean。则该父类bean,仅仅当做一个模板来使用。
使用bean的abstract来表明这个bean是个模板,只能被继承使用。同时父bean是可以省略class不写的。
<bean id="person10" class="com.mz.Person" abstract="true" p:name="meng10" p:age="188" p:car-ref="car"></bean>
<bean id="person100" parent="person10"></bean>
九、Bean的作用域
- Bean能设置的作用域 Scope属性
- singleton 单例:
默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean,单例的。
<bean id="xxx" class="xxx" scope="singleton"></bean>
- prototype 原型 :
原型的,容器初始化的时候后不创建这种scope的bean,而是每次请求的时候创建一个新的Bean,并返回。
<bean id="xxx" class="xxxx" scope="prototype"></bean>
- singleton 单例:
十、外部属性文件配置properties的value
- 在配置文件里配置Bean时,有时需要在Bean的配置里面混入系统部署的细节信息(文件路径,数据库配置信息等)。而这些部署细节实际上需要和Bean配置分离。Spring提供了一个PropertyPlaceHolderConfigure的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到"属性文件"中,可以在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量。
- Spring还允许在属性文件中使用${propName},以实现属性之间的相互引用。Spring2.5之后,可通过context:property-placeholder元素简化.
- 在中添加context Schema定义。
- 在配置文件中加入配置:<context:property-placeholder location=“classpath:xxx.properties” />
#没有使用外部配置文件的xml配置
<bean id="datasource" class="com.mz.DataSource">
<property name="user" value="root"></property>
<property name="password" value="123.com"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
</bean>
#使用xxx.properties外部文件引入属性配置
<context:property-placeholder location="classpath:Datasource.properties" />
<bean id="dataSource1" class="com.mz.DataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="driverClass" value="${driverClass}"></property>
</bean>
#xxx.properties文件中内容
user=meng
password=123.com
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/
十一、IOC容器中Bean的声明周期方法
- SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean的生命周期的特定点执行定制的任务。SpringIOC容器对Bean的生命周期进行管理的工程如下:
- 1、通过构造器或者工厂方法创建Bean实例。
- 2、为Bean的属性设置值,以及其他Bean的引用。
- 3、调用Bean的初始化方法。(通过的init-method属性设置初始化方法。)
- 4、Bean对象的获取,以及Bean对象的方法调用。
- 5、当容器关闭时,调用Bean的销毁方法。(通过的destroy-method属性设置销毁方法。)
# xml中的设置
<bean id="car" class="com.mz.Car" init-method="init" destroy-method="destroy">
<property name="name" value="BWM"></property>
<property name="price" value="2000"></property>
</bean>
# javabean对象
public class Car {
public void init(){
System.out.println("开始创建");
}
public void destroy(){
System.out.println("开始销毁");
}
}
十二、创建Bean的后置管理器 BeanPostProcessor接口
- Bean后置管理器允许在调用"初始化方法前后"对Bean进行额外的处理。
- Bean后置管理器对SpringIOC容器里的所有Bean实例进行逐一处理,而非仅仅是针对某个实例。
- 对Bean后置处理器而言,需要实现Interface BeanPostProcessor接口,在初始化方法被调用前后。Spring将每个Bean实例分别递给上述接口的一下两个方法:
- (1) Object postProcessAfterInitialization( Object bean, String beanName );
- (2) Object postProcessBeforeInitialization( Object bean, String beanName );
- 加入Bean后置管理器之后的声明周期:
- (1) 通过构造器或者工厂方法创建Bean实例。
- (2) 为Bean的属性设置值,以及其他Bean的引用。
- (3) 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法。
- (4) 调用Bean的初始化方法。 #init-method属性
- (5) 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法。
- (6) Bean对象的获取,以及Bean对象方法的调用。
- (7) 当容器关闭时,调用Bean的销毁方法。 #destroy-method属性。
BeanPostProcessor后置管理器使用场景:
- 对bean对象的检查,替换;
- 对Bean对象属性的检查,替换;
# xml中的配置
# 配置BeanPostProcessor对象,不需要id,SpringIOC能自动识别,并且启动对象创建的后置管理。
<bean class="com.mz.MyBeanPostProcessor" ></bean>
# java实现BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {
//before方法,在init-method方法调用之前调用。
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("before:"+o + " : "+s);
if ( s.endsWith("car") ){
Car car = (Car) o;
car.setName("benz");
car.setPrice(1000.0);
}
return o;
}
//after方法,在init-method方法调用之后调用。
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("after:"+o + " : "+s);
return o;
}
}
十三、通过工厂方法配置bean
通过静态工厂方法来配置bean
# 通过静态工厂方法来配置bean.注意不是配置静态工厂方法实例,而是配置 bean 实例。
# id属性: 指静态工厂方法配置中的bean,是要获取对象的名称。(不是静态工厂方法对象的名字。)
# class属性: 指向静态工厂方法的全类名。
# factory-method: 指向静态工厂方法的名字。
# constructor-arg:如果静态工厂方法需要传入参数,则使用 constructor-org 来配置参数。((而不是静态工厂方法的构造函数。)
<bean id="car1" class="com.mz.staticCarFactory" factory-method="getCar">
#静态工厂方法获取bean,constructor-arg为工厂方法传递参数。(而不是静态工厂方法的构造函数。)
<constructor-arg value="audi"></constructor-arg>
</bean>
# java静态工厂类
# 静态工厂方法: 直接调用某一个类的静态方法就可以返回 Bean 的实例。
public class StaticCarFactory {
private static Map<String,Car> cars = new HashMap<String,Car>();
static {
cars.put("audi", new Car("audi", 100000));
cars.put("ford", new Car("ford", 200000));
}
//静态工厂方法
public static Car getCar( String name ){
return cars.get(name);
}
}
# 获取bean实例,并且使用
public static void main( String[] args ){
ApplicationContext ctx = new ClassPathXMLApplicationContext("beans-factory.xml");
Car car1 = (Car)ctx.getBean("car1");
System.out.println(car1);
}
通过实例工厂方法来配置bean
实例工厂方法: 实例工厂的方法,即需要创建工厂本身,再调用工厂的实例方法来返回 bean的实例。
# 第一步: 需要先配置工厂的实例
<bean id="car" class="com.mz.InstanceCarFactory">
</bean>
# 第二步: 通过实例工厂方法来配置bean
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="ford"></constructor-arg>
</bean>
# java实例的工厂类实现
public class InstanceCarFactory {
private Map<String,Car> cars = null;
public InstanceCarFactory(){
cars = new HashMap<String, Car>();
cars.put("audi", new Car("audi", 3000));
cars.put("ford", new Car("ford", 4000));
}
public Car getCar( String brand ){
return cars.get(brand);
}
}
# 获取bean实例,并且使用
Car car2 = (Car)ctx.getBean("car2");
Systen.out.println(car2);
十四、通过FactoryBean配置bean
配置bean的时候bean有一个属性是引用的IOC容器中的其他bean的时候,通过FactoryBean配置bean。
# xml中对FactoryBean的配置
# 通过FactoryBean来配置Bean的实例
# class : 指向FactoryBean的全类名。
# property : 配置 FactoryBean 的属性。
# 但是实例返回的实例却是 Factorybean 的 getObject() 方法返回的实例。
<bean id="car" class="com.mz.CarFactoryBean">
<Constructor-arg value="BWM"></Constructor-arg>
</bean>
# FactoryBean的实现
# 自定义的FactoryBean,需要实现FactoryBean接口。
public class CarFactoryBean implements FactoryBean<Car>{
private String brand;
public void setBrand(String brand){
this.brand = brand;
}
//返回 bean 的对象
public Car getOject() throws Exception {
return new Car(brand, 50000);
}
//返回的 bean 的类型
public Class<?> getObjectType(){
return Car.class;
}
//是否是单例
public boolean isSingleton(){
return true;
}
}
# 获取bean
ApplicationContext ctx = new ClassPathXmlApplicationContext("xxx.xml");
Car car = ctx.getBean("car");
System.out.println(car);
补充: 懒加载, 加载顺序
懒加载
- 懒加载: 只针对spring创建bean时模式为单例时存在. 被标记为懒加载的实例,在容器启动的时候,不创建该bean实例。而是在第一次使用(获取)Bean时才创建单例Bean。
- 基于xml配置的懒加载,只需要设置标签的 lazy-init属性为true即可。
<bean id="lazyBean" class="xxxx" lazy-init="true">
</bean>
setter方式的属性注入时,指定加载顺序
todo 未完成