感谢尚硅谷
视频地址:【尚硅谷】Spring框架视频教程(spring5超详细源码级讲解)_哔哩哔哩_bilibili
主要内容
一、Spring简介
二、Spring IOC介绍
三、IOC操作Bean管理
四、Spring AOP
五、Spring 事务操作
一、Spring简介
1、Spring概述
官网地址:Spring | Home
Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用
Spring 框架来创建性能好、易于测试、可重用的代码。
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首
次在 Apache 2.0 许可下发布。
Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应
用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO
编程模型来促进良好的编程实践。
2、Spring家族
项目列表:Spring | Projects
3、Spring Framework
Spring 基础框架,可以视为 Spring 基础设施,基本上任何其他 Spring 项目都是以 Spring Framework 为基础的。
1)Spring Framework特性
- 非侵入式:使用 Spring Framework 开发应用程序时,Spring 对应用程序本身的结构影响非常小。对领域模型可以做到零污染;对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。这就使得基于 Spring Framework 开发应用程序 时结构清晰、简洁优雅。
- 控制反转:IOC——Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源 变成环境将资源准备好,我们享受资源注入。
- 面向切面编程:AOP——Aspect Oriented Programming,在不修改源代码的基础上增强代码功能。
- 容器:Spring IOC 是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化 的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发 效率。
- 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML 和 Java 注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。
- 声明式:很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
- 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且 Spring 旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。
2)Spring Framework五大功能模块
| 功能模块 | 功能介绍 |
| Core Container | 核心容器,在 Spring 环境下使用任何功能都必须基于 IOC 容器。 |
| AOP&Aspects | 面向切面编程 |
| Testing | 提供了对 junit 或 TestNG 测试框架的整合。 |
| Data Access/Integration | 提供了对数据访问/集成的功能。 |
| Spring MVC | 提供了面向Web应用程序的集成功能。 |
二、Spring IOC介绍
1、IOC思想
IOC:Inversion of Control,翻译过来是反转控制。
①获取资源的传统方式
自己做饭:买菜、洗菜、择菜、改刀、炒菜,全过程参与,费时费力,必须清楚了解资源创建整个过程 中的全部细节且熟练掌握。
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的 模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
②反转控制方式获取资源
点外卖:下单、等、吃,省时省力,不必关心资源创建过程的所有细节。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
③DI
DI:Dependency Injection,翻译过来是依赖注入。
DI 是 IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器 的资源注入。相对于IOC而言,这种表述更直接。
所以结论是:IOC 就是一种反转控制的思想, 而 DI 是对 IOC 的一种具体实现。
使用 IOC 目的:为了耦合度降低
2、IOC 底层原理
xml 解析、工厂模式、反射

3、IOC容器在Spring中的实现
Spring 的 IOC 容器就是 IOC 思想的一个落地的产品实现。IOC 容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建 IOC 容器。Spring 提供了 IOC 容器的两种实现方式:
- BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用。加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件的对象进行创建
ApplicationContext 接口实现类

| 类型名 | 简介 |
| ClassPathXmlApplicationContext | 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器 对象 |
| FileSystemXmlApplicationContext | 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象 |
| ConfigurableApplicationContext | ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、 关闭和刷新上下文的能力。 |
| WebApplicationContext | 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对 象,并将对象引入存入 ServletContext 域中。 |
三、IOC操作Bean管理
Bean 管理指的是两个操作
- Spring 创建对象
- Spirng 注入属性
Bean 管理操作有两种方式
- 基于 xml 配置文件方式实现
- 基于注解方式实现
1、IOC操作Bean管理(基于 xml 方式)
1)基于 xml 创建对象
<bean id="helloworld" class="com.atguigu.spring.bean.HelloWorld"></bean>
配置HelloWorld所对应的bean,即将HelloWorld的对象交给Spring的IOC容器管理,通过bean标签配置IOC容器所管理的bean
属性:
- id:设置bean的唯一标识
- class:设置bean所对应类型的全类名
测试
@Test
public void testHelloWorld(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloworld = (HelloWorld) ac.getBean("helloworld");
helloworld.sayHello();
}
思路

