# SpringStudy
**Repository Path**: Mr-Sponge/spring-study
## Basic Information
- **Project Name**: SpringStudy
- **Description**: 根据B站狂神教学视频学习-源代码
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-08-26
- **Last Updated**: 2024-09-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# SpringStudy
# 狂神说Spring笔记+源码
# Spring5学习
# Spring-Study
代码:https://github.com/Donkequan/Spring-Study
## 1. 简介
spring理念:是现有的技术更加容易使用,本身是一个大杂烩。
- SSH:Struct2 + Spring + Hibernate
- SSM: SpringMVC + Spring + Mybatis
官网: https://spring.io/projects/spring-framework#overview
官方下载: https://repo.spring.io/release/org/springframework/spring/
GitHub: https://github.com/spring-projects/spring-framework
[Spring Web MVC](https://mvnrepository.com/artifact/org.springframework/spring-webmvc) **»** [5.2.5.RELEASE](https://mvnrepository.com/artifact/org.springframework/spring-webmvc/5.2.5.RELEASE)
```xml
org.springframework
spring-webmvc
5.2.5.RELEASE
org.springframework
spring-jdbc
5.2.3.RELEASE
```
- spring是开源的免费的容器。
- spring是一个轻量级的,非入侵式的。
- 控制反转(IOC),面向切面编程 (AOP)。
- 支持事务处理,对框架整合的支持。
总结:spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
## 2.IOC理论
1. UserDao
2. UserDaoImp
3. UserSevice
4. UserServiceImp
在之前,用户的需求可能会影响原来的代码。
使用一个set。
```java
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
```
- 之前是主动创建对象,控制权在程序员手上。
- 使用set之后,是被动接受对象。
## 3. Hello Spring
pojo中
```java
package com.pzb.pojo;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/25 11:57
*/
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{\n" +
"\tstr = " + str +
"\n}";
}
}
```
resource中
```xml
```
test
```java
import com.hou.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
//获取spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象下能在都在spring·中管理了,我们要使用,直接取出来就可以了
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
```
bean = 对象
id = 变量名
class = new的对象
property 相当于给对象中的属性设值
核心用set注入
第一个文件中
```xml
```
## 4. IOC创建对象的方式
1. 使用无参构造创建对象,默认。
2. 使用有参构造
* 下标赋值
```xml
```
* 类型赋值(不建议使用)
```xml
```
* 直接通过参数名
```xml
```
Spring类似于婚介网站!
你想不想要,对象都在里面。注册bean之后用不用都被实例化。(这些类相当于项目的静态属性)
* 源码
beans.xml
```xml
```
MyTest.java
```java
import com.pzb.pojo.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/25 16:03
*/
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 无参构造
User user = (User) context.getBean("user");
System.out.println(user.toString()); // User{name='zhangsan'}
// 有参构造--下标方式
User user2 = (User) context.getBean("user2");
System.out.println(user2.toString()); // User{name='lisi'}
// 有参构造--类型方式 (不推荐,当有多个相同类型的就乱套了)
User user3 = (User) context.getBean("user3");
System.out.println(user3.toString()); // User{name='wangwu'}
// 有参构造--参数名方式 (推荐,理由:简单易懂)
User user4 = (User) context.getBean("user4");
System.out.println(user4.toString()); // User{name='laoliu'}
}
}
```
## 5. Spring配置
**别名**
```xml
```
> 别名可以重复,如果别名相同,会自动覆盖上一个数据。id不能重复,一旦重复就会报错
**bean的配置**
```xml
```
- id:bean的id标识符
- class:bean对象所对应的类型
- name:别名,更高级,可以同时取多个别名(多个别名用`,`、`;`或者空格进行分割)。
**import**
一般用于团队开发,它可以将多个配置文件,导入合并为一个
例如:张三用了`beans.xml`配置文件开发,李四用了`beans2.xml`配置文件开发,进行代码合并的时候可以合并成一个配置文件

创建一个`applicationContext.xml`配置文件,在文件中添加如下信息:
```xml
```
> 不过要注意以下 id 重复的问题,合并的文件允许重复,运行**不会报错**,重复的会被后面来的数据覆盖。
## 6. DI(Dependency Injection)依赖注入
**构造器注入**
就是上面,略
**set方式注入**(重点)
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
【环境搭建】
1. 复杂类型
2. 真实测试对象
Student.java
```java
package com.pzb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/25 16:53
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private Address address;
private String[] books;
private List hobbys;
private Map card;
private Set games;
private String wife;
private Properties info;
}
```
Address.java
```java
package com.pzb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/25 16:53
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Address {
private String address;
}
```
beans.xml
```xml
西游记
红楼梦
三国演义
听歌
敲代码
CF
Apex
123456
男
```
MyTest.java
```java
import com.pzb.pojo.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/25 17:00
*/
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
/*\
Student(
name=zhangsan,
address=Address(
address=广东
),
books=[西游记, 红楼梦, 三国演义],
hobbys=[听歌, 敲代码],
card={身份证=123456789, 银行卡=123456789},
games=[CF, Apex],
wife=null,
info={学号=123456, 性别=男}
)
*/
}
}
```
> 学习感受:真tm麻烦啊
**第三方**
p标签和c标签
```java
@Test
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml");
User user = context.getBean("user", User.class);
System.out.println(user); // User(name=zhangsan, age=18)
User user2 = context.getBean("user2", User.class);
System.out.println(user2); // User(name=lisi, age=19)
}
```
> 注意:p、c命名不能直接引用,需要导入约束,不过一般IDEA有提示。
**bean的作用域**

* 单例模式(默认)
```xml
```
* 原型模式: 每次从容器中get的时候,都产生一个新对象!
```xml
```
MyTest.java
```java
@Test
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml");
User user = context.getBean("user", User.class);
System.out.println(user); // User(name=zhangsan, age=18)
User user1 = context.getBean("user", User.class);
System.out.println(user == user1); // false
}
```
* 其余的request、session、application这些只能在web开放中使用!
> 思考:单例和原型模式都有哪些好处
## 7. Bean的自动装配
- 自动装配是Spring是满足bean依赖的一种方式
- Spring会在上下文自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
1. 在xml中显示配置
2. 在java中显示配置
3. 隐式的自动装配bean 【重要】
4. 环境搭建:一个人有两个宠物
```xml
```
5. Byname自动装配:byname会自动查找,和自己对象set对应的值对应的id
保证所有id唯一,**并且和set注入的值一致**
beans.xml
```xml
```
Test.java
```java
@Test
public void test1(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getCat().shout(); // 喵喵喵~~~
people.getDog().shout(); // java.lang.NullPointerException
}
```
> 由于autowire 的类型为byName ,beans.xml的配置文件中没有id为dog的配置信息,所以不能自动注入dog数据,报了空指针异常。
6. Bytype自动装配:byType会自动查找,和自己对象属性相同的bean
保证所有的class唯一
```java
public class Cat {
public void jiao(){
System.out.println("miao");
}
}
public class Dog {
public void jiao(){
System.out.println("wow");
}
}
package com.pojo;
public class People {
private Cat cat;
private Dog dog;
private String name;
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
**使用注解自动装配**
jdk1.5支持的注解,spring2.5支持的注解
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.
==导入context约束==
```xml
```
没有导入的xml文件
```xml
```
@Autowire
在属性上个使用,也可以在set上使用
我们可以不用编写`set`方法了
```java
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
@Nullable 字段标志的注解,说明这个字段可以为null
```
如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候
我们可以使用@Qualifier(value = "dog")去配合使用,指定一个**唯一的id**对象
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
private String name;
// 如果定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private Dog dog;
@Autowired
@Qualifier(value = "cat11")
private Cat cat;
}
```
@Resource(name="dog")也可以(这是java自带的注解)
区别:
- @autowire通过byType实现,而且必须要求这个对象存在
- @resource默认通过byName实现,如果找不到,通过byType实现,如果都找不到就会报错
## 8. 使用注解开发
在spring4之后,必须要保证aop的包导入
使用注解需要导入contex的约束
```xml
```
1. 类的注解
```java
@Component // 等价于
public class User {
public String name;
}
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
}
```
2. 属性如何注入:@Value
```java
@Component // 等价于
public class User {
@Value("zhangsan")
public String name;
public Integer age;
@Value("18") // @Value不仅可以给属性赋值,还可以给方法参数赋值
public void setAge(Integer age){
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
```
3. 衍生的注解
@Component有几个衍生注解,会按照web开发中,mvc架构中分层。
- dao (@Repository)
- service(@Service)
- controller(@Controller)
这四个注解功能一样的,都是代表将某个类注册到容器中
4. 作用域
@Scope("singleton")
```java
@Component
@Scope("prototype")
public class User {
@Value("dong")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
小结:
xml与注解
- xml更加万能,维护简单
- 注解,不是自己的类,使用不了,维护复杂
最佳实践:
- xml用来管理bean
- 注解只用来完成属性的注入
```xml
```
## 9. 使用java方式配置spring
JavaConfig
Spring的一个子项目,在spring4之后,他成为了核心功能
MyConfig.java
```java
package com.pzb.config;
import com.pzb.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @Description TODO
* @Author zbpeng
* @DATE 2024/8/26 11:26
*/
@Configuration // 这个也会被spring容器托管,注册到容器中,因为他本来就是一个@Component,@Configuration代表这是一个配置类,就和我们之前看的beans.xml一样 (具体可以点进去看看源码)
// 既然@Configuration相当于beans.xml,那它也可以支持扫描类功能
@ComponentScan("com.pzb.pojo")
// 那他也支持多个“beans.xml”合并的功能
@Import(MyConfig2.class)
public class MyConfig {
// 注册一个bean,就相当于之前的 bean 标签,id为这个方法的名字,class为这个方法的返回值
@Bean
public User getUser(){
return new User(); // 返回的就是要注入到bean的对象
}
}
```
User.java
```java
public class User {
public String name;
public String getName() {
return name;
}
@Value("zhangsan")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
```
MyConfig2.java
```java
@Configuration
public class MyConfig2 {
}
```
MyTest.java
```java
public class MyTest {
public static void main(String[] args) {
// 通过配置类加载bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
// 通过配置类下的方法名进行调用bean
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser.toString());
}
}
```
这种纯java配置方式
在springboot中,随处可见
## 10. 动态代理
动态代理和静态代理
角色一样
动态代理类是动态生成的,不是我们直接写好的!
动态代理:基于接口,基于类
- 基于接口:JDK的动态代理【使用】
- 基于类:cglib
- java字节码
InvocationHandler
Proxy
```java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//会这个类,自动生成代理类
public class ProxyInvocation implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rent, args);
fare();
return result;
}
public void seeHouse(){
System.out.println("see house");
}
public void fare(){
System.out.println("fare");
}
}
public interface Rent {
void rent();
}
public class Host implements Rent {
public void rent() {
System.out.println("host rent");
}
}
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocation proxyInvocation = new ProxyInvocation();
//通过调用程序处理角色来处理我们要调用的接口对象
proxyInvocation.setRent(host);
Rent proxy = (Rent) proxyInvocation.getProxy(); //这里的proxy是动态生成的
proxy.rent();
}
}
```
## 11.AOP
```xml
org.aspectj
aspectjweaver
1.9.4
```
方法一:使用spring接口【springAPI接口实现】
```xml
public class UserServiceImp implements UserService {
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void query() {
System.out.println("query");
}
public void update() {
System.out.println("update");
}
}
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//args:参数
//target:目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+method.getName());
}
}
public class AfterLog implements AfterReturningAdvice {
//returnVaule: 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+returnValue);
}
}
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplcationContext.xml");
//动态代理代理的是接口
UserService userService = (UserService) context.getBean("userservice");
userService.add();
}
}
```
方法二:自定义来实现AOP【主要是切面定义】
```xml
public class DiyPointcut {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
```
方法三:注解方式
```xml
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这个类是一个切面
public class Annotation {
@Before("execution(* com.service.UserServiceImp.*(..))")
public void before(){
System.out.println("before");
}
@After("execution(* com.service.UserServiceImp.*(..))")
public void after(){
System.out.println("after");
}
//在环绕增强中,我们可以给地暖管一个参数,代表我们要获取切入的点
@Around("execution(* com.service.UserServiceImp.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around");
Object proceed = joinPoint.proceed();
System.out.println("after around");
}
}
```
## 12. 整合mybatis
文档: https://mybatis.org/spring/zh/
```xml
spring-study
com.hou
1.0-SNAPSHOT
4.0.0
spring-10-mybatis
mysql
mysql-connector-java
5.1.47
org.mybatis
mybatis-spring
2.0.4
org.springframework
spring-jdbc
5.2.3.RELEASE
org.mybatis
mybatis
3.5.2
org.aspectj
aspectjweaver
1.9.4
org.projectlombok
lombok
1.18.12
src/main/resources
**/*.properties
**/*.xml
src/main/java
**/*.properties
**/*.xml
true
public interface UserMapper {
List selectUser();
}
```
整合
方法一:
![1586177510119]()
UserMapperImpl
```java
package com.mapper;
import com.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
public List selectUser() {
UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
```
mybatis.xml
```xml
```
spring.xml
```xml
```
test
```java
import com.mapper.UserMapper;
import com.pojo.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Mytest {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
```
方法二:
```xml
package com.mapper;
import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperIml2 extends SqlSessionDaoSupport implements UserMapper {
public List selectUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
```
## 13. 声明式事务
- 要么都成功,要么都失败
- 十分重要,涉及到数据一致性
- 确保完整性和一致性
事务的acid原则:
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响。
Spring中的事务管理
- 声明式事务
- 编程式事务
声明式事务
```xml
```
Mapper
```java
package com.mapper;
import com.pojo.User;
import java.util.List;
public interface UserMapper {
List selectUser();
int addUser(User user);
int delete(int id);
}
insert into mybatis.user (id, name, pwd) values
(#{id}, #{name}, #{pwd})
delete from mybatis.user where id=#{id}
package com.mapper;
import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperIml2 extends SqlSessionDaoSupport implements UserMapper {
public List selectUser() {
User user = new User(6, "long", "zhi");
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
mapper.delete(6);
return mapper.selectUser();
}
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
public int delete(int id) {
return getSqlSession().getMapper(UserMapper.class).delete(id);
}
}
```