1. Spring概述
1.1 Spring是什么
Spring是一个JavaEE轻量级的一站式开发框架。
- 轻量级:使用最少代码启动框架,然后根据你的需求选择,选择你需要的模块使用。
- 重量级:早期有的EJB,开发一个HelloWorld程序都需要引入EBJ的全部模块
- 一站式:提供了,表示层(Struts2/SpringMVC),服务层,持久层的所有支持。
1.2 Spring框架的作用
- Spring是一个一站式的企业级(JavaEE)开发框架,意味着,仅仅使用一个Spring框架就可以满足JavaEE开发的表示层,服务层,持久层的开发。
- Spring强调的理念是,轻量级。意味着Spring提供的功能模块,除了内核模块以外,开发人员可以选择性使用。
- 所以,Spring框架在现实开发中,主要的功能用于整合,各种开发来开发项目。
- 一句话:Spring框架就是为了解耦
2.Spring框架包
官网:https://spring.io/
2.1 框架包的下载
- Spring官方提供的Maven方式的项目下载:https://start.spring.io/
- 基于学习,建议以架包方式学习,下载架包的路径为:http://repo.springsource.org/libs-release-local/org/springframework/spring/
2.2 目录说明
根目录
类库规则
包说明
包名 | 说明 |
---|---|
spring-aop-4.3.2.RELEASE.jar | 实现了AOP的支持 |
spring-aspects-4.3.2.RELEASE.jar | AOP框架aspects支持包 |
spring-beans-4.3.2.RELEASE.jar | 内核支撑包,实现了处理基于xml对象存取 |
spring-context-4.3.2.RELEASE.jar | 内核支撑包,实现了Spring对象容器 |
spring-context-support-4.3.2.RELEASE.jar | 容器操作扩展包,扩展了一些常用的容器对象的设置功能 |
spring-core-4.3.2.RELEASE.jar | 内核支撑包,Spring的内核 |
spring-expression-4.3.2.RELEASE.jar | 内核支撑包,实现了xml对Spring表达式的支持 |
spring-instrument-4.3.2.RELEASE.jar | 提供了一些类加载的的工具类 |
spring-instrument-tomcat-4.3.2.RELEASE.jar | 提供了一些tomcat类加载的的工具类,实现对应Tomcat服务的调用 |
spring-jdbc-4.3.2.RELEASE.jar | SpringJDBC实现包,一个操作数据库持久层的子框架 |
spring-jms-4.3.2.RELEASE.jar | 集成jms的支持,jms:Java消息服务。 |
spring-messaging-4.3.2.RELEASE.jar | 集成messaging api和消息协议提供支持 |
spring-orm-4.3.2.RELEASE.jar | ORM框架集成包,实现了Hibernate,IBatis,JDO的集成。 |
spring-oxm-4.3.2.RELEASE.jar | Spring OXM对主流O/X Mapping框架做了一个统一的抽象和封装。就是对应XML读写框架的支持 |
spring-test-4.3.2.RELEASE.jar | Spring集成JUnit测试 |
spring-tx-4.3.2.RELEASE.jar | 事务代理的支持 |
spring-web-4.3.2.RELEASE.jar | SpringWeb通用模块 |
spring-webmvc-4.3.2.RELEASE.jar | SpringMVC子框架 |
spring-webmvc-portlet-4.3.2.RELEASE.jar | Spring对门户技术(portlet)的支持 |
spring-websocket-4.3.2.RELEASE.jar | Spring对websocket的支持 |
3. 入门案例
3.1 配置流程图
3.2 配置步骤
创建一个java项目,创建目录结构
导入包
- Spring基础支撑包
- Spring依赖日志包
创建配置文件
在项目的src下面创建配置文件applicationContext.xml中并完成配置文件的约束,约束查找位置:
(spring框架docs/spring-framework-reference/core.html#beans-introduction)
<?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">
</beans>
创建对象到容器里面
- 创建一个类
package com.zj.service;
public class HelloWorldService {
public void say(){
System.out.println("--你好世界!--");
}
}
- application.Context.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-4.2.xsd ">
<!--
<bean>标签:用于声明一个类,在启动Spring框架的时候根据该配置的类创建对象到容器里面
name
-->
<bean name="helloWorldService" class="com.zj.service.HelloWorldService"></bean>
</beans>
- 测试使用getBean获得容器中的对象。
package com.zj.test;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zj.service.HelloWorldService;
public class HelloWorldServiceTest {
@Test
public void say(){
//创建一个ApplicationContext对象,根据xml配置创建一个对象
//直接读取Spring的src目录下的配置文件的子类是ClassPathXmlApplicationContext
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorldService helloWorldService = context.getBean("helloWorldService", HelloWorldService.class);
//调用方法
helloWorldService.say();
}
}
通过代码得到,Spring框架不用new就可以创建对象。
3.3 Spring容器的两个实现
- ClassPathXmlApplicationContext:通过classpath路径直接获得加载的xml文件(推荐使用)
- FileSystemXmlApplicationContext:通过文件路径来获得加载的xml文件。
3.4 ApplicationContext类图结构图
通过结构图可以看到,Spring容器顶级接口是BeanFactory,ApplicationContext是它的子接口。
4. Spring的IOC和DI
IOC:Inverse of Control(控制反转)
读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,好比于MVC。就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
- IOC:指将对象的创建权,反转给了Spring容器;
- 正控:若调用者需要使用某个对象,其自身就得负责该对象的创建。
- 反控:调用者只管负责从Spring容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架。(Don’t call me ,I’ll call you)
DI:Dependency Injection(依赖注入)
DI 指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。IoC和DI其实是同一个概念的不同角度描述,DI相对IoC而言,明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Container:容器
在活中容器就是一种盛放东西的器皿,从程序设计角度看作是装对象的对象,因为存在对对象的存入、取出等操作,所以容器还要管理对象的生命周期。
4.1 IOC和DI
所谓的控制反转,就是将代码的调用权从调用方转移给被调用方(服务提供方)。
强耦合关系:将A调用B的对象修改为C类的对象,修改的是调用方的代码,所以我们认为代码的调用权在调用方。
基于IOC控制反转的调用方式
根据上图可以的得出,实现一个IoC的框架,必须要解决两个问题:
- 被调用方(服务方),在程序启动时就要创建好对象,放在一个容器里面。
- 调用方使用一个接口或类的引用(不用使用new),就可以创建获得对象。
一帮将这种不用new,而是根据接口或者类的引用就可以从被调用的容器里获得创建的对象的方式称为依赖注入。所以,控制反转(Ioc),就是依赖注入加上面向接口的编程思想的实现。
重点就是,Spring之所以可以实现可插拔程序,是实现了不用new,使用类或接口就可以获得获得对象!
4.2 标签说明
alias标签
<?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="user" name="test" class="cn.zj.spring.pojo.User"/>
<!--
标签alias: 为已配置的bean设置别名
属性name: 必要属性, 代表为哪一个bean配置别名,
此属性的值为其他bean标签的id或name属性值
属性alias: 必要属性, 代表新命名的别名是什么
-->
<alias name="user" alias="user1"/>
</beans>
Bean标签
<!-- <bean>标签:用于声明一个类,在启动Spring框架的时候根据该配置的类创建对象到容器里面
name:设置对象名(唯一标识符),可以有多个名称,每个名称用逗号隔开 : name1,name2
id:设置对象名(唯一标识符,功能和name一样)
class:用于指定对象对应的类名
scope:用于设置的对象的作用范围,可选参数如下:
*singleton:单例(默认)
对象出生:当程序加载配置文件创建容器时,创建
对象活着:只要容器还在,一直活着
对象死亡:应用停止,容器销毁,对象死亡
*prototype:多例(原型对象)
对象出生:当程序加载配置文件创建容器时,创建
对象活着:只要对象被使用,一直活着
对象死亡:对象长时间不用,会被Java垃圾回收机制回收
*reqeust:web项目中,Spring将创建的对象放在request作用域中
*session:web项目中,Spring将创建的对象放在session作用域中
*globalSession:web项目中,应用域portlet环境,如果没有protlet环境相当于session
init-method:设置创建对象的时候,调用初始化方法
destroy-method:设置对象被回收时,调用注销的方法
-->
<bean name="customerServiceImpl" class="com.zj.spring.service.impl.CustomerServiceImpl"></bean>
实例化Bean的四种方式
- 构造器实例化(无参构造器),最标准,使用最多
public class SomeBean1 {
public SomeBean1() {
System.out.println("SomeBean.SomeBean1()");
}
}
配置文件
<!-- ①.构造器实例化(无参数构造器),最标准,使用最多。 -->
<bean id="someBean1" class="cn.zj.spring.pojo.SomeBean1"></bean>
- 通过静态工厂创建(了解)
SomeBean2/SomeBean2Facotry
public class SomeBean2 {
public SomeBean2() {
System.out.println("SomeBean.SomeBean2()");
}
}
public class SomeBean2Facotry {
//静态工厂方法
public static SomeBean2 getSomeBean2() {
System.out.println("执行静态工厂方法");
return new SomeBean2();
}
}
配置文件
<!-- ②.静态工厂方法实例化:解决系统遗留问题 -->
<bean id="someBean2" class="cn.zj.spring.pojo.SomeBean2Facotry"
factory-method="getSomeBean2"></bean>
- 通过实体工厂创建(了解)
public class SomeBean3 {
public SomeBean3() {
System.out.println("SomeBean.SomeBean3()");
}
}
public class SomeBean3Facotry {
//实例工厂方法
public SomeBean3 getSomeBean3() {
System.out.println("执行实例工厂方法");
return new SomeBean3();
}
}
配置方式
<!-- ③.实例工厂方法实例化:解决系统遗留问题 -->
<!-- 1.配置工厂bean -->
<bean id="someBean3Factory" class="cn.zj.spring.pojo.SomeBean3Facotry"></bean>
<!-- 2.配置bena
factory-bean : 创建bean的工厂对象对应的 id
factory-method : 工厂bean中返回 bean对象的方法
-->
<bean id="someBean3" factory-bean="someBean3Factory" factory-method="getSomeBean3"/>
- 实现FactoryBean接口实例化
实现FactoryBean接口,MyBatis和Spring集成就是使用的这种方法。此种方式,如果没有使用Bean对应的对象,Spring就不会自动创建,只有在使用的时候Spring才会创建对应的对象。
public class SomeBean4 {
public SomeBean4() {
System.out.println("SomeBean4.SomeBean4()");
}
}
public class SomeBean4ObjectFactory implements FactoryBean<SomeBean4>{
//返回的泛型类型对应的对象
@Override
public SomeBean4 getObject() throws Exception {
SomeBean4 bean4 = new SomeBean4();
return bean4;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
配置方式
!-- ④.实现FactoryBean接口实例化:实例工厂变种:集成其他框架使用:LocalSessionFactoryBean -->
<bean id="someBean4" class="cn.zj.domian.SomeBean4ObjectFactory"></bean>
Spring依赖注入DI的方式
所谓的依赖注入,就是属性不创建对象,通过配置文件的配置将Spring容器里面的对象注入给对应的属性。依赖注入有三种方式:setter注入(属性注入)、构造器注入和P命名空间注入。
获取properties文件的值
- Spring配置文件支持通过xxx.properties文件的Key获得对应的值。实现该功能是通${Key}来获得Properties文件对应Key的值。
- 使用Spring读取配置文件必须导入新的命名空间 context;导入命名空间方法,将命名空间和约束重新拷贝一份,将对于的全部替换成 context。
- 使用Spring创建阿里巴巴Druid连接池,读取配置文件
拷贝mysql驱动包和druid连接池jar包到项目中
创建db.properites
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbcdemo
jdbc.username=root
jdbc.password=root
jdbc.maxActive=10
applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 读取项目的配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 创建连接池对象 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName"
value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="${jdbc.maxActive}" />
</bean>
</beans>
4.5 案例代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--p空间的引入:xmlns:p="http://www.springframework.org/schema/p"-->
<!--context引入:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
-->
<bean id="helloService" class="cn.xiaoxiao.spring01.service.HelloService"></bean>
<!--IOC:控制反转-->
<!--service-->
<bean id="serviceA" class="cn.xiaoxiao.IocDI.service.impl.CustomerServiceImplA"></bean>
<bean id="serviceB" class="cn.xiaoxiao.IocDI.service.impl.CustomerServiceImplB"></bean>
<!--controller-->
<bean id="customerController" class="cn.xiaoxiao.IocDI.controller.CustomerController">
<!--依赖注入-->
<property name="customerService" ref="serviceB"></property>
</bean>
<!--IOC:控制反转-->
<!-- 1.setter方法注入:属性注入
name:属性名称
value:基本数据类型+String类型的值注入
ref:引用类型(对象类型)的注入
ref和value二选一
-->
<bean id="emp" class="cn.xiaoxiao.DI.pojo.Employee">
<property name="name" value="贾宝玉"/>
<property name="age" value="18"/>
<property name="dept" ref="myDept"/>
</bean>
<!-- 2.构造方法注入-->
<bean id="myDept" class="cn.xiaoxiao.DI.pojo.Department">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="吹水"/>
</bean>
<!--3.p空间注入-->
<bean id="user" class="cn.xiaoxiao.DI.pojo.User"
p:id="124" p:name="林黛玉" p:age="18"/>
<!--4.集合类型注入-->
<bean id="collectionBean" class="cn.xiaoxiao.DI.pojo.CollectionBean">
<!--Array-->
<property name="arrays">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<!--list-->
<property name="list">
<list>
<value>1</value>
<value>1</value>
<value>1</value>
<value>1</value>
</list>
</property>
<!--set-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
<value>set4</value>
</set>
</property>
<!--map-->
<property name="map">
<map>
<entry key="key1" value="贾宝玉"/>
<entry key="key2" value="林黛玉"/>
<entry key="key3" value="贾宝玉"/>
</map>
</property>
<!--property-->
<property name="prop">
<props>
<prop key="pro1">proVlaue1</prop>
<prop key="pro2">proVlaue2</prop>
</props>
</property>
</bean>
<!--读取配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--连接池配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</bean>
</beans>
5. Spring综合案例xml-模拟注册功能
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userServlet" class="cn.xiaoxiao.controller.UserServlet">
<property name="userService" ref="userService"/>
</bean>
<bean id="userService" class="cn.xiaoxiao.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="cn.xiaoxiao.dao.impl.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--读取配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--连接池配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</bean>
</beans>
UesrServlet.java
public class UserServlet {
/* 传统做法
* private UserService service = new UserServiceImpl();
* 现在交给Spring管理,使用Spring的setter方法注入
* 因为要交给Spring的setter方法注入,所以(必须)提供set方法
*/
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void register(User user) {
userService.register(user);
}
}
UserServiceImpl.java
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void register(User user) {
userDao.register(user);
}
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void register(User user) {
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("conn:" + conn);
System.out.println("user:" + user);
}
}