Spring 底层默认通过反射技术调用组件类的无参构造器来创建组件对象,这一点需要注意。如果在需要 无参构造器时,没有无参构造器,则会抛出下面的异常
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'helloworld' defined in class path resource [applicationContext.xml]: Instantiation of bean
failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed
to instantiate [com.atguigu.spring.bean.HelloWorld]: No default constructor found; nested
exception is java.lang.NoSuchMethodException: com.atguigu.spring.bean.HelloWorld.<init>
()
2)基于xml方式注入属性
第一种注入方式:使用 set 方法
创建类,定义属性和对应的 set 方法
/** * 演示使用 set 方法进行注入属性 */ public class Book { //创建属性 private String bname; private String bauthor; //创建属性对应的 set 方法 public void setBname(String bname) { this. bname = bname; } public void setBauthor(String bauthor) { this. bauthor = bauthor; } }在 spring 配置文件配置对象创建,配置属性注入
<!--2 set 方法注入属性--> <bean id="book" class="com.atguigu.spring5.Book"> <!--使用 property 完成属性注入 name:类里面属性名称 value:向属性注入的值 --> <property name= "bname" value="易筋经"></property> <property name= "bauthor" value="达摩老祖"></property> </bean>
第二种注入方式:使用有参数构造进行注入
1)创建类,定义属性,创建属性对应有参数构造方法
/** * 使用有参数构造注入 */ public class Orders { //属性 private String oname; private String address; //有参数构造 public Orders(String oname,String address) { this. oname = oname; this. ad dress = address; } }2)在 spring 配置文件中进行配置
<!--有参数构造注入属性--> <bean id="orders" class="com.atguigu.spring5.Orders"> <constructor-arg name= "oname" value="电脑"></constructor-arg> <constructor-arg name= "address" value="China"></constructor-arg> </bean>
第三种注入方式:p 名称空间注入(了解)
使用 p 名称空间注入,可以简化基于 xml 配置方式
1)添加 p 名称空间在配置文件中
2)进行属性注入,在 bean 标签里面进行操作
<!--2 set 方法注入属性--> <bean id="book" class="com.atguigu.spring5.Book" p:bname="九阳神功" p:bauthor="无名氏"></bean>
3)xml 注入其他类型属性
字面量
(1)null 值
<!--null 值--> <property name="address"> <null/> </property>(2)属性值包含特殊符号
<!--属性值包含特殊符号 1 把<>进行转义 < > 2 把带特殊符号内容写到 CDATA --> <property name= "address"> <value><![CDATA[<<南京>>]]></value> </property>
注入属性- 外部 bean
(1)创建两个类 service 类和 dao 类
(2)在 service 调用 dao 里面的方法
(3)在 spring 配置文件中进行配置public class UserService { //创建 UserDao 类型属性,生成 set 方法 private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add() { System.out.println( "service add..............."); userDao.update(); } }<!--1 service 和 dao 对象创建--> <bean id="userService" class="com.atguigu.spring5.service.UserService"> <!--注入 userDao 对象 name 属性:类里面属性名称 ref 属性:创建 userDao 对象 bean 标签 id 值 --> <property name="userDao" ref="userDaoImpl"></property> </bean> <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
注入属性- 内部 bean
//部门类 public class Dept { private String dname; public void setDname(String dname) { this. dname = dname; } }//员工类 public class Emp { private String ename; private String gender; //员工属于某一个部门,使用对象形式表示 private Dept dept; public void setDept(Dept dept) { this.dept = dept; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } }<!--内部 bean--> <bean id= "emp" class= "com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <!--设置对象类型属性--> <property name="dept"> <bean id="dept" class="com.atguigu.spring5.bean.Dept"> <property name="dname" value="安保部"></property> </bean> </property> </bean>
注入属性-级联赋值
级联赋值在使用上,是在一个对象中注入另一个bean对象(外部bean)的属性并对该属性进行赋值
(1)第一种写法
<!--级联赋值--> <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <!--级联赋值--> <property name="dept" ref="dept"></property> </bean> <bean id="dept" class="com.atguigu.spring5.bean.Dept"> <property name="dname" value="财务部"></property> </bean>(2)第二种写法
<!--级联赋值--> <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <property name= "dept" ref="dept"></ property> <property name= "dept.dname" value="技术部"></property> </bean> <bean id="dept" class="com.atguigu.spring5.bean.Dept"> <property name="dname" value="财务部"></property> </bean>
4)xml 注入集合属性
public class Stu {
//1 数组类型属性
private String[] courses;
//2 list 集合类型属性
private List<String> list;
//3 map 集合类型属性
private Map<String,String> maps;
//4 set 集合类型属性
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>java 课程</value>
<value>数据库课程</value>
</array>
</property>
<!--list 类型属性注入-->
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<!--map 类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--set 类型属性注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
在集合里面设置对象类型值
<bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="Spring5框架"></property>
</bean>
<bean id= "course2" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="MyBatis框架"></property>
</bean>
<!--注入 list 集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
把集合注入部分提取出来
(1)在 spring 配置文件中引入名称空间 util

(2)使用 util 标签完成 list 集合注入提取
<!--1 提取 list 集合类型属性注入-->
<util:list id= "bookList">
<value>易筋经</value>
<value>九阴真经</value>
<value>九阳神功</value>
</util:list>
<!--2 提取 list 集合类型属性注入使用-->
<bean id="book" class="com.atguigu.spring5.collectiontype.Book">
<property name="list" ref="bookList"></property>
</bean>
2、IOC 操作Bean管理(FactoryBean )
Spring 有两种类型 bean ,一种普通 bean ,另外一种工厂 bean (FactoryBean )
- 普通 bean :在配置文件中定义 bean 类型就是返回类型
- 工厂 bean :在配置文件定义 bean 类型可以和返回类型不一样
实现方式:
- 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
- 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class MyBean implements FactoryBean<Course> {
//定义返回 bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname( "abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
</bean>
测试
@Test
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext( "bean3.xml");
Course course = context.getBean( "myBean", Course. class);
System. out .println(course);
}
3、IOC操作Bean管理(bean作用域)
在 Spring 里面,默认情况下,bean 是单实例对象


如何设置单实例还是多实例
在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
- singleton,默认值,表示是单实例对象
- prototype,表示是多实例对象

singleton 和 prototype 区别
设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,在调用
getBean 方法时候创建多实例对象
4、IOC 操作 Bean 管理(bean 生命周期)
1. 生命周期
(1)从对象创建到对象销毁的过程
2. bean 生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
3. 演示 bean 生命周期
public class Orders {
private String oname;
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建bean实例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
<bean id= "orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
@Test
public void testBean3() {
// ApplicationContext 无 close方法
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean( "orders", Orders.class);
System.out.println("第四步 获取创建bean实例对象");
System.out.println(orders);
//手动让 bean 实例销毁
context.close();
}

4. bean 的后置处理器,bean 生命周期有七步
- 通过构造器创建 bean 实例(无参数构造)
- 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
- 调用 bean 的初始化的方法(需要进行配置初始化的方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
- bean 可以使用了(对象获取到了)
- 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
实现步骤:
(1)创建类,实现接口 BeanPostProcessor,创建后置处理器
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
(2)配置后置处理器
<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>

5、IOC操作Bean管理(xml 自动装配)
自动装配:根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
演示自动装配过程:
(1)根据属性名称自动注入 byName
注入值 bean 的 id 值和类属性名称一样
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
(2)根据属性类型自动注入 byType,使用这种方式注入只能有一个该类型的bean,否则spring不知道该注入哪一个
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
6、IOC操作Bean管理(外部属性文件)
1、直接配置数据库信息
(1)配置德鲁伊连接池
(2)引入德鲁伊连接池依赖 jar 包

<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value ="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
2、引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties 格式文件,写数据库信息

(2)把外部 properties 属性文件引入到 spring 配置文件中
引入 context 名称空间

(3)在 spring 配置文件使用标签引入外部属性文件
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
7、IOC 操作 Bean 管理(基于注解方式)
1)什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
2)Spring 针对 Bean 管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
上面四个注解功能是一样的,都可以用来创建 bean 实例
3)基于注解方式实现对象创建
第一步 引入依赖
![]()
第二步 开启组件扫描
- 如果扫描多个包,多个包使用逗号隔开
- 扫描包上层目录
<context:component-scan base-package="com.atguigu"></context:component-scan>
第三步 创建类,在类上面添加创建对象注解
在注解里面 value 属性值可以省略不写,默认值是类名称,首字母小写
@Component(value = "userService") //<bean id="userService" class=".."/>
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
4)开启组件扫描细节配置
示例一
use-default-filters="false" 表示现在不使用默认filter,自己配置 filter
context:include-filter:设置扫描哪些内容
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
上面配置的意思是:只扫描com.atguigu包下带注解@Controller的类,别的类不扫描
示例二
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
使用默认的filter,但是不扫描com.atguigu包下带注解@Controller的类
5)基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
(2)@Qualifier:根据名称进行注入
@Qualifier(value = "userDaoImpl1")
private UserDao userDao;
(3)@Resource:可以根据类型注入,可以根据名称注入
①根据类型进行注入
@Resource
private UserDao userDao;
②根据名称进行注入
@Resource(name = "userDaoImpl1")
private UserDao userDao;
(4)@Value:注入普通类型属性
@Value(value = "abc")
private String name;
6)完全注解开发
(1)创建配置类,替代 xml 配置文件
@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
(2)加载配置类,使用AnnotationConfigApplicationContext
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",UserService.class);
System.out.println(userService);
}
四、Spring AOP
1、什么是AOP
(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
(3)使用登录例子说明 AOP

2、AOP 底层原理
AOP 底层使用动态代理,有两种情况动态代理
(1)有接口情况,使用 JDK 动态代理
创建接口实现类代理对象,增强类的方法

(2)没有接口情况,使用 CGLIB 动态代理
创建子类的代理对象,增强类的方法

3、AOP 术语
1)连接点
类里面哪些方法可以增强,这些方法成为连接点。
2)切入点
实际被真正增强的方法,称为切入点。
3)通知增强
1)实际增强的逻辑部分称为通知(增强)
2)通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
4)切面
把通知应用到切入点的过程
4、AOP操作
1)切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(..))
举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (..))举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))
2)AOP 操作(AspectJ 注解)
① 创建类,在类里面定义方法
public class User {
public void add() {
System. out .println( "add.......");
}
}
② 创建增强类(编写增强逻辑)
public class UserProxy {
public void before() { //前置通知
System. out .println( "before......");
}
}
③ 进行通知的配置
1.在 spring 配置文件中,开启注解扫描
<context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>2.使用注解创建 User 和 UserProxy 对象
3. 在增强类上面添加注解 @Aspect
@Component @Aspect //生成代理对象 public class UserProxy { }4.在 spring 配置文件中开启生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
④ 配置不同类型的通知
在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Component
@Aspect
public class UserProxy {
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void before() {
System.out.println("before.........");
}
//后置通知(返回通知)
@AfterReturning(value = "execution(*com.atguigu.spring5.aopanno.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning.........");
}
//最终通知
@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void after() {
System.out.println("after.........");
}
//异常通知
@AfterThrowing(value = "execution(*com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
//环绕通知
@Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前 .........");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后 .........");
}
}
⑤ 相同的切入点抽取
@Component
@Aspect
public class UserProxy {
//相同的切入点抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointDemo(){
}
@Before(value = "pointdemo()")
public void before() {
System.out.println( "before.........");
}
}
⑥有多个增强类多同一个方法进行增强,设置增强类优先级
在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class UserProxy{
}
⑦ 完全使用注解开发
创建配置类,不需要创建 xml 配置文件
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true) //开启生成代理类对象
public class ConfigAop {
}
3)AOP 操作(AspectJ 配置文件)
创建两个类,增强类和被增强类,创建方法。
在 spring 配置文件中创建两个类对象
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
在 spring 配置文件中配置切入点
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
五、Spring 事务操作
1、基本介绍
1)事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)
2)在 Spring 进行事务管理操作有两种方式:编程式事务管理和声明式事务管理(使用)
3)声明式事务管理
- 基于注解方式 (使用)
- 基于 xml 配置文件方式
4)在 Spring 进行声明式事务管理,底层使用 AOP 原理
5)Spring 事务管理 API:提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

