一、 Spring框架概述
Spring是分层的JavaSE/EE full-stack (一站式) 轻量级开源框架它的出现,就是为了解决 JavaEE 企业级开发的实际问题(取代了ejb),框架内部提供JavaEE开发各层解决方案。Spring以IoC(反转控制) 和AOP(面向切面编程)为核心
Spring包含Spring core(核心)、Spring security (安全)、Spring webflow (工作流)、Spring Andriod (整 合Andriod)等等。
Spring 的好处
*方便解耦,简化开发
Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
*AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
*声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
*方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
*方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、 Quartz等)的直接支持
*降低JavaEE API的使用难度
Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
Spring体系结构
test模块:非常方便集成junit 进行测试
CoreContainer 核心容器: Beans 、 Core、Context 、Expression 最基本的东西(实现IoC )
AOP面向切面编程:AOP 、Aspects
DataAccess数据访问/ integration 集成:Spring本身提供数据访问技术,同时支持各种优秀持久化框架集合(Hibernate、MyBatis)
web模块:Spring 本身提供 Spring MVC 框架, 同时支持集成 Struts2
二、 Spring Ioc 控制反转入门案例
1、 下载开发包
Spring 最新版本 3.2.2 课程以3.2 进行学习 ----- 下载dist 开发包
* 关于spring-framework-3.0.2.RELEASE-dependencies.zip(依赖包)
Spring在3.0 时,提供 dependencies 依赖包,里面存放了所有常用开源技术的jar包,3.0之后就没有提供依赖包了,由于常用的开源技术jar经常更新,所以维护起来很麻烦。
Spring 解压目录
docs文档(规范和javadoc)
libsjar包
schema开发过程中配置文件需要导入约束
2、 将开发jar包导入web project
最基本jar : spring-beans 、spring-core 、spring-context 、 spring-expression
spring开发依赖 apache commons-logging 日志,导入common-logging的jar
整合log4j导入log4j的jar(在src 配置log4j.properties)
3、 编写反转控制入门程序
IoC(Inverse of Control反转控制):就是将原本在程序中手动创建HelloService对象的控制权,交由Spring框架管理,简单说,就是创建HelloService对象控制 权被反转到了Spring框架。
在src 创建 applicationContext.xml
导入约束
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
<beanid="helloService "class="cn.itcast.spring.quickstart.HelloService"></bean>
程序中:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
IHelloServicehelloService2 = (IHelloService) applicationContext.getBean ("helloService");
helloService2.sayHello();
DI(Dependency Injection依赖注入)
必须要先理解什么是依赖 (一个对象,可以依赖另一个对象,依赖表现在方法参数上)
例:class A {
void setName(String name){
// 就可以说 A 对象依赖 String 类型参数
}
void setB(B b){
//就可以说 A 对象 依赖 B 类型参数
}
}
依赖与程序变量无关,只和方法有关
使用Spring Ioc 将对象 创建权交给Spring, Spring在创建对象时,将依赖对象注入给目标对象
例:
<beanid="helloService" class="cn.itcast.spring.quickstart.HelloService">
<propertyname="name "value="itcast"></property>
</bean>
4、 关于Spring 配置文件读取
*Spring 框架默认配置文件,建议命名为 applicationContext.xml
*编写配置文件,默认位置有两个 src目录 、WEB-INF目录
*读取配置文件有两种方式:
加载classpath:加载的是src下的配置文件
newClassPathXmlApplicationContext("applicationContext.xml");
加载磁盘路径:加载的是WebRoot根目录下的配置文件
newFileSystemXmlApplicationContext("applicationContext.xml");
三、 BeanFactory 接口与ApplicationContext接口区别
1、ApplicationContext 是 BeanFactory 的一个子接口
2、BeanFactory 是Spring 核心工厂接口,加载Bean 采用延迟加载,使用getBean时,才会创建 Bean 的实例,ApplicationContext为立即加载。
3、ApplicationContext 接口提供了额外功能
*国际化处理
*自动装配
*事件传递
*各种不同应用层的Context实现
注:在实际开发中,通常使用 ApplicationContext 接口
四、 Ioc 容器装配Bean (xml 配置)
1、 Spring管理Bean ,实例化Bean对象有三种方式
第一种 使用默认构造器(无参构造函数)
<beanid="bean1"class="cn.itcast.spring.initbean.Bean1"></bean>
第二种 静态工厂方法
publicclass Bean2Factory {
public static Bean2 getBean2() {
return new Bean2();
}
}
配置文件中
<beanid="bean2" class="cn.itcast.spring.initbean.Bean2Factory "factory-method ="getBean2" />
第三种 实例工厂方法
配置文件中需要两步完成
<beanid="bean3factory" class="cn.itcast.spring.initbean.Bean3Factory "></bean>
<beanid="bean3" factory-bean ="bean3factory" factory-method ="getBean3"></bean>
实例工厂
publicclass Bean3Factory {
publicBean3 getBean3() {
returnnew Bean3();
}
}
2、 Bean的id 属性和 name 属性
在使用Spring 配置Bean
<beanid="helloService" class=".....HelloService" />
<beanname="helloService" class="....HelloSerivce" />
注:在配置Bean过程中 id属性和 name属性都行,都可以通过applicationContext.getBean(id/name)来获得一个Bean实例
区别:配置id 必须唯一,通常不含有特殊字符, 比如以/开始,以数字开始
配置name 属性,不必须唯一, 可以含有特殊字符
应用:
比如 struts1 整合 spring 需要将 请求路径 配置到spring 中
<beanid="/login" class="..... UserAction" /> ------ 在早期Spring版本 是报错的
<beanname="/login" class="..... UserAction" /> ------ 以前整合都是这样写的
3、 Bean的作用域
在配置 <bean> 元素时, 通过 scope 属性 指定 Bean的作用域
singleton: 代表Bean 在整个Spring 容器环境中是单例的(每次获得的bean对象都是同一个对象)
prototype: 多例(原型模式),在一个Spring 容器中,每次使用Bean 都会返回一个新的实例
request: 相当于 构造对象,保存request数据范围 (request.setAttribute())
session: 相当于 构造对象,保存session数据范围 (session.setAttribute()) 以后再次使用,同一个
Session无需构造
globalsession:主要用于单点登录。
注:在实际开发中只需要掌握 singleton(默认)和 prototype 就可以了
4、 Bean 生命周期
在配置<bean>时,可以通过 init-method和destroy-method定义Bean的初始化和销毁的方法
例:
<bean id="product"class="cn.itcast.spring.lifecycle.Product"init-method="myinit"destroy-method="mydestroy"></bean>
publicclass Product {
publicProduct() {
System.out.println("执行 Product的 构造 ...");
}
初始化方法
publicvoid myinit() {
System.out.println("Product对象初始化....");
}
销毁方法
publicvoid mydestroy() {
System.out.println("Product对象销毁....");
}
}
调用bean
publicvoid demo1() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Productproduct = (Product) applicationContext.getBean("product");
System.out.println(product);
//如果销毁 Spring手动调用 close方法
applicationContext.close();
}
问题:在构造函数的时候没有初始化吗?为什么还要有init?
答:java语言不建议在构造器 编写复杂处理逻辑,通常在构造器中只会给成员变量赋值。
完整Bean的生命周期
1) instantiate bean对象实例化(构造函数执行)
2) populate properties 封装属性(属性的依赖注入)
3) 如果Bean实现BeanNameAware覆盖了setBeanName方法
(Spring就会将 <bean> 配置中的id属性的值返回)
4) 如果Bean实现BeanFactoryAware或者 ApplicationContextAware设置工厂 setBeanFactory 或者上 下文对象 setApplicationContext
(Spring就会将Spring 应用上下文ApplicationContext注入给 Bean)
作用:通过ApplicationContext对象可以操作其它Bean
注:3和4步是为了让Bean了解Spring 容器
5) 如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
Bean的后处理器:如果一个类实现了 BeanPostProcessor接口,该类成为Bean的后处理器
作用:后处理Bean可以对已经创建的Bean对象进行代理增强
BeanPostProcessor接口在spring的程序代码中就是一个“钩子”,在这个接口中设置了两个方法,让使 用spring的人进行实现,通过实现接口并覆盖方法来对bean进行增强。
实现了BeanPostProcessor的类叫做后处理bean,这个bean也要配置。配置的时候不需要写id,因为是对每个bean都有效的。
6) 如果Bean实现InitializingBean 就会覆盖afterPropertiesSet (属性封装完成)
7) 调用<bean init-method="init"> 指定初始化方法 init(bean中自定义的初始化方法)
8) 如果存在类实现BeanPostProcessor(后处理Bean),会执行另一方法postProcessAfterInitialization
9) 执行业务处理(自己写的方法)
10)如果Bean实现 DisposableBean 执行destroy(释放资源方法无需配置)
11)调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy(配置文件中配置 自定义的方法进行资源的释放)
Bean属性的依赖注入
1)构造函数属性注入
publicclass Car {
privateString name;
privateString color;
publicCar(String name, String color) {
super();
this.name = name;
this.color= color;
}
}
<beanid="car" class="cn.itcast.spring.di.Car">
<!--构造函数注入 通过constructor-arg标签 -->
<!--通过索引和类型,指定注入参数位置 -->
<constructor-argindex="0 "type="java.lang.String" value="宝马"></constructor-arg>
<constructor-argindex="1"type="java.lang.String" value="红色"></constructor-arg>
</bean>
2) setter 方法注入
publicclass Car2 {
privateString name;
privateString color;
publicvoid setName(String name) {
this.name= name;
}
publicvoid setColor(String color) {
this.color= color;
}
}
<beanid="car2" class="cn.itcast.spring.di.Car2">
<!--setter 方法注入 ,根据setter 方法编写注入属性 -->
<propertyname="name" value="保时捷"></property>
<propertyname="color" value="黑色"></property>
</bean>
注入一个复杂类型,通过<property>的ref属性 引用其他Bean
<beanid="employee" class="cn.itcast.spring.di.Employee">
<propertyname="name" value="小丽"></property>
<!--ref 引用另一个Bean -->
<propertyname="car2" ref="car2"></property>
</bean>
3) p名称空间的使用
从spring2.5 版本以后,为了简化 bean属性注入 写法,引入 p名称空间
语法格式:p:<属性名>="xxx" 引入常量值
p:<属性名>-ref="xxx"引用其它Bean对象
注:使用p名称空间需要先引用p名称空间
"xmlns:p="http://www.springframework.org/schema/p"加入到bean元素
例:<beanid="employee" class="cn.itcast.spring.di.Employee">
<propertyname="name" value="小丽"></property>
<propertyname="car2" ref="car2"></property>
</bean>
简化为
<beanid="employee" class="cn.itcast.spring.di.Employee"p:name="小丽" p:car2-ref="car2"/>
4) SpEL (Spring Expression Language )表达式的使用
语法格式 : #{ }
用法一:向一个Bean注入另一个Bean
<property name="car2"ref="car2" /> 改写为 <propertyname="car2" value="#{car2}" />
用法二:使用另一个Bean属性为当前Bean属性赋值
<beanid="carinfo"class="cn.itcast.spring.di.CarInfo"></bean>
<beanid="car3" class="cn.itcast.spring.di.Car2">
car3的name值,调用 carinfo对象 getName() 方法获取值
<propertyname="name" value="#{carinfo.name}"></property>
</bean>
用法三:使用另一个Bean方法,为当前Bean属性赋值
<beanid="carinfo"class="cn.itcast.spring.di.CarInfo"></bean>
<beanid="car3" class="cn.itcast.spring.di.Car2">
<propertyname="name" value="#{carinfo.name}"></property>
car3的color值,由carinfo对象指定的 initColor方法提供的,默认是找getxxx方法
<propertyname="color" value="#{carinfo.initColor()}"></property>
</bean>
用法四:读取properties文件的值
向一个Bean对象 ,注入集合类型的属性
List、Set 、 Map 、Properties
例:<beanid="collectionBean"class="cn.itcast.spring.di.CollectionBean">
<!--注入list基本数据类型-->
<propertyname="hobbies">
<list>
<value>体育</value>
<value>爬山</value>
</list>
</property>
<!--注入 Set复杂数据类型-->
<propertyname="cars">
<set>
<refbean="car2"/>
<refbean="car3"/>
</set>
</property>
<!--注入Map -->
<propertyname="webSiteVisitMap">
<map>
<entry key="传智播客" value="100"></entry>
<entry key="黑马程序员" value="110"></entry>
</map>
</property>
<!--注入property -->
<propertyname="employees">
<props>
<prop key="张三">传智播客</prop>
<prop key="李四">黑马程序员</prop>
</props>
</property>
</bean>
Spring 配置文件分离
第一种:同时加载多个配置文件,这些配置文件并列关系
例:new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
第二种:主配置文件是applicationContext.xml,在主配置文件中引入子配置文件 bean1.xmlbean2.xml 例:newClassPathXmlApplicationContext("applicationContext.xml");
在applicationContext.xml 中
<importresource="classpath:bean1.xml"/>
<importresource="classpath:bean2.xml"/>
在开发中主要用第二种