Spring
Spring 是什么?
Spring 是于 2003 年兴起的一个轻量级的,IOC 和 AOP 的 Java 开发框架,它
是为了简化企业级应用开发而生的。
Spring 优点
轻量级的
jar包小,运行消耗内存资源小,核心包小
spring于2003年兴起的一个轻量级的IOC和AOP的java开发框架,为了简化企业级开发而生的
Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核 心功能的所需的 jar 总共在 3M 左右。 Spring 框架运行占用的资源少,运行 效率高。
非侵入式
spring框架代码不会侵入到我们的业务代码(用户管理 servlet service dao) 编写一些业务类的时候不需要继承 spring 特定的类,通过配置完成依赖注入后 就可以使用,此时,spring 就没有侵入到我业务类的代码里. UserSrlevt extends HttpServlet(侵入式)
IOC
即 Inversion of Control,缩写为 IOC 控制反转 --> 把什么的控制权 反转 给谁 以前写代码,在哪儿需要一个对象,就地new一个
spring理念是将生成对象的控制权 反转给spring框架 由spring框架生成并管理对象
AOP
面向切面 为 Aspect(切面) Oriented Programming
开发出了第一版程序 修saveStudent(){ } 改原来的代码
绑定(配置)
savelog(){}
后来要在第一版的基础上添加功能(保存日志, 管理实务 sqlseesion.commit())
AOP的思想是 可以帮我们动态代理的调用,而不需要修改源代码
一站式
它是一个后端管理架构框架,集基础容器,数据访问(jdbc,事务管理),web(Servlet),AOP 为一身 的 一站式框架
spring搭建
第一步: 导入jar
依赖6个jar
org.springframework
spring-context
5.2.2.RELEASE
第二步: 创建类
第三部: 创建springp配置文件
第四部: 测试spring
IOC: spring创建对象
DI:Dependency Injection 依赖注入 为创建好的对象属性注入值.
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/*切面*/
@Component //创建对象
@Aspect //面向切面
public class Aopdemo {
/*
* 通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。
* 通 知分为方法执行前通知, 方法执行后通知, 异常通知 环绕通知(方法执行前通知+方法执行后通知)等.
* */
public void log4j(){
System.out.println("添加日志");
}
/* @Before("execution(* spring.dao.Userdao.save(..))")
public void before(){
System.out.println("前置通知");
}
@After("execution(* spring.dao.Userdao.save(..))")
public void after(){
System.out.println("后置通知");
}
@AfterReturning("execution(* spring.dao.Userdao.save(..))")
public void return1(){
System.out.println("return执行后通知");
}*/
/*
public void aroundAdvice(ProceedingJoinPoint point){
System.out.println("前置通知");
try {
point.proceed();//调用切入方法
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知");
}
System.out.println("后置通知");
}
*/
@Around("execution(* spring.dao.Userdao.save(..))")
public void around(ProceedingJoinPoint point) {
System.out.println("start");
try {
point.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知");
}
System.out.println("end");
}
public void exceptionAdvice(Throwable e){
System.out.println("异常通知"+e.getMessage());
}
}
Spring 体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMqYwcj5-1637671166120)(D:\HJ2012\框架\spring\无标题.png)]
Core Container(核心容器):
Beans: 管理 Beans
Core: Spring 核心
Context: 配置文件
ExpressionLanguage: SpEL 表达式
AOP(切面编程)
AOP 框架: Aspects
Data Access(数据库整合):
JDBC, ORM, OXM, JMS, Transaction
Web(MVC Web 开发):
Web, Servlet, Portlet, Struts
Test(Junit 整合)
官网地址:https://spring.io/
Spring Hello World 搭建
Maven 导入 spring 核心基础 jar
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
编写 spring 配置文件
<?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" class="spring.model.User">
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
</bean>
-->
<bean id="user" class="spring.model.User">
<constructor-arg type="java.lang.Integer" value="10"></constructor-arg>
<constructor-arg type="java.lang.String" value="王五"></constructor-arg>
</bean>
<bean id="UserDao" class="spring.dao.UserDao"></bean>
<bean id="userservice" class="spring.service.UserService">
<property name="userDao" ref="UserDao"></property>
</bean>
</beans>
编写一个 User 实体类
public class UserDao {
public void save(){
System.out.println("保存数据");
}
}
测试 spring
public class test {
public static void main(String[] args) {
//ApplicationContext是spring一个底层定义的接口,定义了一些规范
//ClassPathXmlApplicationContext是spring中一个具体落地实现的类(创建并管理对象)
ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
//spring思想:IOC把生成对象的控制权反转给spring框架
// 在程序中需要对象的时候,直接从spring容器中获取即可(依赖注入)
User user=app.getBean("user",User.class);
User user1=app.getBean("user",User.class);
System.out.println(user);
System.out.println(user1);
}
}
IOC(控制反转)
读作**“反转控制”(Inverse of Control)更好理解,不是什么技术,而是一种 设计思想,就是**将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。
对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
正控:若要使用某个对象,需要自己去负责对象的创建
反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,
不关心对象的创建过程,也就是把创建对象的控制权反转给了 Spring 框架.
Spring Bean 管理
基于 xml 配置方式
bean 配置需要 spring 管理的类
<!--
配置我们的项目中的类,配置进来spring就会对其进行管理(创建对象,存储)
由spring框架生成的一个对象称为Bean(特指spring框架创建的对象,他会添加额外的功能)
id 生成的对象名
class 全类名
name 对象别名,可以为多个
scope:
singleton(默认值):单例的,整个应用程序只创建一次,多次获取是同一个,在spring容器启动时创建
prototype:原型的(多例的),每次获取时创建一个新对象
request:每次 http 请求都会创建一个 bean, 仅用于 WebApplicationContext
-->
<!-- <bean id="user" name="user1,user2" class="spring.model.User" scope="prototype">
</bean>
-->
Xml 配置方式依赖注入
指 Spring 创建对象的过程中,将对象依赖属性(简单值,集合,对象)通
过配置设置给该对象。
<!--
创建对象并为对象属性赋值
方法有两种:
1.构造方法
2.set方法
-->
注解方式实现
注解开发准备工作
注解需要的 jar 包注解功能封装在 AOP 包中,导入 Spring aop jar 包即可
开启注解扫描
<context:component-scan base-package=“包名”> </context:component-scan>
• 注解创建对象
@Component(value=“user”)等于
@Service
@Repository
以上注解都可以实现创建对象功能,只是为了后续扩展功能,在不同的层
使用不同的注解标记
@Scope(value=“prototype”) 原型
@Scope(value=“ singleton ”) 单例
注解方式注入属性
@Autowired 是 Spring 提供的注解,可以写在字段和 setter 方法上。如果写在 字段上,那么就不需要再写 setter 方法。默认情况下它要求依赖对象必须存在, 如果允许 null 值,可以设置它的 required 属性为 false。
@Autowired是spring框架自身提供的注解标签
@Autowired(required = true) 默认,注入值不能为空
@Autowired是根据属性的类型自动注入(根据属性的类型在spring容器中查找byType
@Qualifier(value = "userDao")也可通过对象名查找注入需要
@Resource(name = "userDao")是JDK自身提供的注解标签也支持byName和byType两种注入方式
name = "userDao"指定注入的对象名
JDK 注解@Resource 自动注入
Spring 提供了对 jdk 中@Resource 注解的支持。@Resource 注解既可以按名 称匹配 Bean,也可以按类型匹配 Bean。默认按照 ByName 自动注入
byName 注入引用类型属性
@Resource 注解指定其 name 属性,则 name 的值即为按照名称进行匹配 的 Bean 的 id。
注解与 XML 的对比
注解优点: 方便,直观,高效(代码少,没有配置文件的书写那么复杂)。
**注解缺点:**以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重 启服务器即可将新的配置加载。
**xml 的缺点是:**编写麻烦,效率低,大型项目过于复杂。
Spring JDBC
Spring 是个一站式框架:
Spring 自身也提供了控制层的 SpringMVC 和 持久 层的 Spring JdbcTemplate。
开发步骤
下载 Spring JdbcTemplate 的 jar 包
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
导入属性文件
<context:property-placeholder location="config.properties"/>
管理数据源对象
spring 管理与数据库链接 (数据源)
<bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource">
<propertyname="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property><property name="username" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="initialSize" value="10"></property>
<property name="minIdle" value="5"></property>
<property name="maxActive" value="20"></property>
</bean>
在配置文件中创建 JdbcTemplate
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
JdbcTemplate 中常用的方法
execute:无返回值,可执行 ddl,增删改语句
update:执行新增、修改、删除语句;
queryForXXX:执行查询相关语句;
不使用 AOP 的开发方式
先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要再写两个非业务方法。非业务方法也称为交叉业务逻辑:
➢ save1():异常通知
➢save():保存数据
然后,再使接口方法调用它们。接口方法也称为主业务逻辑
AOP :面向切面编程
* oop 为面向对象编程
*(在oop基础上增加功能),将业务代码(保存,删除)和非业务代码(保存日志,提交事务)分离
oop是整体设计
AOP是针对业务代码中的公共部分提取,
核心原理: 使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑,可实现在不修改代码的情况下为程序增加新功能
抽取代码有条件(功能和业务逻辑没有直接关系)
面向切面编程的好处就是: 减少重复,专注业务;
注意:面向切面编程只是面向对象编程的一种补充。
核心原理:
使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
使用案例:
事务处理:开启事务,关闭事务,出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理
AOP 的基本概念
**连接点(Joinpoint):**类中可以被增强的方法,这个方法就被称为连接点
**切入点(pointcut):**类中有很多方法可以被增强,但实际中只有 add 和 update被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)
通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通 知分为方法执行前通知,方法执行后通知,环绕通知等.
**切面(Aspect)😗*把通知添加到切入点的过程叫切面.
目标(Target): 代理的目标对象(要增强的类)
代理(Proxy): 向目标对象应用通知之后创建的代理对象
springAOP 实现
下载 AOP 相关 jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
基于 aspectj 的 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--把装有增强功能的类交给spring管理
编制:将连接点与通知点编制到一起
-->
<bean id="Aopdemo" class="spring.aop.Aopdemo"></bean>
<aop:config>
<aop:pointcut id="save" expression="execution(* spring.dao.Userdao.save(..))"/>
<aop:pointcut id="save1" expression="execution(* spring.dao.Userdao.save1())"/>
<aop:aspect ref="Aopdemo">
<aop:before method="log4j" pointcut-ref="save"></aop:before>
<aop:after method="after" pointcut-ref="save"></aop:after>
<aop:before method="before" pointcut-ref="save"></aop:before>
<aop:around method="aroundAdvice" pointcut-ref="save"></aop:around>
<aop:after-returning method="return1" pointcut-ref="save"/>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="save1" throwing="e"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
基于注解方式的实现
启动 AspectJ 支持:<aop:aspectj-autoproxy />
定义通知:
@Component
@Aspect
public class AOPDemo {
@Before("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void before(){
System.*out*.println("before");
}
@After("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void after(){
System.out.println("after");
}
@Around("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void around(ProceedingJoinPoint point) throws Throwable { System.out.println("start");
point.proceed();
System.out.println("end");
}
@AfterThrowing(value = "execution(* com.ff.spring.demo1.dao.UserDao.*(..))",throwing = "e")
public void afterthrow(Throwable){
System.out.println("afterthrow");
}
@AfterReturning("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void afterreturn(){
System.out.println("afterreturn");
}
}
Spring 事物管理
事务:看做一次对数据的若干操作组成的一个序列,是一个整体的过程,要么都成功,要么都不成功
事物可以看做是由对数据库若干操作组成的一个单元。
我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作 的结合。由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常, 异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操 作数据的并不可靠,需要在这种情况下进行回退。 事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都 必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态,这些操作 要么都完成,要么都取消,从而保证数据满足一致性的要求 Spring 中的事务管理分为两种形式,一种是编程式事务,一种是声明式事务.
编 程 式 事 务
在 项 目 中 很 少 使 用 , 这 种 方 式 需 要 注 入 一 个 事 务 管 理 对 象 TransactionTemplate ,然后在我们代码中需要提交事务或回滚事务时自己写代 码实现.
声明式事务
管理建立在 AOP 基础上,本质是对方法前后进行拦截,所以声明式 事务是方法级别的。
Spring 声明式事物管理方式有两种:
基于 xml 配置
基于注解实现
Spring 事物管理 APIPlatformTransactionManager 事物管理器接口
Spring 针对不同的 dao 框架,提供了不同的实现类,Jdbc,mybatis 事物管理实
现类是 DataSourceTransactionManager.
配置事物管理器
<!-- 配置 spring 事务管理类, 并注入数据源 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
Xml 配置方式
<!-- 声明式事务 配置 spring 事务管理类, 并注入数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property> </bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- <!–配置spring事务传播行为,这是spring框架自己特有的功能–>
<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* spring.dao.Userdao.save(..))" id="save"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="save"/>
</aop:config>-->
<tx:annotation-driven transaction-manager="transactionManager"/>
在 service 中控制事务
@Service(value=“userservice”)
@Transactional(propagation=Propagation.REQUIRED)
Spring 事务传播行为
什么叫事务传播行为?
即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事
务方法调用时,这个事务方法应该如何进行。事务传播行为是 Spring 框架独有
的事务增强特性,他不属于的事务实际提供方数据库行为.
例如:methodA 事务方法调用 methodB 事务方法时,methodB 是继续在调
用者 methodA 的事务中运行呢,还是为自己开启一个新事务运行,这就是由
methodB 的事务传播行为决定的。
Spring 定义了七种传播行为:
PROPAGATION_REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务,指定的方法必须在事务内执行,若当前存在事务,加入到当前事务中,若当前没 有事务,则创建一个新事务,这种传播行为是最常见的,也是 spring 默认的传播行 为.
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPOR TED
以非事务方式执行操作,如果当前存在事务,就把当前事务 挂起。
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事 务,则执行与 PROPAGATION_REQUIRED 类似的操作。
声明式事务不生效的场景
@Transactional 应用在非 public 修饰的方法上
@Transactional 注解属性 propagation 设置错误
同一个类中方法调用,导致@Transactional 失效
异常被 catch 捕获导致@Transactional 失效
数据库引擎不支持事务
Spring 集成 Mybatis
Spring 集成 Mybatis 其核心是将 SqlSessionFactory 交由 Spring 管理,并由
Spring 管理对 dao 接口的代理实现。
导入 mybatis jar 包
Spring 结合 mybatis 插件包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
配置 sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml">
</property>
</bean>
指定生成接口代理
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="ssm.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
</property>
</bean>
在 service 中注入 Dao 代理接口,此接口有 Spring 代理实现