Spring
1.Spring
1.1 简介

-
下载spring所有版本信息的地址入口:https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/
-
下载spring所有版本信息的地址:http://repo.spring.io/release/org/springframework/spring
-
导入spring-webmvc,可以快速一次性导入所有java包)
1 2 3 4 5 6<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> -
导入spring web jdbc
1 2 3 4 5 6<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.3</version> </dependency>
1.2 优点
- 开源的免费容器
- 轻量级,非入侵式的框架(引入不会对原来的代码产生任何影响)
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
spring就是一个轻量级的控制反转和面向切面编程的框架
1.3 组成

1.4 学习路线

SpringBoot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- 要先学Spring和SpringMVC
SpringCloud
- 基于SpringBoot实现的
2.坑
-
多态父类实现子类独有的方法需要向下强转
-
1public static void main(String[] args){}可以由快捷键psvm加回车打出来
-
无参构造函数,只要一new就会执行
-
只要有new一定要写在main方法里
3.IOC DI
3.1 理论推导(依赖注入:set注入)
|
|
- 之前程序是主动创建对象!控制权在程序员手上
- 使用set注入后,程序不再具有主动性,而是变成了被动的接受对象
- 这种思想从本质上解决了问题,我们程序员不用再去管理对象的创建了
3.2 IOC本质
是一种通过描述(XML或注解)并通过第三方生产或获取特定对象的方式,在spring中实现控制反转的是Ioc容器,其实现方法是依赖注入(DI)
3.3 IOC容器(控制反转)
-
配置文件
- xml中的bean标签就是一个对象,把类用bean标签添加在配置文件中,就相当于:类名 变量名=new 类名(),而标签中的id就是变量名,class就等于new的对象。所以myHello就是一个Hello类对象。这里的对象是由spring创建的,而不是java new出来的。
- property相当于给对象中的基本数据类型的属性设置一个值(注意!!!,类中一定要有:set属性名(参数类型 参数值){this.属性名=参数值} 这个方法
1 2 3<bean id="myHello" class="com.kua.pojo.Hello"> <property name="str" value="spring"/> </bean>- property如果要给对象中的对象数据设置值,那就是
<property name="userDao" ref="mySql"/>其中name表示对象属性名,表示引用spring中创建好的对象
1 2 3<bean id="myServiceImpl" class="com.kuang.service.UserServiceImpl"> <property name="userDao" ref="mySql"/> </bean> -
初始化时,先读取配置文件,获得spring的上下文对象(固定语句不可变)
1ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");//这里的bean.xml是配置文件名 -
通过上下文对象context的getBean方法从Ioc容器中直接取出对象
1Hello myHello=(Hello)context.getBean("hello");
3.4 IOC综合
-
控制:谁来控制对象的创建,传统的应用程序是由程序本身来控制创建的,使用Spring后,对象是由Spring创建的
-
反转:程序本身不创建对象,而变成被动的接收对象
-
依赖注入:利用set方法进行注入
-
IOC编程思想:由主动编程,变成被动接收,对象由Spring来创建,管理,装配
3.5 IOC创建对象的方式(依赖注入:构造器注入)
使用构造器方式注入可以不写set
-
使用无参构造创建对象(默认的)
-
如果要用有参构造函数创建对象
方式一:下标赋值
1 2 3<bean id="user" class="com.kuang.pojo.User"> <constructor-arg index="0" value="renzuoweishihanhan"/> </bean>index表示参数的下标,value表示给参数赋值
方式二:匹配参数类型(不建议使用)
1 2 3<bean id="user" class="com.kuang.pojo.User"> <constructor-arg type="java.lang.String" value="renzuoweishihanhan"/> </bean>
注意:基本类型可以直接写,但是引用类型如:String得写全名
方式三:直接通过参数名
|
|
3.6 IOC初始化对象的时间
在new ClassPathXmlApplicationContext,即加载完配置文件后就已经初始化好了所有bean对象,然后你需要getBean谁就取谁
4.Spring配置
4.1 Spring配置
-
alias,给bean对象取别名(一对一)
给容器中的东西取别名
1<alias name="user" alias="user2"/> -
bean配置
-
id:bean的唯一标识符
-
class:bean对象所对应的全限定名(包+类)
-
name:给bean对象取别名,可以同时取多个别名,中间可以用逗号、空格、分号隔开
-
import:一般用于团队开发使用,他可以将多个文件导入合并为一个
用import可以导入这个模块的其他bean文件,合并为一个总的,然后通过总的xml文件可以取到所有导入的bean里面的东西,如果不同bean中有相同的配置,但是配置的值不同,则下面的xml文件会覆盖上面的
-
5.DI依赖注入之set注入
5.1、依赖注入之set注入
依赖:bean对象的创建依赖于容器
注入:bean对象的所有属性值由容器注入
复杂类型:
|
|
真实测试对象:
|
|
bean4.xml
|
|
测试类:
|
|
6.导入test测试包(junit)
6.1、导入test测试包
|
|
然后在测试类中@Test,这样在测试类中写出的方法,会自动被执行
7.c命名和p命名空间注入
7.1、命名空间
p命名空间的注入,可以直接注入属性的值:property(本质还是set注入)
-
前提:
- 导入约束xmlns:p=“http://www.springframework.org/schema/p"
- 要有set方法
-
1<bean id="user" class="com.kuang.pojo.User" p:age="18" p:name="yzq"/>可以直接在bean标签内注入属性的值
如果是注入对象则:

-
导入junit,并在测试文件中@Test(插曲)
c命名空间(本质是构造器注入)
-
前提:
- 导入约束
|
|
- 要有set方法
- 必须要有无参构造函数和有参构造函数两种
-
1<bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="nihao"/> -
测试:
1 2 3 4 5 6@Test public void test2(){ ApplicationContext context=new ClassPathXmlApplicationContext("beans4.xml"); User user=context.getBean("user",User.class); System.out.println(user); };
8.Bean Scopes(bean作用域)
8.1、bean作用域

- 单例模式singleton(Spring默认机制)

对象只有一个,不管从相同的bean对象中getBean多少个对象,都是表示同一个对象,如下:输出true
用法:在bean的后面加上scope=“singleton”,也可以不加,因为这种作用域是spring默认的
|
|
|
|
- 原型模式prototype

用法:scope=“prototype”
每次从容器中get时都会产生新对象,每个对象都不一样
|
|
输入false
- 其他四个只能在web开发中使用
9.bean的自动装配(Autowired)
9.1、bean自动装配
Spring会在上下文中自动寻找,并自动给bean装配属性,只针对bean对象
在Spring中有三种装配方式:
- 在xml中显示的配置
- 在java中显示的配置
- 隐式的自动装配bean(重要)
自动装配就是:可以不用在bean中自己手动装备bean对象的对象属性,也就是不用property来为对象中的对象引用赋值,但是只针对对象属性
用法:用autowired=““实现
People.java
|
|
bean5.xml
|
|
byName表示在容器上下文中查找和自己set方法后面的值对应的beanid,弊端:名字必须相同
byType表示在容器上下文中查找和自己set方法中对象类型相同的对应的beanid,都可以省略id。弊
端:容器中所有bean的class唯一,即只有一个对象,如下就会报错
|
|
10.使用注解实现自动装配
10.1 @Autowired
可以删掉set方法,但是需要get方法!!!
前提:只针对bean对象,通过byType方式实现,如果有多个对象,就通过byName方式实现
-
导入约束
1xmlns:context="http://www.springframework.org/schema/context" -
配置注解的支持
1 2<!--所有注解驱动--> <context:annotation-config/> -
容器中和.java中的名字要相同
使用:
在配置文件中注入所有你要自动装配的对象,然后直接在属性上面或者set方法上面使用@Autowired
bean5.xml
|
|
People.java
|
|
也可以放在set方法上面
10.2 @Nullable(拓展)
如果显示定义@Autowired的require属性为false,那么那个对象的属性值为null也不会报错(但是完全没有定义,只有声明,就会报错)
与这有相同效果的是@Nullable,用法:在构造函数的形参前面
|
|
10.3 @Qualifier
当容器中和.java中的对象名字和类型都不匹配时,这时@Autowired就没办法用,但如果又想要自动匹配,就可以使用@Qualifier(value=”")实现名字匹配
|
|
|
|
但是可能在运行前要去maven里clean一下,再运行
10.4 @Resource
以上三种都是Spring注解,这一个是java注解
@Resource与@Autowired用法一样,但是@Resource先通过byName,再通过byType
当名字和类型都不匹配时:加一个name属性可以指定名字匹配
@Resource(name=””)
10.5 @Component
见11的第2条的方法二
10.6 @Scope
见11的第5条
11.使用注解开发
- 在Spring4之后,要使用注解开发,必须保证aop的包导入,所以出错时检查这个包有没有问题
- 导入约束
- 增加支持
-
bean
-
属性如何注入(开启注解的支持)
方法一:
注解驱动
1<context:annotation-config/>方法二:
指定包中的全部注解都生效
1<context:component-scan base-package="com.kuang.pojo"/>用@Component注解:
放在类上面,表示 这个类被Spring管理了,就是一个bean,而@Value就相当于bean中的property,给属性(这里的属性,不只是对象,还包含基本数据类型的属性)注入值,@Value也可以放在set方法上面
1 2 3 4 5 6 7//相当于在配置文件中 //<bean id="user" class="com.kuang.pojo.User" /> @Component public class User { @Value("yzq") private String name; } -
衍生的注解
@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层
-
poji层:@Component
-
dao层:@Repository
-
service层:@Service
-
controller层:@Controller
这四个注解功能一样,都是讲某个类注入到容器中
-
-
自动装配置
以上所有注解
-
作用域
也可以使用注解:@Scope(“作用域类型”),也是放在类上面的
1 2 3 4 5@Component @Scope("prototype") public class User{ } -
小结
xml和注解:
- xml更加万能,适用于任何场所|维护简单方便
- 注解:不是自己的类使用不了,维护复杂,因为每个不同的类的注解是独立的
xml与注解最佳实践
- xml用来管理bean
- 注解只负责完成属性的注入
- 注意:一定要开启注解的支持
12.使用java方式配置Spring
12.1 用@Configuration配置过程
-
写一个类作为配置类,将@Configuration放在类上面,@Bean放在一个返回类的方法里面
@Configuration代表最这是一个配置类,和之前的bean.xml是一样的,本身也会被spring容器托管,注册到容器中,因为他本来就是一个@Component
@Bean代表bean,哪个类的bean就写一个返回类的方法,然后bean的id就是方法的方法名
配置类:
1 2 3 4 5 6 7 8@Configuration public class myConfig { @Bean public User getUser(){ //返回要注入到bean中的对象 return new User(); } } -
给bean中的属性注入值
1 2 3 4 5 6@Value("yzq") private String name; public String getName() { return name; } -
测试类:注意是用的AnnotationConfigApplicationContext实现类,因为没有配置文件xml了,完全是用java+注解配置的,实参是写的配置类,bean的id名是配置类中的方法名
1 2 3ApplicationContext context = new AnnotationConfigApplicationContext(myConfig.class); User getUser=(User) context.getBean("getUser"); System.out.println(getUser.getName());
12.2 @Configuration扫描
- 也可以显示的扫描包
|
|
- 因为肯定有多个bean,所以就根据几个bean创建几个java配置类,然后每个类上面都加上@Configuration,代表这是一个配置类但是要把这么多bean整合到一起,就要使用@Import(其他配置类名.class)
13.代理模式
13.1 代理模式

为什么学习代理模式?
因为这是SpringAOP的底层
13.2 静态代理
角色分析:
-
抽象角色(租房):一般会使用接口或者抽象类来解决
1 2 3public interface rent { public void rent(); } -
真实角色(房东):被代理的角色
1 2 3public void rent(){ System.out.println("房东要出租房子"); }; -
代理角色(中介):代理真实角色,代理真实角色后,一般会做一些附属操作(代理角色自己的方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25public class Proxy { public Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent(){ host.rent(); hetong(); see(); fee(); } public void hetong(){ System.out.println("中介带你签合同"); } public void see(){ System.out.println("中介带你看房"); } public void fee(){ System.out.println("中介带你付费"); } } -
客户(我):访问代理对象的人
1 2 3 4 5 6 7 8 9 10public class Client { public static void main(String[] args) { //房东只租房子 Host host =new Host(); //代理出来租房子还有一些附属操作 Proxy proxy=new Proxy(host); //不用面对房东,直接找中介即可 proxy.rent(); } }
好处:
- 可以使真实角色操作更纯粹,不用去关注一些公共的业务
- 公共也就交给代理角色!实现了业务的分工
- 公共业务发生拓展时,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率低
13.3 静态代理再理解
-
抽象角色
1 2 3 4 5 6public interface UserService { public void add(); public void delete(); public void update(); public void query(); } -
真实角色,实现增删改查四个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14public class UserServiceImpl implements UserService{ public void add(){ System.out.println("增"); }; public void delete(){ System.out.println("删"); }; public void update(){ System.out.println("改"); }; public void query(){ System.out.println("查"); }; } -
代理角色:现有客户需要在每次实现什么方法的时候,能够输出实现了什么方法,称为日志功能,这个时候如果去在真实角色的代码里面添加,就违反了”改动原有代码,在公司中是大忌“,所以这时候就需要代理去实现
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 27public class UserServiceProxy { private UserServiceImpl userServiceImpl; public void setUserServiceImpl(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } public void add(){ log("add"); userServiceImpl.add(); } public void delete(){ log("delete"); userServiceImpl.delete(); } public void update(){ log("update"); userServiceImpl.update(); } public void query(){ log("query"); userServiceImpl.query(); } public void log(String a){ System.out.println("实现了"+a+"方法"); } } -
客户:只需要跟代理角色接触,让代理角色去调用真实角色的各种方法
1 2 3 4 5 6 7 8public class Client { public static void main(String[] args) { UserServiceImpl userServiceImpl=new UserServiceImpl(); UserServiceProxy userServiceProxy=new UserServiceProxy(); userServiceProxy.setUserServiceImpl(userServiceImpl); userServiceProxy.add(); } }
13.4 聊聊AOP

AOP实现机制,就是不改变原有代码,增加代理角色,面向切面编程
13.5 动态代理详解
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK的动态代理
- 基于类:cglib
- java字节码实现(现在用的多的):javassist,javassist是一个开源的分析、编辑和创建java字节码的类库
前提:了解两个类
Proxy类:生成动态代理实例的,提供动态代理类和实例的静态方法
InvocationHandle:调用处理程序并返回一个结果的(调用处理程序实现的接口)
接口:
|
|
真实角色:
|
|
创建代理对象的类,ProxyInvocationHandle.java:
|
|
客户:
|
|
输出:

好处:
- 静态代理的优点全有
- 一个动态代理类代理的是一个接口,一般就是对应的一些业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口就可以
14.AOP
14.1 了解
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术,在不改变原来代码的基础上实现动态的增强

14.2 使用Spring实现Aop
前提:使用AOP织入,需要导入一个依赖包
|
|
14.2.1 方法一:使用原生Spring API接口(JDK)默认
- 此方法特点是,切入一个方法就要对应一个类
UserService接口
|
|
UserServiceImpl实现类
|
|
Log类:实现日志功能
|
|
AfterLog类:实现方法执行后,得知返回值功能
|
|
bean9.xml配置类
切入点表示要切入到哪里去,即实现接口的类中的方法要在哪里执行
执行环绕:表示把自定义类与切入点连接起来,对应起来,表示自定义类中的方法在对应的切入点处执行
|
|
测试类Test9.java
|
|
14.2.2 方法二:使用自定义类(CGLIB)
- 此方法的特点是:切入的所有方法都存在于一个类中,切入 多少个方法就对应多少个函数
切面表示引用哪个类,即哪个类里面有自定义的特定功能的方法,它就是一个类。切面中还要还要定义切入点(切面要引用到哪里去)和通知(是要切入切面类中的哪个方法,且切入到哪里去)
自定义切面类
|
|
bean9.xml
|
|
14.2.3 方法三:注解实现
与方法二原理一模一样,只是将xml换成注解
AnnotationPointCut自定义切面类:

注意选的是上面那个Before注解
|
|
配置文件
|
|
运行:

14.2.4 小结
后面设置为false,使用JDK支持,这也是默认的
设置为true,使用cglib支持
|
|
15.整合mybatis
15.1 回顾Mybatis
Mybatis过程:
- 导入相关jar包
-
junit
1 2 3 4 5<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> -
mysql
1 2 3 4 5<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> -
mybatis
1 2 3 4 5<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> -
spring-webmvc
1 2 3 4 5<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> -
spring-jdbc
1 2 3 4 5 6<!-- spring操作数据库的话,需要一个spring-jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> -
aspectjweaver:aop必导的包
1 2 3 4 5<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> -
mybatis-spring
1 2 3 4 5<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency>
-
编写配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="uchr@123"/> </dataSource> </environment> </environments> </configuration> -
测试

看到视频23的15:00
16.声明式事务
16.1 回顾事务
- 把一组业务当成一个业务来做,要么都成功要么都失败
- 涉及到数据的一致性问题
- 确保完整性和一致性
事务ACID原则
- 原子性:确保事务要么都成功要么都失败
- 一致性:事务完成后,要么都提交,要么就都不行,资源状态都要保持一致性
- 隔离性:多个业务操作同一个资源,防止数据损坏
- 持久性:事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中
