目录
4.3 ApplicationContext (新版本的工厂类)
一.了解Spring
- Spring:SE/EE开发的一站式框架(有EE开发的每一层解决方案)
- WEB层 :SpringMVC
- Service层 :Spring的Bean管理,Spring声明式事务
- DAO层 :Spring的Jdbc模板,Spring的ORM模块
功能:
二.Spring入门
2.1 Spring开发包
- docs :Spring的开发规范和API
- libs :Spring的开发的jar和源码
- schema :Spring的配置文件的约束
2.2 创建项目引入jar包
在 Sping开发包中找到以下jar包并引入项目
三.IOC&DI
3.1 IOC
IOC: Inversion of Control(控制反转)。
控制反转:将对象的创建权反转给(交给)Spring。
3.1.1 IOC的主题引入
以往我们在项目中处理dao层通常用下面这种方式
/**
* 用户管理DAO层接口
*
*/
public interface UserDAO {
public void save();
}
/**
* 用户管理DAO层实现类
*
*/
public class UserDAOImpl implements UserDAO {
@Override
public void save() {
System.out.println("UserDAOImpl执行了...");
}
}
/**
* 传统方式的调用
*/
public void demo1(){
UserDAOImpl userDAO = new UserDAOImpl();
userDAO.save();
}
问题:
如果底层的实现切换了,需要修改源代码,比如说原本对数据库的操作用的是JDBC,现在要切换成Hibernate,是否可以不修改程序源代码对程序进行扩展?
3.1.2 IOC解决上述问题
① 配置XML文件,将实现类交给Spring管理
在项目的src目录下增加配置文件名为 applicationContext.xml
在spring的解压路径下spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 中最下方复制约束放入该配置文件,并在该文件中配置实现类。
<?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">
<!-- Spring的入门的配置==================== -->
<bean id="userDAO" class="com.itheima.spring.demo1.UserDAOImpl" >
</bean>
</beans>
② 编写测试方法
@Test
public void test02(){
// 创建Spring的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
3.2 DI
依赖注入,前提必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来,即在Spring实例化该类时,其中的属性也自动赋值,修改上述 UserDaoImpl实现类增加 name 属性,并设置 set 方法。
/**
* 用户管理DAO层实现类
*
*/
public class UserDAOImpl implements UserDAO {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void save() {
System.out.println("UserDAOImpl执行了..."+name);
}
}
修改配置文件加入属性
<bean id="userDAO" class="com.itheima.spring.demo1.UserDAOImpl" >
<property name="name" value="李东"/>
</bean>
重新运行上述测试类,运行结果为:
四.Spring工厂类
4.1 工厂类结构图
4.2 BeanFactory (老版本的工厂类)
特征:调用getBean的时候,才会生成类的实例
4.3 ApplicationContext (新版本的工厂类)
特征:加载配置文件的时候,就会将Spring管理的类都实例化。
ApplicationContext 有两个实现类
ClassPathXmlApplicationContext:加载类路径下的配置文件
FileSystemXmlApplicationContext:加载文件系统下的配置文件
/**
* 加载磁盘上的配置文件
*/
public void demo3(){
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\applicationContext.xml");
UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
userDAO.save();
}
五.Spring的配置
5.1 Schema本地的配置
① 设置 Key 将下面这句话填入key中
② 设置 Location解压:spring-framework-4.2.4.RELEASE-schema.zip 在beans 目录下 选择 spring-beans-4.2.xsd
③ 设置 KeyType
5.2 Bean的相关配置
5.2.1 <bean>标签的id和name的配置
- id :使用了约束中的唯一约束。里面不能出现特殊字符的。
- name :没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现的),里面可以出现特殊字符,其余 功能与id相同。应用在Spring和Struts1框架整合的时候 <bean name=”/user” class=””/>
5.2.2 Bean的生命周期的配置
- init-method :Bean被初始化的时候执行的方法
- destroy-method :Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)
案例:
① 新建接口 CustomerDao 和 CustomerDaoImpl
public interface CustomerDao {
public void save();
}
public class CustomerDaoImpl implements CustomerDao {
public void setup(){
System.out.println("CustomerDAOImpl被初始化了...");
}
@Override
public void save() {
System.out.println("CustomerDAOImpl的save方法执行了...");
}
public void destroy(){
System.out.println("CustomerDAOImpl被销毁了...");
}
}
② 在applicationContext.xml中增加如下配置
<!-- Spring的sBean的生命周期的配置=========== -->
<bean id="customerDao" class="dao.impl.CustomerDaoImpl" init-method="setup" destroy-method="destroy"/>
③ 编写测试方法
/**
* 生命周期的配置
*/
public void test03(){
ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerDao customerDAO = (CustomerDao) applicationContext.getBean("customerDao");
customerDAO.save();
applicationContext.close();
}
运行结果:
5.2.3 Bean的作用范围的配置(重点)
- scope :Bean的作用范围
- singleton :默认的,Spring会采用单例模式创建这个对象。
- prototype :多例模式。(Struts2和Spring整合一定会用到)
- request :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
- session :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。
- globalsession :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。
XML配置案例:
<!-- Spring的sBean的生命周期的配置=========== -->
<bean id="customerDao" class="dao.impl.CustomerDaoImpl" init-method="setup" destroy-method="destroy" scope="prototype" />
六.Spring中bean的管理(XML)
6.1 Spring中Bean的实例化方式
Bean已经都交给Spring管理,Spring创建这些类的时候,有几种方式:
6.1.1 无参构造方法的方式(默认)
/**
* 无参数构造方法方式
*
*/
public class Bean1 {
public Bean1() {
super();
System.out.println("Bean1的无参数的构造方法执行了...");
}
}
<!-- 无参数构造方法 -->
<bean id="bean1" class="test.Bean1"></bean>
public void test05(){
ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 b1 = (Bean1) applicationContext.getBean("bean1");
}
运行结果:
6.1.2 静态工厂实例化的方式
① 编写Bean2的静态工厂
/**
* Bean2的静态工厂
*
*/
public class Bean2Factory {
public static Bean2 createBean2(){
System.out.println("Bean2Factory中方法执行了...");
return new Bean2();
}
}
② 配置xml文件
<!-- 静态工厂实例化 -->
<bean id="bean2" class="test.Bean2Factory" factory-method="createBean2"/>
③编写测试方法
/**
* 静态工厂实例化
*/
public void demo2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
System.out.println(bean2);
}
6.1.3 实例工厂实例化的方式
① 编写Bean3的实例工厂
/**
* Bean3的实例工厂
*
*/
public class Bean3Factory {
public Bean3 createBean3(){
System.out.println("Bean3的实例工厂执行了...");
return new Bean3();
}
}
② 配置xml文件
<!-- 实例工厂实例化 -->
<bean id="bean3Factory" class="test.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>
③编写测试方法
/**
* 实例工厂实例化
*/
public void demo3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");
System.out.println(bean3);
}
6.2 Spring的属性注入
6.2.1 构造方法的方式的属性注入
①编写汽车类
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 + "]";
}
}
②配置xml文件
<!-- 构造方法的方式 -->
<bean id="car" class="demo4.Car">
<constructor-arg name="name" value="宝马"/>
<constructor-arg name="price" value="800000"/>
</bean>
③测试方法
@Test
/**
* 构造方法方式的属性注入
*/
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
}
6.2.2 set方法的方式的属性注入
①实体类
/**
* 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 + "]";
}
}
②配置xml文件
<!-- set方法的方式 -->
<bean id="car2" class="demo4.Car2">
<property name="name" value="奔驰"/>
<property name="price" value="1000000"/>
</bean>
③测试方法
/**
* set方法方式的属性注入
*/
public void demo2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car2 car2 = (Car2) applicationContext.getBean("car2");
System.out.println(car2);
}
6.2.3 set方法设置对象类型的属性
①实体类
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 + "]";
}
}
②配置xml文件
<!-- set方法注入对象类型的属性 -->
<bean id="employee" class="demo4.Employee">
<!-- value:设置普通类型的值,ref:设置其他的类的id或name -->
<property name="name" value="涛哥"/>
<property name="car2" ref="car2"/>
</bean>
<bean id="car2" class="demo4.Car2">
<property name="name" value="奔驰"/>
<property name="price" value="1000000"/>
</bean>
③测试方法
@Test
/**
* set方法注入对象类型
*/
public void demo3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Employee employee = (Employee) applicationContext.getBean("employee");
System.out.println(employee);
}
6.2.4 P名称空间的属性注入(Spring2.5以后)
在约束中加入下面这句
配置类
<!-- 改为p名称空间的方式 -->
<bean id="car2" class="demo4.Car2" p:name="奇瑞QQ" p:price="30000"></bean>
<bean id="employee" class="demo4.Employee" p:name="王东" p:car2-ref="car2"></bean>
6.2.5 SpEL的属性注入(Spring3.0以后)
SpEL:Spring Expression Language,Spring的表达式语言。
语法:#{SpEL}
编写实体类 CarInfo
public class CarInfo {
private String name;
public String getName() {
return "摩托车";
}
public Double calculatorPrice(){
return Math.random() * 3000;
}
}
修改xml文件
<!-- SpEL的属性注入 -->
<bean id="carInfo" class="demo4.CarInfo">
</bean>
<bean id="car2" class="demo4.Car2">
<property name="name" value="#{carInfo.name}"></property>
<property name="price" value="#{carInfo.calculatorPrice()}"></property>
</bean>
<bean id="employee" class="demo4.Employee">
<property name="name" value="#{'赵洪'}"></property>
<property name="car2" value="#{car2}"></property>
</bean>
6.2.6 集合类型属性注入
①实体类
/**
* 集合属性的注入:
*
*/
public class CollectionBean {
private String[] arrs;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
public void setArrs(String[] arrs) {
this.arrs = arrs;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "CollectionBean [arrs=" + Arrays.toString(arrs) + ", list=" + list + ", set=" + set + ", map=" + map
+ "]";
}
}
②配置xml文件
<!-- Spring的集合属性的注入============================ -->
<!-- 注入数组类型 -->
<bean id="collectionBean" class="demo4.CollectionBean">
<!-- 数组类型 -->
<property name="arrs">
<list>
<value>王东</value>
<value>赵洪</value>
<value>李冠希</value>
</list>
</property>
<!-- 注入list集合 -->
<property name="list">
<list>
<value>李兵</value>
<value>赵如何</value>
<value>邓凤</value>
</list>
</property>
<!-- 注入set集合 -->
<property name="set">
<set>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</set>
</property>
<!-- 注入Map集合 -->
<property name="map">
<map>
<entry key="aaa" value="111"/>
<entry key="bbb" value="222"/>
<entry key="ccc" value="333"/>
</map>
</property>
</bean>
③测试类
@Test
public void demo1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");
System.out.println(collectionBean);
}
七.Spring分模块开发与项目优化
7.1 引入配置文件
在applicationContext.xml中引入其他配置文件
<import resource="applicationContext2.xml"/>
7.2 Spring项目优化
7.2.1 问题:
每次请求都会创建一个Spring的工厂,这样浪费服务器资源,应该一个项目只有一个Spring的工厂。
7.2.2 解决方案:
- 在服务器启动的时候,创建一个Spring的工厂,创建完工厂,将这个工厂类保存到ServletContext中,每次使用的时候都从ServletContext中获取,使用ServletContextListener,监听ServletContext对象的创建和销毁。
- 引入jar包:spring-web.jar
- 配置监听器
- 在Action中获取工厂