Spring 框架详细学习
学习Spring 框架目录
-
-
- Spring BeanFactory 容器
- Spring ApplicationContext 容器
- Spring Bean 定义
- Spring Bean 作用域
- Spring Bean 生命周期
-
- Spring 基于构造函数的依赖注入
- Spring 基于set方法的依赖注入
- Spring 注入内部 Beans
- Spring 注入集合
-
- Spring 自动装配 byName
- Spring 自动装配 byType
- Spring 由构造函数自动装配
-
Spring 基于注解的配置
- Spring @Required 注释
- Spring @Autowired 注释
- Spring @Qualifier 注释
-
Spring 框架的AOP
- Spriing 中基于AOP的XML架构
- Spring 中基于AOP的 @Aspect架构
-
Spring JDBC 框架
- Spring JDBC 示例
- Spring 中SQL的存储过程
-
Spring 事务管理
- Spring 编程式事务管理
- Spring 声明式事务管理
-
Spring Web MVC 框架
- Spring MVC Hello World 例子
- Spring MVC 表单处理例子
- Spring 页面重定向例子
- Spring 静态页面例子
- Spring 异常处理例子
- Spring 使用 Log4J 记录日志
Spring概述
Spring 是一个轻量级开源框架,它以IOC(控制反转)和AOP(面向切面编程)为内核,使用基本的JavaBean来完成工作。
Spring框架结构
体系结构
核心模块
- Core Container(核心容器)
- Beans:核心组件是BeanFactory,对Bean进行管理。是工厂模式的实现。
- Core:Spring框架的基本组成部分。
- Context:访问定义和任何对象的媒介。ApplicationContext接口是上下文模块的焦点。
- SpEL:是运行时查询和操作对象图的强大的表达式语言。
- Web 模块
- Web:提供面向Web的基本功能。例如使用Servlert监听器初始化Ioc容器等。
- Servlert:Spring模型——视图——控制层(MVC)实现Web应用程序。
- Struts:集成Struts Web层。
- Protlet:类似Web-Servlert的功能。
- Data Access / Integration(数据访问/集成)
- JDBC:提供JDBC抽象层。
- ORM:提供对象关系映射API,例如Hibernate、JPA等的集成。
- OXM:提供支持对象/XML映射的抽象层实现。
- JMS:Java消息服务。
- Transactions:支持编程和声明式事务实现特殊接口类。编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细。
- 其他模块
- AOP:提供面向切面编程的实现。
- Aspects:功能强大且成熟的面向切面编程的实现。
- Messaging
- Instrumentation
Spring Hello World例子
- Idea新建Maven项目,添加Spring依赖<!-- spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
- Idea中项目结构图如下:
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>springMVC</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
添加Tomcat启动就Ok了。
Spring Ioc 容器
Spring 容器是Spring 框架的核心,Ioc容器具有依赖注入功能的容器,可以创建对象,Ioc容器负责实例化等操作。Spring提供了两种不同类型的容器。容器名称 | 容器描述 |
---|---|
Spring BeanFactory容器 | 给DI提供和基本的支持。 |
Spring ApplicationContext 容器 | 加载配置文件中定义的bean,另外增加了其他功能。 |
Spring BeanFactory 容器
- 主要功能是为依赖注入提供支持。在Spring中,有大量对BeanFactory接口的实现。其中最常用的是XmlBeanFactory类,从Xml中读取配置数据。
使用XmlBeanFactory实例如下:
- HelloWorld.java
public class HelloWorld {
private int id;
private String message;
@Override
public String toString() {
return "HelloWorld{" +
"id=" + id +
", message='" + message + '\'' +
'}';
}
// 省略setget方法
}
- HelloWorld.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-3.0.xsd">
<bean id="helloWorld" class="com.li.entity.HelloWorld">
<property name="message" value="张三"></property>
<property name="id" value="1"></property>
</bean>
</beans>
- 测试方法
@Test
public void test1(){
// 定义Bean的文件地址
ClassPathResource resource=new ClassPathResource("HelloWorld.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
HelloWorld helloWorld = factory.getBean(HelloWorld.class);
System.out.println(helloWorld.toString());
}
Spring ApplicationContext 容器
ApplicationContext 是BeanFactory的子接口,也被称为应用上下文,它有两个常用的实现类。
- ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {
configLocation}, true, null);
}
- FileSystemXmlApplicationContext
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {
configLocation}, true, null);
}
- WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
两种容器使用的区别:如果Bean的一个属性没有注入,使用BeanFactory加载后,在第一次调用getBean()方法会抛出异常, ApplicationContext 则在初始化时自检,这样有利于检查所依赖的属性是否注入。
Spring Bean 定义
Bean是一个被实例化、组装通过SpringIoc容器所管理的对象。
- Bean所包含的属性
属性 | 意义 |
---|---|
class | 指定用来创建Bean的类 |
name | 指定唯一的Bean标识,可以使用Id或name进行唯一标识 |
scope | 指定Bean的作用域 |
constructor-arg | 用来注入依赖关系 |
properties | 用来注入依赖关系 |
autowiring mode | 用来注入依赖关系 |
lazy-initialization mode | 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。 |
-
Spring 配置元数据:有下面三种方法把配置元数据提供给Spring容器。
- 基于Xml的配置文件
- 基于注解的配置:@Component取代
<bean class="">
、@Component(“id”)取代<bean id=" " class=" ">
。注解使用的前提,在xml中配置让spring扫描含有的注解类。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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:component-scan base-package="com.cc.study.annotation"></context:component-scan>
</beans>
- 基于Java的配置
Spring Bean 作用域
当在Spring中定义一个Bean时候,必须声明Bean作用域的选项。
作用域 | 描述 |
---|---|
singleton | SpingIoc容器中仅存在一个Bean实例,以单例方式存在 |
prototype | 每次从容器中调用Bean时都返回一个新的实例 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 暂不了解 |
- singleton配置方式
<bean id="helloWorld" class="com.li.entity.HelloWorld" scope="singleton">
<property name="message" value="张三" ></property>
<property name="id" value="1"></property>
</bean>
Spring Bean 生命周期
Bean的生命周期:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
- HelloWorld.java
public void init(){
System.out.println("HelloWorld Bean创建了");
}
public void destroy(){
System.out.println("HelloWorld Bean销毁了");
}
- HelloWorld.xml
<bean id="helloWorld" class="com.li.entity.HelloWorld" scope="singleton" init-method="init" destroy-method="destroy">
<property name="message" value="张三" ></property>
<property name="id" value="1"></property>
</bean>
- Test.java
@Test
public void test3(){
AbstractApplicationContext context=new ClassPathXmlApplicationContext("HelloWorld.xml");
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
System.out.println(helloWorld);
context.registerShutdownHook();
}
Spring 依赖注入
Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。每个基于应用程序的 java 都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。spring通过注入对象的方式进行管理这些Bean之间的依赖关系。能注入的数据类型有基本类型和String、其他Bean类型
Spring 基于构造函数的依赖注入
- type:用于不指定要注入数据的数据类型
- index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。
- name:用于指定给构造函数中指定名称的参数赋值。
- ref:指定其他的Bean类型。
两个实体类
- People.java
public class People {
private int id;
private Message message;
public People(int id, Message message) {
System.out.println("我是People的构造函数!"+"===="+id+"======"+message);
this.id = id;
this.message = message;
}
}
- Message.java
public class Message {
private int id;
private String world;
public Message(int id, String world) {
System.out.println("我是Message的构造函数"+"===="+id+"====="+world);
this.id = id;
this.world = world;
}
}
- peopleBean.xml:通过构造函数的方式注入,配置实例如下:
<bean id="people" class="com.li.entity.People">
<constructor-arg type="int" name="id"><value >10</value></constructor-arg>
<constructor-arg ref="message"></constructor-arg>
</bean>
<bean id="message" class="com.li.entity.Message">
<constructor-arg type="int" name="id"><value>12</value></constructor-arg>
<constructor-arg type="java.lang.String" name="world"><value>"张三"</value></constructor-arg>
</bean>
Spring 基于set方法注入
- name:用于指定注入时所调用的set方法名称
- value:用于提供基本类型和String类型的数据
- ref:用于指定其他的bean类型(在spring的ioc核心容器中出现过的bean对象)数据
<bean id="accountServiceSet" class="com.dudu.service.impl.AccountServiceImplSet">
<property name="name" value="骆闻舟"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
Spring 注入内部 Beans
- people.java
public class People {
private int id;
private Message message;
public People(int id, Message message) {
System.out.println("我是People的构造函数!"+"===="+id+"======"+message);
this.id = id;
this.message = message;
}
public Message message(){
return message;
}
public void showMessage(){
message.show();
}
}
- Bean.xml
<bean id="people" class="...">
<property name="message">
<bean id="message" class="..."/>
</property>
</bean>
Spring 注入集合
- testBean.xml
<bean id="accountServiceList" class="com.dudu.service.impl.AccountServiceImplList">
<property name="myList">
<list><!-- 标签可以换成array或set -->
<value>骆闻舟</value>
<value>长庚</value>
<value>赵锦辛</value>
<!-- <ref bean="now"><bean></bean></ref> -->
</list>
</property>
<property name="myMap">
<map><!-- 标签可以换成props -->
<entry key="骆闻舟" value="费渡"/><!-- 标签可以换成prop -->
<entry key="长庚" value="顾昀"/><!-- <prop key="骆闻舟">费渡</prop> -->
<entry key="黎朔" value="赵锦辛"/>
</map>
</property>
<!-- 配置独立的list -->
<util:list id="cars">
<ref bean=""></ref>
</util:list>
</bean>
Spring Beans 自动装配
自动装配模式
方法 | 描述 |
---|---|
byName | 由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。 |
byType | 由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。 |
constructor | 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。 |
Spring 自动装配 byName
<bean id="people" class="com.li.People" autowire="byName">
<property name="name" value="张三" />
</bean>
Spring 自动装配 byType
<bean id="people" class="com.li.People" autowire="byType">
<property name="name" value="张三" />
</bean>
Spring 由构造函数自动装配
一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。 |
|constructor | 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。 |
Spring 自动装配 byName
<bean id="people" class="com.li.People" autowire="byName">
<property name="name" value="张三" />
</bean>
Spring 自动装配 byType
<bean id="people" class="com.li.People" autowire="byType">
<property name="name" value="张三" />
</bean>
Spring 由构造函数自动装配
Spring 基于注解的配置
从Spring2.5开始可以使用注解来配置依赖注入,而不是采用xml描述一个bean,可以通过注解进行配置Bean。如果想用注解进行配置,可以加上配置。
<!-- 使用注解进行配置 -->
<context:annotation-config/>
注解 | 注解 & 描述 |
---|---|
@Required | @Required 注解应用于 bean 属性的 setter 方法。 |
@Autowired | @Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。 |
@Qualifier | 通过指定确切的将被连线的 bean,@Autowired 和 @Qualifier 注解可以用来删除混乱。 |
Spring @Required 注释
@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。
Spring @Autowired 注释
使用 spring 开发时,进行配置主要有两种方式,一是 xml 的方式,二是 java config 的方式。@Autowired 注释的功能就是为我们注入一个定义好的 bean。
Spring @Qualifier 注释
当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
Spring 框架的AOP
Aop将影响多个模块的行为方法进行封装到一个可重用模块,并将其命名为切面(Aspect),与业务无关,便于减少系统的重复代码,降低模块之间的耦合度,利于后面的可操作性和可维护性。
- AOP核心概念
概念 | 意义 |
---|---|
切入点(Pointcut) | 在哪些类,哪些方法上切入 |
通知(Advice) | 在方法执行的时候(方法前,方法后,方法前后)做什么 |
切面(Aspect) | 在什么时机,什么什么地方,作什么增强 |
织入(Weaving) | 把切面加入到对象,并创建出代理对象的过程 |
Spriing 中基于AOP的XML架构
- Aspect依赖
<!-- Aspect -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
- message.java:要进行切入的对象
public class Message {
private int id;
private String message;
public void showMessage(){
System.out.println(this.id+"========"+this.message);
System.out.println("我是Message的show()");
}
// 省略setget()
}
- 连接点
public interface Logging {
public void beforeAdvice();
public void afterAdvice();
public void afterReturningAdvice(Object retVal);
}
public class LoggingImpl implements Logging {
@Override
public void beforeAdvice() {
System.out.println("方法之前");
}
@Override
public void afterAdvice() {
System.out.println("方法之后");
}
@Override
public void afterReturningAdvice(Object retVal){
System.out.println("方法返回之后得到的返回值为=======" + retVal.toString());
}
}
- bean的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="message" class="com.li.entity.Message">
<property name="id" value="1"></property>
<property name="message" value="testmessage"></property>
</bean>
<bean id="loggingImpl" class="com.li.entity.LoggingImpl"></bean>
<aop:config >
<aop:aspect id="testlog" ref="loggingImpl">
<aop:pointcut id="selectAll" expression="execution(* com.li.entity.*.*(..))"/>
<aop:before method="beforeAdvice" pointcut-ref="selectAll" ></aop:before>
<aop:after method="afterAdvice" pointcut-ref="selectAll"></aop:after>
<aop:after-returning returning="retVal" method="afterReturningAdvice" pointcut-ref="selectAll"></aop:after-returning>
</aop:aspect>
</aop:config>
</beans>
Spring 中基于AOP的 @Aspect架构
-
需要的依赖同上面。
-
连接点
@Aspect
public class LogAspect {
@Pointcut("execution(* com.li.entity.*.*(..))")
private void selectAll(){
System.out.println("定义的连接点");
}
@Before("selectAll()")
public void beforeAdvice(){
System.out.println("=========方法前");
}
@After("selectAll()")
public void afterAdvice(){
System.out.println("=========方法后");
}
}
- bean的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="message" class="com.li.entity.Message">
<property name="id" value="1"></property>
<property name="message" value="testmessage"></property>
</bean>
<bean id="logAspect" class="com.li.aspect.LogAspect"></bean>
</beans>
Spring JDBC 框架
在使用普通的jdb操作数据库时候,需要些代码处理异常。Spring jdbc框架负责所有的底层细节,从开始打开连接、准备和执行Sql语句、事务处理、异常处理等。
- JdbcTemplate 类
使用JdbcTemplate常用的方法是在Spring配置文件中配置数据源,共享数据源Bean进行注入,实例化JdbcTemplate。
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
Spring JDBC 示例
- 添加Maven依赖
<!-- Spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
- beam.xml
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value=""></property>
<property name="username" value=""></property>
<property name="password" value=""></property>
</bean>
- 使用
@Test
public void test6(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = context.getBean("dataSource", DataSource.class);
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * test");
maps.forEach(x->{
System.out.println(x);
});
}
。。。。。。未完待续!