一、HelloWorld程序示例
导入基础Spring包:
commons-logging
spring-beans
spring-context
spring-core
spring-expression
2. 创建HelloWorld.java
package me.ziry.helloworld; public class HelloWorld { private String name; public String getName() { System.out.println("get Name = " + name); return name; } public void setName(String name) { System.out.println("set Name = " + name); this.name = name; } public HelloWorld() { System.out.println("HelloWorld initialize..."); } public void sayHello() { System.out.println("hello : " + name); } }
3. 在src下创建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="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="name" value="spring"/> </bean> </beans>
4.创建测试类(Main.java)进行测试
package me.ziry.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import me.ziry.helloworld.HelloWorld; public class Main { public static void main(String[] args) { /* * 传统获取Bean方式 HelloWorld helloworld = new HelloWorld(); helloworld.setName("ziry"); */ /* Spring方式 */ //1.创建Spring的IOC容器 ApplicationContext acx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从容器中获取Bean HelloWorld helloworld = (HelloWorld)acx.getBean("helloWorld"); //3.调用方法 helloworld.sayHello(); } }
二、Spring容器
Spring 提供了两种类型的 IOC 容器实现.
1.BeanFactory: IOC 容器的基本实现.
2.ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
ApplicationContext 面向使用 Spring 框架的开发者,
几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
无论使用何种方式, 配置文件时相同的.
ApplicationContext 的主要实现类:
ClassPathXmlApplicationContext:从 类路径下加载配置文件
//1.创建Spring的IOC容器 ApplicationContext acx = new ClassPathXmlApplicationContext("applicationContext.xml");
2.FileSystemXmlApplicationContext: 从文件系统中加载配置文件
//1.创建Spring的IOC容器 ApplicationContext acx = new FileSystemXmlApplicationContext("D://applicationContext.xml");
ConfigurableApplicationContext 扩展于 ApplicationContext,
新增加两个主要方法:refresh() 和 close(),
让 ApplicationContext 具有启动、刷新和关闭上下文的能力
ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。
WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作
三、依赖注入的方式
Spring 支持 3 种依赖注入的方式
1. 属性注入
● 属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
● 属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值
属性注入是实际应用中最常用的注入方式
HelloWorld.java
package me.ziry.helloworld; public class HelloWorld { private String name; private Integer age; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } }
applicationContext.xml:
<bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="name" value="ziry"/> <property name="age"> <value>24</value> </property> </bean>
2. 构造器注入
● 通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
● 构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性
HelloWorld.java
public class HelloWorld { private String name; private int age; private double height; private List<Cpu> cpuList; private Map<String,String> cpuMap; private Properties properties;//配置文件类 public HelloWorld(String name, int age, double height) { this.name = name; this.age = age; his.height = height; } //....此处省略get,set方法 }
applicationContext.xml:
<!--方式1--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <constructor-arg name="name" value="ziry"></constructor-arg> <constructor-arg name="age" value="24"></constructor-arg> <constructor-arg name="height" value="1.7"></constructor-arg> </bean> <!--方式2--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <constructor-arg value="ziry" index="0"></constructor-arg> <constructor-arg value="24" index="1"></constructor-arg> <constructor-arg value="1.7" index="2"></constructor-arg> </bean> <!--方式3--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <constructor-arg value="ziry" type="java.lang.String"/> <constructor-arg value="24" type="int"></constructor-arg> <constructor-arg value="1.7" type="double"></constructor-arg> </bean> <!--方式4--> <bean id="myString" class="java.lang.String" > <constructor-arg value="myStrings"/> </bean> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <constructor-arg ref="myString" /> <constructor-arg value="24" type="int"></constructor-arg> <constructor-arg value="1.7" type="double"></constructor-arg> </bean> <!--方式5: 内部Bean--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="cpu"> <bean class="me.ziry.helloworld.Cpu"> <property name="name" value="amd" /> </bean> </property> </bean> <!--方式6: 赋NULL值--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="cpu"><null /></property> </bean> <!--方式7: 级联方式赋值--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <!-- 需要先创建,再赋值 --> <property name="cpu"> <bean class="me.ziry.helloworld.Cpu" /> </property> <property name="cpu.name" value="AMD"/> </bean> <!--方式8: 赋值集合List;Set类似--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="cpuList"> <list > <bean class="me.ziry.helloworld.Cpu" > <property name="name" value="cpu1" /> </bean> <bean class="me.ziry.helloworld.Cpu" > <property name="name" value="cpu2" /> </bean> <bean class="me.ziry.helloworld.Cpu" > <property name="name" value="cpu3" /> </bean> </list> </property> </bean> <!--方式9: 赋值Map--> <bean id="myString" class="java.lang.String" > <constructor-arg value="myStrings"/> </bean> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="cpuMap"> <map> <entry key="AA" value="cpuAA"/> <entry key="BB" value-ref="myString" /> </map> </property> </bean> <!--方式10: 赋值Properties类型--> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="properties"> <props> <prop key="username" >admin</prop> <prop key="password" >ziry</prop> </props> </property> </bean> <!-- 方式11: 独立集合Bean 需要引入util命名空间 xmlns:util="http://www.springframework.org/schema/util" --> <bean id="cpu" class="me.ziry.helloworld.Cpu"> <property name="name" value="cop1"/> </bean> <util:list id="cpus"> <ref bean="cpu"/> <bean class="me.ziry.helloworld.Cpu"> <property name="name" value="cop2"/> </bean> </util:list> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" > <property name="cpuList" ref="cpus" /> </bean> <!-- 方式12: 简化XML (Spring 2.5开始) 需要引入 p 命名空间 xmlns:p="http://www.springframework.org/schema/p" --> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" p:name="ziry" p:age="24" /> <!-- 方式13: 自动装配:autowire --> <!-- 缺点:在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了. autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之. --> <bean id="cpu" class="me.ziry.helloworld.Cpu"> <property name="name" value="cop1"/> </bean> <!-- byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同. --> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" p:name="ziry" p:age="24" autowire="byName" /> <!-- byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配. --> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" p:name="ziry" p:age="24" autowire="byType" />
3. 工厂方法注入(很少使用,不推荐)
三、Bean 之间的关系
1. 继承Bean
Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
子 Bean 也可以覆盖从父 Bean 继承过来的配置
父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true
<bean id="helloWorldBase" class="me.ziry.helloworld.HelloWorld" p:name="helloBase" abstract="true"/> <bean id="helloWorld" p:age="24" parent="helloWorldBase" />
2. 依赖Bean
Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好
如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称
<bean id="cpu" class="me.ziry.helloworld.Cpu" p:name="cpu1"/> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" p:name="ziry" p:age="24" depends-on="cpu" />
四、Bean的作用域
singleton(默认):在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype:一个bean定义对应多个对象实例。
request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext 情形下有效。
session:在一个HTTP Session 中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext 情形下有效。
<bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" p:name="ziry" p:age="24" scope="singleton|prototype.."/>
五、使用外部属性文件
在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离
Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量.
Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用。
applicationContext.xml
<!-- 导入属性文件 需要设置context命名空间 xmlns:context=" spring 2.5 以后简化了元素 --> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name="driverClass" value="${driverClass}" /> <property name="jdbcUrl" value="${jdbcUrl}" /> <property name="user" value="${user}" /> <property name="password" value="${password}" /> </bean>
db.properties
user=root password=123456 driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/test
六、spring语言表达式:SpEL
Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。
语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL
SpEL 为 bean 的属性进行动态赋值提供了便利
通过 SpEL 可以实现:
通过 bean 的 id 对 bean 进行引用
调用方法以及引用对象中的属性
计算表达式的值
正则表达式的匹配
字面量的表示:
<!-- 整数: --> <property name="count" value="#{5}"/> <!-- 小数: --> <property name="frequency" value="#{89.7}"/> <!-- 科学计数法: --> <property name="capacity" value="#{1e4}"/> <!-- String可以使用单引号或者双引号作为字符串的定界符号: --> <property name=“name” value="#{'Chuck'}"/> <property name='name' value='#{"Chuck"}'/> <!-- Boolean: --> <property name="enabled" value="#{false}"/>
2. 引用其他对象:
<!-- 通过value属性和SpEL配置Bean之间的应用关系 --> <property name="car" value="#{beanid}"/>
3. 引用其他对象的属性
<!-- 通过value属性和SpEL配置属性值为另一个Bean的属性值 --> <property name="carname" value="#{car.name}"/> <!-- 调用静态方法或静态属性:通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性: --> <property name="ziry" value="#{T(java.lang.Math).PI}"/>
4. 调用其他方法
<!-- 通过value属性和SpEL配置属性值为另一个Bean的方法返回值 --> <property name="carname" value="#{car.toString()}"/> <property name="carname" value="#{car.toString().toUppercase()}"/>
5. 算数运行符
<property name="ziry" value="#{ziry.age + 1}"/> <property name="ziry" value="#{ziry.age - 1}"/> <property name="ziry" value="#{T(java.lang.Math).PI * 2}"/> <property name="ziry" value="#{10/2}"/> <property name="ziry" value="#{10%2}"/> <property name="ziry" value="#{T(java.lang.Math).PI* ziry.age ^2}"/> <!-- 加号可以用作字符串连接 --> <property name="ziry" value="#{'Ziry'+'Lee'}"/> <!-- 比较运算 <,>,==,<=,>=,lt,gt,eq,le,ge --> <property name="ziry" value="#{ziry.age == 24}"/> <!-- 逻辑运算符 and,or,not,! --> <property name="ziry" value="#{ziry.age == 24 or ziry.age==25}"/> <!-- if-else运算符 --> <property name="ziry" value="#{ziry.age == 0 ? 24 : ziry.age}"/> <!-- 正则表达式:matches --> <property name="ziry" value="#{ziry.email matches '[*]+@[*]'}"/>
七、IOC 容器中 Bean 的生命周期方法
Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.
Spring IOC 容器对 Bean 的生命周期进行管理的过程:
--通过构造器或工厂方法创建 Bean 实例
--为Bean 的属性设置值和对其他 Bean 的引用
--调用 Bean 的初始化方法
--Bean 可以使用了
--当容器关闭时, 调用 Bean 的销毁方法
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.
<!-- 方法名可自定 --> <bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" init-method="init" destroy-method="destroy" />
八、Bean 后置处理器
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
对Bean 后置处理器而言, 需要实现orgspringframework.beans.factory.config.BeanPostProcessor接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
过程:
通过构造器或工厂方法创建 Bean 实例
为 Bean 的属性设置值和对其他 Bean 的引用
将 Bean 实例传递给 Bean 前置处理器的 postProcessBeforeInitialization 方法
调用 Bean 的初始化方法
将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
Bean 可以使用了
当容器关闭时, 调用 Bean 的销毁方法
示例:
MyBeanPostProcessor.java
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException { System.out.println("postProcessAfterInitialization:"+bean+","+beanname); return bean;//这里注意需要返回bean } @Override public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException { System.out.println("postProcessBeforeInitialization:"+bean+","+beanname); return bean;//这里注意需要返回bean } }
applicationContext.xml
<bean id="helloWorld" class="me.ziry.helloworld.HelloWorld" init-method="init" destroy-method="destroy" /> <bean class="me.ziry.helloworld.MyBeanPostProcessor"/>
九、工厂方法创建Bean
通过调用静态工厂方法创建 Bean
调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节.
要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用 <constrctor-arg> 元素为该方法传递方法参数.
示例
Car.java
public class Car { private String name;//品牌名 private Integer price;//价格 public Car(String name, Integer price) { this.name = name; this.price = price; } //....此处省略get,set方法 }
applicationContext.xml
<!-- 通过调用静态工厂方法创建 Bean 配置工程方法实例 class 属性:指向静态工厂方法的名字 factory-method:指向静态工厂方法的名字 --> <bean id="car" class="me.ziry.factory.MyCarFactory" factory-method="getCarByName"> <!-- 如果工厂方法需要传入参数,用此标签设置方法参数 --> <constructor-arg value="AUDI"/> </bean>
Main.java
public static void main(String[] args) { //1.创建Spring的IOC容器 ApplicationContext acx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从容器中获取Bean Car car = (Car)acx.getBean("car"); System.out.println(car); }
2. 通过调用实例工厂方法创建 Bean
实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节.
要声明通过实例工厂方法创建的 Bean
--在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
--在 factory-method 属性里指定该工厂方法的名称
--使用 construtor-arg 元素为工厂方法传递方法参数
示例
MyCarFactory2.java
import java.util.HashMap; import java.util.Map; /** * 我的汽车工厂类 * @author Ziry */ public class MyCarFactory2 { private Map<String, Car> cars = null; public MyCarFactory2() { cars = new HashMap<String, Car>(); cars.put("AUDI", new Car("AUDI", 30000)); cars.put("BMW", new Car("BMW", 40000)); } public Car getCarByName(String name) { return cars.get(name); } }
applicationContext.xml
<!-- 配置工程实例 --> <bean id="carFactory" class="me.ziry.factory.MyCarFactory2" ></bean> <!-- 通过示例方法配置Bean --> <bean id="car2" factory-bean="carFactory" factory-method="getCarByName"> <constructor-arg value="BMW"/> </bean>
3. 实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean.
工厂 Bean 跟普通Bean不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象
示例
MyFactoryBean.java
import org.springframework.beans.factory.FactoryBean; /** * 我的Bean工厂 * @author Ziry */ public class MyFactoryBean implements FactoryBean<Car>{ private String carName; public void setCarName(String carName) { this.carName = carName; } @Override public Car getObject() throws Exception { return new Car(carName, 500000); } @Override public Class<?> getObjectType() { return Car.class; } @Override public boolean isSingleton() { return true; } }
applicationContext.xml
<!-- 通过FactoryBean来配置Bean的实例 class:指向FactoryBean的全类名 property: 配置FactoryBean 的属性 实际返回的是FactoryBean的getObject()方法返回的实例 --> <bean id="car3" class="me.ziry.factory.MyFactoryBean"> <property name="carName" value="BMW"/> </bean>
纯干货!Spring4 简单教程 共 4 篇 分别:
注意:转载请注明出处,谢谢!
注意:本文归作者所有,未经作者允许,不得转载