文章目录
什么是 Spring ?
Spring 叫做 EE 开发的一站式框架。
- 一站式框架:有 EE 开发的每一层解决方案。
- Web 层:SpringMVC
- Service层:Spring 的 Bean 管理,Spring 的声明式事务
- Dao层:Spring 的 JDBC 模板,Spring 的 ORM 模块
Spring 入门(IOC)
什么是 IOC?
- IOC:Inversion of Control(控制反转)
- 控制反转:将对象的创建权交给 Spring,Spring 会帮你创建这个类的实例对象。
下载 Spring 的开发包
解压开发包
- docs:Spring 的开发规范和 API
- libs:Spring 开发 jar 包和源码
- schema:Spring 的配置文件的约束
创建一个 web 项目引入 jar 包
创建对应的接口和类
/**
* 用户管理业务层的接口
*/
public interface UserDao {
public void save();
}
/**
* 业务层实现类
*/
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl执行了!");
}
}
public class UserDaoHibernateImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoHibernateImpl执行了...");
}
}
/**
* Spring入门
*/
public class SpringDemo1 {
@Test
/**
* 传统方式的调用
* 这里相当于一个业务层,现在是UserDaoImpl类的实现,如果想变成UserHibernateImpl的实现,必须修改
* 这里的源代码
*/
public void demo1(){
UserDao userDao = new UserDaoImpl();
//UserDao userDaoHibernate = new UserDaoHibernateImpl();
userDao.save();
}
}
- 问题:如果底层的实现切换了,需要修改底层的源代码,能不能不修改底层的源代码对程序进行扩展?
对程序的扩展式开放的,对修改源代码是关闭的。当我们使用面向接口编程的时候还是会修改源代码,所以这个方法也不是最好的。这里我们使用工厂模式开解决这个问题。我们通过建立一个工厂类来管理实现类的创建工作。这样可以把在很多类中要修改的地方,变成只改一个类。最终的目的是为了只更改配置文件而不更改程序的源代码。
将实现类交给Spring管理
<?xml version="1.0" encoding="UTF-8"?>
<!--spring配置文件applicationContext.xml的约束-->
<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">
<!--Spring入门配置=================-->
<bean id="userDao" class="spring.demo1.UserDaoImpl"></bean>
</beans>
编写测试类
/**
* Spring入门
*/
public class SpringDemo1 {
@Test
/**
* 传统方式的调用
* 这里相当于一个业务层,现在是UserDaoImpl类的实现,如果想变成UserHibernateImpl的实现,必须修改
* 这里的源代码
*/
public void demo1(){
UserDao userDao = new UserDaoImpl();
//UserDao userDaoHibernate = new UserDaoHibernateImpl();
userDao.save();
}
@Test
/**
* Spring方式的调用
*/
public void demo2(){
//创建Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
}
IOC 和 DI(重点)
-
IOC:控制反转,将对象的创建权反转给了 Spring
- DI(dependency injection):依赖注入,前提必须要有 IOC 的环境,Spring 在管理这个类的时候将类的依赖的属性注入(设置)进来
-
面向对象的时候,对象和对象之间的关系:
- 依赖
有一个 A 类,一个 B 类,可能在 B 类的方法当中需要一个 A 类的对象,就说 B 依赖 A
- 依赖
Class A{
}
Class B{
public void xxx(A a){
}
}
-
继承
-
聚合
Spring 工厂类
Spring 工厂类的结构图
ApplicationContext 工厂继承了 BeanFactory,所以我们现在用的是 ApplicationContext。
BeanFactory:老版本的工厂类
- BeanFactory:调用 getBean 的时候,才会生成类的实例。
ApplicationContext:新版本的工厂类
- ApplicationContext:加载配置文件的时候,就会将 Spring 所管理的类都实例化。
- ApplicationContext 有两个实现类:
- ClassPathXmlApplicationContext:用来加载类路径下的配置文件
类路径指的就是 src 下的 - FileSystemXmlApplicationContext:用来加载文件系统下的配置文件,加载某个磁盘下的配置文件
- ClassPathXmlApplicationContext:用来加载类路径下的配置文件
Spring 的配置
XML 提示的配置
Bean 的相关配置
标签的 id 和 name 的配置
- id:使用了约束中的唯一约束,里面不能出现特殊字符
- name: 没有使用约束中的唯一约束(理论上可以出现重复的,但实际开发不能出现重复),里面可以出现特殊字符
Bean 的生命周期的配置(了解)
<!--Spring的Bean的生命周期的配置=================-->
<bean id="customerDao" class="spring.demo2.CustomerImpl" init-method="setup" destroy-method="destory"/>
- init-method:Bean 被初始化的时候执行的方法
- destory-method:Bena 被销毁的时候执行的方法(Bean 是单例创建,工厂关闭)
Bean 的作用范围的配置(重点)
- scope 属性:Bean 的作用范围
- singleton:默认的,Spring 会采用单例模式(不管有多少程序调用,只会得new一次,每一次用的都是同一个对象)创建对象
- prototype:多例模式(在 Structs2 和 Spring 整合一定会用到)
- request:应用在 web 项目中,Spring 创建这个类以后,将这个类存入到 request 范围中
- session:应用在 web 项目中,Spring 创建这个类以后,将这个类存入到 session 范围中
- globalsession:应用在 web 项目中,必须在 prolet 环境下使用
Spring 属性注入
给 Bean 中的属性设置值:
构造方法方式
public class User{
private String name;
private String password;
public User(String name, String password){
this.name = name;
this.password = password;
}
}
构造方法的方式的属性注入
<!--Spring的属性注入的方式================-->
<!--构造方法的方式-->
<bean id="car" class="spring.deomo3.Car">
<constructor-arg name="name" value="宝马"/>
<constructor-arg name="price" value="800000"/>
</bean>
set 方法方式
public class User{
private String name;
public void setName(String name){
this.name = name;
}
}
set方法的方式的属性注入
<!--set方法的方式-->
<bean id="car2" class="spring.deomo3.Car2">
<property name="name" value="奔驰"/>
<property name="price" value="1000000"/>
</bean>
<!--set方法注入对象类型的属性-->
<bean id="employee" class="spring.deomo3.Employee">
<!--value:设置普通类型的值,ref:设置其他的类的id或name-->
<property name="name" value="小明"/>
<property name="car2" ref="car2"/>
</bean>
接口注入的方式
public interface Injection{
public void setName(String name);
}
public class User implements Injection{
private String name;
public void setName(String name){
this.name = name;
}
}
Spring 当中的属性注入支持前两种
构造方法方式的属性注入
public class Car {
private String name;
private Double price;
public Car(String name, Double price) {
super();
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Car [name=" + name + ", price=" + price + "]";
}
}
/**
* @author Administrator
* 属性注入的方式
*/
public class SpringDemo4 {
@Test
public void demo1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
}
}
<!-- Spring的属性注入的方式 -->
<!-- 构造方法的方式(属性注入的一个前提是bean交给spring管理)-->
<bean id="car" class="spring.demo4.Car">
<constructor-arg name="name" value="宝马"/>
<constructor-arg name="price" value="800000"/>
</bean>
Set方法方式的属性注入
public class Car2 {
private String name;
private Double price;
public void setName(String name) {
this.name = name;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car2 [name=" + name + ", price=" + price + "]";
}
}
/**
* @author Administrator
* set方式的属性注入
*/
@Test
public void demo2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car2 car2 = (Car2) applicationContext.getBean("car2");
System.out.println(car2);
}
<!-- set方法的方式 -->
<bean id="car2" class="pring.demo4.Car2">
<property name="name" value="奔驰"/>
<property name="price" value="1000000"/>
</bean>
以上注入的属性的类型都是普通的类型,但是如果属性中有对象类型该怎么办?
public class Employee {
private String name;
private Car2 car2;
public void setName(String name) {
this.name = name;
}
public void setCar2(Car2 car2) {
this.car2 = car2;
}
@Override
public String toString() {
return "Employee [name=" + name + ", car2=" + car2 + "]";
}
}
<!-- set方法注入对象类型的属性 -->
<bean id="employee" class="spring.demo4.Employee">
<!-- value:设置普通类型的值,ref:设置其他类型的id或name -->
<property name="name" value="张三"/>
<property name="car2" ref="car2"/>
</bean>
P 名称空间的属性注入
-
通过引入 p 名称空间完成属性的注入:
写法:
普通属性:p:属性名=“值”
对象属性:p:属性名-ref=“值”
首先要引入p名称空间
-
使用 p 名称空间(Spring2.5以后的版本)
<!--改为p名称空间的方式==============-->
<bean id="car2" class="spring.deomo3.Car2" p:name="奇瑞" p:price="30000"></bean>
<bean id="employee" class="spring.deomo3.Employee" p:name="王东" p:car2-ref="car2"></bean>
SpEL 的属性注入(Spring3.0以后的版本)
- SpEL:Spring Expression Language,Spring 的表达式的语言
语法:
#{SpEL}
<!--SpEL的属性注入-->
<bean id="car2" class="spring.deomo3.Car2">
<property name="name" value="#{'三蹦子'}"></property>
<property name="price" value="#{3000}"></property>
</bean>
<bean id="employee" class="spring.deomo3.Employee">
<property name="name" value="#{'赵洪'}"></property>
<property name="car2" value="#{car2}"></property>
</bean>
在 #{SpEL} 中还可以更加灵活的使用,比如调用对象的属性,调用对象的方法,写相关表达式等等
<!--SpEL的属性注入-->
<bean id="carInfo" class="spring.deomo3.CarInfo"></bean>
<!--SpEL 中还可以调用其他类的属性或方法-->
<bean id="car2" class="spring.deomo3.Car2">
<property name="name" value="#{carInfo.name}"></property>
<property name="price" value="#{carInfo.caculatePrice()}"></property>
</bean>
<bean id="employee" class="spring.deomo3.Employee">
<property name="name" value="#{'赵洪'}"></property>
<property name="car2" value="#{car2}"></property>
</bean>
复杂数据类型的属性注入
- 数组、集合的属性注入
<!--Spring集合属性的注入===========-->
<!--注入数组类型-->
<bean id="collectionBean" class="spring.demo4.CollectionBean">
<!--数组类型-->
<property name="arrs">
<list>
<value>小明</value>
<value>小王</value>
<value>小强</value>
</list>
</property>
<!--集合类型-->
<property name="list">
<list>
<value>李冰</value>
<value>李水</value>
<value>李小水</value>
</list>
</property>
<!--注入set集合-->
<property name="set">
<set>
<value>aaa</value>
<value>bbb</value>
</set>
</property>
<property name="map">
<map>
<entry key="aaa" value="111"></entry>
<entry key="bbb" value="222"></entry>
<entry key="ccc" value="333"></entry>
</map>
</property>
</bean>
Spring 分模块开发的配置
分模块配置
在加载配置文件时候,加载多个
- 在加载配置文件的时候使用多变量参数
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
在一个配置文件中引入多个配置文件
<import resource="applicationContext2.xml"/>