一、HelloWorld程序示例

  1. 导入基础Spring包:

    1. commons-logging

    2. spring-beans

    3. spring-context

    4. spring-core

    5. 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 的主要实现类:

  1. 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的作用域

  1. singleton(默认):在每个Spring IoC容器中一个bean定义对应一个对象实例。

  2. prototype:一个bean定义对应多个对象实例。

  3. request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext 情形下有效。

  4. 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 进行引用

    • 调用方法以及引用对象中的属性

    • 计算表达式的值

    • 正则表达式的匹配


  1. 字面量的表示:

<!-- 整数: -->
<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 实例分别传递给上述接口的以下两个方法:


过程:

  1. 通过构造器或工厂方法创建 Bean 实例

  2. 为 Bean 的属性设置值和对其他 Bean 的引用

  3. 将 Bean 实例传递给 Bean 前置处理器的 postProcessBeforeInitialization 方法

  4. 调用 Bean 的初始化方法

  5. 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法

  6. Bean 可以使用了

  7. 当容器关闭时, 调用 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

  1.  通过调用静态工厂方法创建 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 篇 分别:



注意:转载请注明出处,谢谢!

注意:本文归作者所有,未经作者允许,不得转载