2、事务操作(注解声明式事务管理)
在 spring 配置文件配置事务管理器
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testrewriteBatchedStatements=true"/>
<property name="username" value="root"/>
<property name="password" value="12345/>
</bean>
<!--创建事务管理器-->
<bean id="transactionManager"class= "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
在 spring 配置文件,开启事务注解
(1)在 spring 配置文件引入名称空间 tx

(2)开启事务注解
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
(3)在 service 类上面或者 (service类里面方法上)添加事务注解
@Transactional,这个注解添加到类上面,也可以添加方法上面,如果把这个注解添加类上面,这个类里面所有的方法都添加事务,如果把这个注解添加方法上面,为这个方法添加事务。
@Service
@Transactional
public class UserService {
}
3、事务操作(声明式事务管理参数配置)
在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

1)propagation :事务传播行为


2)ioslation:事务隔离级别
有三个读问题:脏读、不可重复读、虚(幻)读
脏读:一个未提交事务读取到另一个未提交事务的数据

不可重复读:一个未提交事务读取到另一提交事务修改数据
虚读:一个未提交事务读取到另一提交事务添加数据
解决:通过设置事务隔离级别,解决读问题

3)timeout :超时时间
事务需要在一定时间内进行提交,如果不提交进行回滚,默认值是 -1 ,设置时间以秒单位进行计算。
4)readOnly :是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
5)rollbackFor :回滚
设置出现哪些异常进行事务回滚
6)noRollbackFor :不回滚
设置出现哪些异常不进行事务回滚
4、使用配置类替代 xml
@Configuration
@ComponentScan(basePackages = {"dao","service"})
@EnableTransactionManagement //开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true");
dataSource.setUsername("root");
dataSource.setPassword("12345");
return dataSource;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
本文详细介绍了Spring框架的核心特性,包括控制反转(IOC)和面向切面编程(AOP)。讲解了IOC容器的实现、Bean的管理(如属性注入、作用域、生命周期)以及基于XML和注解的配置方式。此外,还阐述了Spring的事务操作,包括声明式事务管理的基本概念和配置。内容深入浅出,适合初学者和进阶者学习。



3. 在增强类上面添加注解 @Aspect
505

被折叠的 条评论
为什么被折叠?



