狂神说Spring
Spring简介
- SSH : Struct2 + Spring + Hibernate!
- SSm : SpringMVC + Spring + Mybatis!
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
引入maven
1 | <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> |
Spring的组成和拓展
组成

拓展
- Spring Boot
- 一个快速开发的脚手架
- 基于Spring Boot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- Spring Cloud是基于Spring Boot实现的。
弊端:人称“配置地狱”。
IOC理论推导
控制反转思想
1 | private UserDao userDao; |
这种思想大大降低系统的耦合性,可以更加专注的在业务的实现上,这就是IOC的原型。
HelloSpring
IOC本质

xml配置骨架
1 |
|
IOC创建对象方式
默认无参构造
有参构造实现方式
1 | <!-- 直接通过参数名赋值--> |
总结
结论:在配置文件加载的时候。其中管理的对象都已经初始化了!
Spring配置说明
别名
1 | <!-- 别名 如果添加了别名 我们也可以用别名获取到这个对象--> |
bean的配置
1 | <!-- |
import
团队的合作通过import来实现
1 | <import resource="beans.xml"/> |
DI依赖注入环境
概念
- 依赖注入(Dependency Injection,DI)。
- 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
- 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .
构造器注入
我们在之前的案例已经讲过了
Set 注入 (重点)
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没 有set方法 , 是 is .
测试pojo类 :
Address.java
1 | public class Address { |
Student.java
1 | package com.kuang.pojo; |
常量注入
1 | <bean id="student" class="com.kuang.pojo.Student"> |
Bean注入
1 | <bean id="addr" class="com.kuang.pojo.Address"> |
注意点:这里的值是一个引用,ref
数组注入
1 | <bean id="student" class="com.kuang.pojo.Student"> |
List注入
1 | <property name="hobbys"> |
Map注入
1 | <property name="card"> |
set注入
1 | <property name="games"> |
Null注入
1 | <property name="wife"><null/></property> |
Properties注入
1 | <property name="info"> |
测试结果:

p命名和c命名注入
P命名空间注入 : 需要在头文件中加入约束文件
1 | 导入约束 : xmlns:p="http://www.springframework.org/schema/p" |
c 命名空间注入 : 需要在头文件中加入约束文件
1 | 导入约束 : xmlns:c="http://www.springframework.org/schema/c" |
把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!
Bean的作用域

单例模式
1 | <!-- 设置作用域为单例,默认模式--> |
原型模式
1 | <bean id="user2" class="com.kuang.pojo.User" c:age="16" c:name="框线" scope="prototype"/> |
每次从容其中get都会产生新对象
其余的request、session、application,这些只能在web开发中使用到。
自动装配Bean
- 自动装配是Spring满足Bean依赖的一种方式
- spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
-
在xml中显式配置;
-
在java中显式配置;
-
隐式的bean发现机制和自动装配。
ByName自动装配
1
2
3
4
5
6<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog222" class="com.kuang.pojo.Dog"/>
<!-- byName 会自动在容器上下文查找,和自己set方法后面的值对应的beanid-->
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="狂神"/>
</bean>ByType自动装配
1
2
3
4
5
6
7
8<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog222" class="com.kuang.pojo.Dog"/>
<!-- byName 会自动在容器上下文查找,和自己set方法后面的值对应的beanid
byType 会自动在容器上下文查找,类型相同的beanid
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="狂神"/>
</bean>- ByName时,需保证所有bean的id唯一
- ByType时,需保证所有bean的类型唯一
使用注解自动装配

要使用注解须知:
-
导入约束
1
xmlns:context="http://www.springframework.org/schema/context"
-
配置注解支持
1
2
3
4
5
6
7
8
9
10
11
12
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
直接在属性上使用即可!也可使用在set方法上
现在set方法可以省略,因为注解基于反射实现。前提是你这个自动装配的属性在Spring容器中存在,且符合ByName
科普
1 | public Autowired { |
1 | public class People { |
@Qualifier
- @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
- @Qualifier不能单独使用。
-
配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!
1
2
3
4<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/> -
在属性上添加Qualifier注解
1
2
3
4
5
6
private Cat cat;
private Dog dog;
@Resource
- 更高级,会自动ByName查询,之后进行类型自动注入,也可以通过那么属性指定bean的id
- @Resource和@Autowired都是用来自动装配的,都可以放在属性字段上
- @Autowired通过byType的方式实现
- @Resource默认通过byname实现,如果找不到名字,就通过byType的方式实现,如果两个都找不到,才报错。
- @Resource和@Autowired执行顺序不同,@Autowired通过byType的方式实现
Spring注解开发
在spring4之后,想要使用注解形式,必须得要引入aop的包

在配置文件当中,还得要引入一个context约束
1 |
|
属性注入
1 |
|
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
- @Controller:web层
- @Service:service层
- @Repository:dao层
写上这些注解,就相当于将这个类交给Spring管理装配了!
作用域
@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
1 |
|
xml与注解整合开发 :推荐最佳实践
- xml管理Bean
- 注解完成属性注入
使用JavaConfig实现配置
基于Java类进行配置
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版 本, JavaConfig 已正式成为 Spring4 的核心功能 。
新建一个config配置包,编写一个MyConfig配置类
1 | package com.kuang.config; |
静态代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!
代理模式的分类:
- 静态代理
- 动态代理

角色分析:
- 抽象角色:一般会使用接口或者抽象类
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
代码实现
Rent . java 即抽象角色
1 | //抽象角色:租房 |
Host . java 即真实角色
1 | //真实角色: 房东,房东要出租房子 |
Proxy . java 即代理角色
1 | //代理角色:中介 |
Client . java 即客户
1 | //客户类,一般客户都会去找代理! |
代理模式的好处
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情
- 公共的业务由代理来完成 . 实现了业务的分工
- 公共业务发生扩展时变得更加集中和方便
缺点 :
一个类对应一个代理类,工作量翻倍,解决方法就是动态代理!
动态代理详解
- 动态代理的角色和静态代理的一样 .
- 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理–cglib
- 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
需要了解两个类
-
Proxy :代理

-
InvocationHandler:调用处理程序

万能模板
代理处理类:
1 | package com.kuang.demo04; |
测试类
1 | package com.kuang.demo04; |
AOP实现方式一
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序 功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要 内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各 部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

以下名词需要了解下:
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注 的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。 连接点(JointPoint):与切入点匹配的执行点。

使用Spring实现Aop
【重点】使用AOP织入,需要导入一个依赖包!
1 | <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> |
第一种方式
首先编写我们的业务接口和实现类
1 | public interface UserService { |
1 | public class UserServiceImpl implements UserService{ |
然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
1 | public class Log implements MethodBeforeAdvice { |
1 | public class AfterLog implements AfterReturningAdvice { |
最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
1 |
|
测试
1 | public class MyTest { |
AOP实现方式二
第二种方式 自定义类来实现Aop
目标业务类不变依旧是userServiceImpl
第一步 : 写我们自己的一个切入类
1 | public class DiyPointcut { |
去spring中配置
1 | <!--第二种方式自定义实现--> |
AOP方式二从零实现
-
导入maven依赖
1
2
3
4
5<!--AOP织入依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency> -
自定义切面类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package com.backstage.log;
/**
* 操作日志切面类
*
* @ClassName OperateLogAspect
* @Author Alfa
* @Data 2022/6/9 11:35
* @Version 1.0
**/
public class OperateLogAspect {
public void before() {
System.out.println("==========before============");
}
public void after() {
System.out.println("===========after=============");
}
} -
配置applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置要代理的类-->
<bean id="userService" class="com.backstage.service.impl.UserServiceImpl"/>
<!--自定义切面,ref要引用的类-->
<bean id="logAspect" class="com.backstage.log.OperateLogAspect"/>
<aop:config>
<aop:aspect ref="logAspect">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.backstage.service.impl.StaffServiceImpl.updatePassword(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans> -
测试类
1
2
3
4
5
6
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.login(new User());
}
注解实现AOP
第三种方式 使用注解实现
第一步:编写一个注解实现的增强类
1 | package com.kuang.config; |
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
1 | <!--第三种方式:注解实现--> |
注解方式从零实现
-
配置applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置注解实现aop-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans> -
切面类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27/**
* 操作日志切面类
*
* @ClassName OperateLogAspect
* @Author Alfa
* @Data 2022/6/9 11:35
* @Version 1.0
**/
public class OperateLogAspect {
public void around(ProceedingJoinPoint pj) throws Throwable {
//获取当前登录用户
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session=attr.getRequest().getSession(true);
Staff user = (Staff)session.getAttribute("staff");
System.out.println(user);
//获取方法所在包
System.out.println("==========before============");
String methodName = pj.getSignature().getName();
System.out.println(methodName);
Object o = pj.proceed();
System.out.println(o);
System.out.println("===========after=============");
}
}
回顾Mybatis
-
导入jar包
-
junit
-
mybatis
-
mysql数据库
-
spring相关的
-
aop织入
-
mybatis-spring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency> -
-
编写配置
-
配置Maven静态资源过滤问题!
1
2
3
4
5
6
7
8
9
10
11
12<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
-
-
测试
整合mybatis方式一
mybatis-config.xml
1 |
|
spring-dao.xml
1 |
|
applicationContext.xml
1 |
|
测试
1 |
|
整合mybatis方式二
mybatis-spring1.2.3版以上的才有这个 .
官方文档截图 :
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要 管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看

实现步骤
-
将我们上面写的UserMapperImpl修改一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* TODO
*
* @ClassName UserMapperImpl2
* @Author Alfa
* @Data 2022/6/10 12:46
* @Version 1.0
**/
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> getAllUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.getAllUser();
}
} -
配置bean
1
2
3<bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean> -
测试
1
2
3
4
5
6
7
public void selectUser() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = (UserMapper) context.getBean("userMapper2");
List<User> user = userMapper.getAllUser();
System.out.println(user);
}
Spring中的事务管理
声明式事务管理
-
使用Spring管理事务,注意头文件的约束导入 : tx
1
2
3xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"> -
配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<!-- 配置声明式事务-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 结合AOP实现事务的织入-->
<!-- 配置事务的类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给那些方法配置事务-->
<!-- 配置事务的传播特性-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>


