Spirng 痛苦源码学习(一)——总起spring(一)

news2025/2/25 4:28:34

文章目录

  • 前言
  • 一、总览Spring的bean
    • 1)bean的过程【先了解具体的生命周期后面弄】
    • 2)hello spring 简单bean操作
  • 二、总览AOP
    • - 1、test coding
    • - 2、- debug
    • - 3、- 总结debug
  • 三、总览事务
    • - 1、- test coding
    • - 2、 debugging
    • - 3、 事务失效
    • - 4、事务总结


前言

对于spring来说最重要的两个特性就是老生常谈的IOC和AOP,这两个大哥先放一放。那我就先其中的一个重要小零件Bean来说,来看看spring是对Bean进行多牛逼的管理

一、总览Spring的bean

1)bean的过程【先了解具体的生命周期后面弄】

=》1、Spring底层会调用类的构造方法完成对象创建
(这里先不管他是怎么拿到构造方法的,反正就是拿构造方法,默认是无参构造器。这里其实有一个推断构造方法的过程)

1 稍微解释一下构造方法推断

多个构造方法,直接报错(没有构造器被找到)
在这里插入图片描述

解决方法在你需要的构造器上加上@Autowired指定spring用;因为spring比较笨所以你要教他做事

2 Spring的设计思想是这样的:
  1. 如果一个类只有一个构造方法,那么没得选择,只能用这个构造方法
  2. 如果一个类存在多个构造方法,Spring不知道如何选择,就会看是否有无参的构
    造方法,因为无参构造方法本身表示了一种默认的意义
  3. 不过如果某个构造方法上加了@Autowired注解,那就表示程序员告诉Spring就
    用这个加了注解的方法,那Spring就会用这个加了@Autowired注解构造方法了
    需要重视的是,如果Spring选择了一个有参的构造方法,Spring在调用这个有参构造方法
    时,需要传入参数,那这个参数是怎么来的呢?
    Spring会根据入参的类型和入参的名字去Spring中找Bean对象(以单例Bean为例,
    Spring会从单例池那个Map中去找):
  4. 先根据入参类型找,如果只找到一个,那就直接用来作为入参
  5. 如果根据类型找到多个,则再根据入参名字来确定唯一一个
  6. 最终如果没有找到,则会报错,无法创建当前Bean对象
    确定用哪个构造方法,确定入参的Bean对象,这个过程就叫做推断构造方法。

=》 2、对象依赖注入(属性赋值)

=》 3、初始化前 ()

=》 4、初始化

=》 5、初始化后(AOP)

=》 5.1 代理对象【只有当有AOP织入的时候,才会产生代理对象】

=》 6、bean

:从源码的大的角度出发,就是先读取配置=》生成bean的定义信息(放到一个map里)=》按照bean的定义信息生成bean(也放到map里,要用的时候自取)

spring架构原理
在这里插入图片描述

2)hello spring 简单bean操作

  • 1、通过注解的方式

// 扫描该包下的所有组件

@ComponentScan("com.xusj")
public class AppConfig {

}

// 组件一、二如下

package com.xusj.future.service;

import org.springframework.stereotype.Service;

/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:59
 */
@Service
public class DogService {
}

// 这里有一个点值得我们在以后业务需求中可以使用,当项目一启动你要给对应的bean属性赋值,implements InitializingBean 重写afterPropertiesSet,在初始化bean的时候就直接赋值了

package com.xusj.future.service;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:58
 */
@Service
public class PeopleService implements InitializingBean {
	@Autowired
	private DogService dogService;

	private String initStr;


	public void testMethod() {
		System.out.println("111");
	}
	
	// 这里就是你想在bean创建的时候给他赋值implements InitializingBean
	@Override
	public void afterPropertiesSet() throws Exception {
		initStr = "直接在bean初始化的时候就创建了";
		System.out.println("在创建bean的时候自动和初始化一些值");
	}
}

// main 函数直接getBean

package com.xusj.future;

import com.xusj.future.bean.Person;
import com.xusj.future.config.AppConfig;
import com.xusj.future.service.PeopleService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author xusj
 * <br>CreateDate 2022/5/9 22:15
 */
public class MainTest {
	public static void main(String[] args) {
	// xml方式
//		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("bean1.xml");
//		Person bean = classPathXmlApplicationContext.getBean(Person.class);
//		System.out.println(bean);
	// 注释方式
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		PeopleService peopleService = (PeopleService) context.getBean("peopleService");
		peopleService.testMethod();

	}
}

  • 2、对于以上的一些代码我们放如下问题【希望学完,我自己能解决】
  1. 第一行代码,会构造一个ClassPathXmlApplicationContext对象,
    ClassPathXmlApplicationContext该如何理解,调用该构造方法除开会实例化得到
    一个对象,还会做哪些事情?
  2. 第二行代码,会调用ClassPathXmlApplicationContext的getBean方法,会得到
    一个UserService对象,getBean()是如何实现的?返回的UserService对象和我们自
    己直接new的UserService对象有区别吗?
  3. 第三行代码,就是简单的调用bean的test()方法,不难理解。

二、总览AOP

- 1、test coding

package com.xusj.future.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 切面bean 交给ioc管理
 *
 * @author xusj
 * <br>CreateDate 2022/11/27 0:31
 */
@Aspect // 切面
@Component // 切面也是一个bean
public class TestAspect {


	@Pointcut("execution(public void com.xusj.future.service.PeopleService.testMethod())")
	public void mypoint() {
		//切面定义
	}

	@Before("mypoint()")
	public void doAround() {
		System.out.println("before logic");
	}

}

package com.xusj.future.service;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:58
 */
@Service
public class PeopleService implements InitializingBean {
	@Autowired
	private DogService dogService;

	private String initStr;

	// 构造 二

//	public PeopleService(String initStr) {
//		this.initStr = initStr;
//	}
//	// 构造一
//	@Autowired
//	public PeopleService(DogService dogService) {
//		this.dogService = dogService;
//	}

	public void testMethod() {
		System.out.println("111");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		initStr = "直接在bean初始化的时候就创建了";
		System.out.println("在创建bean的时候自动和初始化一些值");
	}
}

// 这里很重要开启AOP代理

package com.xusj.future.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:58
 */
@ComponentScan("com.xusj")
@EnableAspectJAutoProxy // 开启Aop代理
public class AppConfig {
//	@Bean
//	public PeopleService getPeople() {
//		return new PeopleService();
//	}
}

// 启动类

package com.xusj.future;

import com.xusj.future.config.AppConfig;
import com.xusj.future.service.PeopleService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @author xusj
 * <br>CreateDate 2022/5/9 22:15
 */

public class MainTest {
	public static void main(String[] args) {
//		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("bean1.xml");
//		Person bean = classPathXmlApplicationContext.getBean(Person.class);
//		System.out.println(bean);
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		PeopleService peopleService = (PeopleService) context.getBean("peopleService");
		peopleService.testMethod();

	}
}

- 2、- debug

  1. 在有AOP的情况下,我们getBean拿到是cglib的代理对象,代理对象是怎么调普通对象的方法的
    在这里插入图片描述

  2. 先走前置通知在这里插入图片描述

  3. 当正在去调用方法的时候,并不是通过代理对象去调的,而是原普通对象来弄的
    在这里插入图片描述

- 3、- 总结debug

// 对于cglib代理来说,就是代理对象去继承被代理对象;为代码如下,这样代理对象就能使用bean中的方法和属性了【代理对象里面是没有值的】

public A extends B{
	// spring 中
	private B b;
	
	// 这是继承父类的方法
	public void test(){
		// 怎么去调用父类的方法
		// 1、直接去super.test
		// 2、将B做为属性干到代理类中,spring是这么干的
		b.test();
	}
}

在这里插入图片描述
对于代理对象来说,以AOP为例子,我们只关注切到对应的方法上面,我们对被代理对象中的属性没有太大关注,所以代理对象是没有值得。

Object target = joinPoint.getTarget();这个完全可以拿到被代理得对象

@Aspect // 切面
@Component // 切面也是一个bean
public class TestAspect {


	@Pointcut("execution(public void com.xusj.future.service.PeopleService.testMethod())")
	public void mypoint() {
		//切面定义
	}

	@Before("mypoint()")
	public void doAround(JoinPoint joinPoint) {
		// 拿到得是普通对象(被代理对象得值,我们就可以通过这个去得到其中得属性)
		Object target = joinPoint.getTarget();
		System.out.println("before logic");
	}

}

三、总览事务

- 1、- test coding

// 拿到数据库连接,然后给到事务管理器和jdbc进行操作

/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:58
 */
@ComponentScan("com.xusj")
@EnableAspectJAutoProxy // 开启Aop代理
@EnableTransactionManagement // 开启事务
@Configuration
public class AppConfig {
//	@Bean
//	public PeopleService getPeople() {
//		return new PeopleService();
//	}

	// 拿jdbc
	@Bean
	public JdbcTemplate jdbcTemplate() {
		// 将连接交给他
		return new JdbcTemplate(dataSource());
	}
	// 创建数据库连接
	@Bean
	public DataSource dataSource() {
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/study?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useInformationSchema=true");
		dataSource.setUsername("root");
		dataSource.setPassword("root");
		return dataSource;
	}
	// 交给事务管理
	@Bean
	public PlatformTransactionManager transactionManager(){
		DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
		dataSourceTransactionManager.setDataSource(dataSource());
		return dataSourceTransactionManager;
	}
}

// 添加注解


/**
 * @author xusj
 * <br>CreateDate 2022/11/26 22:58
 */
@Service
public class PeopleService implements InitializingBean {
	@Autowired
	private DogService dogService;



	@Autowired
	private JdbcTemplate jdbcTemplate;


	@Transactional// 事务注解
	public void execute() {
		jdbcTemplate.execute("insert student values (3,s,1)");
		System.out.println("zhix ");
		throw new NullPointerException();
	}

}

// 主方法调用

/**
 * @author xusj
 * <br>CreateDate 2022/5/9 22:15
 */

public class MainTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		PeopleService peopleService = (PeopleService) context.getBean("peopleService");

		peopleService.execute();

	}
}

- 2、 debugging

这里也是用过代理对象完成事务的,流程如下,类似aop的代理,里面逻辑不一样

public A extends B{
	// spring 中
	private B b;
	
	// 这是继承父类的方法
	public void test(){
		// 1先判断有没有@Transactional这个注解
		// 2有的话,将conn置为false(默认是true自动提交,这里将他置为手动提交)
		b.执行sql();
		// 3没有异常直接commit
		// 4有异常rollback
	}
}

- 3、 事务失效

  • 一个经典的事务失效(方法里面调用方法,事务失效)
  1. 由上面分析代理对象我们可以知道,只有当代理对象去调用方法的时候,事务ok
  2. 但是你在方法中调用方法的时候,一开始第一个方法你是代理对象调用过来的,但是后面第二个方法是普通对象搞来的,那么就失效了
@Transactional// 事务注解
	public void execute() {
		jdbcTemplate.execute("insert student values (3,s,1)");
		System.out.println("zhix ");
		a();
	}

	public void a() {
		jdbcTemplate.execute("insert student values (3,s,1)");
		System.out.println("zhix ");
		throw new NullPointerException();
	}

// 解决方法,我们可以注入自己,然后调用方法,这样的话,我们在ioc拿出来的都是一个代理对象,所以就解决了

@Autowired
	private PeopleService peopleService;
	@Transactional// 事务注解
	public void execute() {
		jdbcTemplate.execute("insert student values (3,s,1)");
		System.out.println("zhix ");
		peopleService.execute();;
//		a();
	}

- 4、事务总结

Spring事务的代理对象执行某个方法时的步骤:

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
  5. 执行完了之后如果没有出现异常,则提交,否则回滚
    Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cpu设计和实现(流水线暂停)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;数字电路里面流水线的引入&#xff0c;主要是为了提高数据的处理效率。那么&#xff0c;鉴于此&#xff0c;为什么又要对…

ssm宠物商城管理系统源码

在 Internet飞速开展的今天&#xff0c;互联网成为人们快速获取、发布和传 递信息的重要渠道&#xff0c;它在人们学习、工作、生活等各个方面发挥着重要的作用。 因此建立在 Internet应用上的地位显而易见&#xff0c;它已成为政府、企事业单位信息化 建立中的重要组成局部&am…

[附源码]SSM计算机毕业设计网上书店管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【kafka】十五、kafka消费者API

kafka消费者API Consumer消费数据时的可靠性是很容易保证的&#xff0c;因为数据在kafka中是持久化的&#xff0c;故不用担心数据丢失的问题。 由于consumer在消费过程中可能会出现断电宕机的等故障&#xff0c;consumer恢复后&#xff0c;需要从故障前的位置继续消费&#xf…

visual studio 2019 + Qt 开发,使用visual leak detector检测内存泄漏

选择了在vs2019上开发Qt, 遇到了内存泄露问题。还好vs上有方便的visual leak detector&#xff08;vld&#xff09;检测工具。 虽然官网上只支持到vs2015, 但vs2019上也能用。 具体参考这位博主的文章&#xff1a;https://blog.csdn.net/qq_22108657/article/details/1208843…

Redis数据库安装(Windows)

目录 一、下载Windows安装包 二、启动Redis 1.在终端中启动 2.使用start.bat文件启动 3.添加服务启动 三、安装Redis可视化管理工具 1.安装Redis图形客户端 2.连接数据库 一、下载Windows安装包 下载地址&#xff1a;Releases tporadowski/redis GitHub 选择下载相…

单链表的递归详解 (leetcode习题+ C++实现)

文章目录合并两个有序链表翻转链表链表中移除节点合并两个有序链表 传送门&#xff1a; https://leetcode.cn/problems/merge-two-sorted-lists/description/ 题目要求&#xff1b; 给你两个有序的链表&#xff0c;将这两个链表按照从小到大的关系&#xff0c;合并两个链表为…

Mybatis快速入门

Mybatis安装与配置 Mybatis概述 Mybatis本质上是一个别人写好的框架&#xff0c;用于简化 JDBC 开发&#xff0c;通过Mybatis框架&#xff0c;可以极大的降低JDBC的开发难度。 官方文档&#xff1a;https://mybatis.org/mybatis-3/zh/index.html Mybatis快速入门 需求&…

MySQL进阶实战10,MySQL全文索引

一、全文索引 全文索引的目的是 通过关键字的匹配进行查询过滤&#xff0c;基于相似度的查询&#xff0c;而不是精确查询。 全文索引利用分词技术分析出文字中某关键字的频率和重要性&#xff0c;并按照一定的算法智能的筛选出我们想要的结果。 全文索引一般用于字符串中某关…

tomcat服务器安装及配置教程(保姆级教程)

Tomcat安装教程 &#xff08;以tomcat-9.0.62为例&#xff1a;&#xff09; 1.下载安装包 可以从官网下载安装包&#xff1a; &#xff08;1&#xff09;从官网下载 输入网址进入官网 选择版本10&#xff0c;版本9&#xff0c;或者版本8&#xff0c;都可以&#xff0c;这里…

掘金热榜首推!阿里内部都在用的Java后端面试笔记,囊括99%的主流技术

纵观今年的技术招聘市场&#xff0c; Java依旧是当仁不让的霸主 &#xff01;即便遭受 Go等新兴语言不断冲击&#xff0c;依旧岿然不动。究其原因&#xff1a; Java有着极其成熟的生态&#xff0c;这个不用我多说&#xff1b;Java在 运维、可观测性、可监 控性方面都有着非常优…

Spring Boot JPA 本机查询示例

在本教程中&#xff0c;您将了解如何在 Spring 引导中使用 Spring Data JPA 本机查询示例&#xff08;带参数&#xff09;。我将向您展示&#xff1a; 将 Spring JPA 本机查询与Query注释一起使用的方法如何在 Spring 引导中执行 SQL 查询具有 WHERE 条件的 JPA 选择查询示例 …

动态SQL

动态SQL 可以根据具体的参数条件&#xff0c;来对SQL语句进行动态拼接。比如在以前的开发中&#xff0c;由于不确定查询参数是否存在&#xff0c;许多人会使用类似于where 1 1 来作为前缀&#xff0c;然后后面用AND 拼接要查询的参数&#xff0c;这样&#xff0c;就算要查询的…

MongoShake数据灾备与迁移

安装部署 解压 建议部署在离目标端近的地方&#xff0c;比如部署再目标端本地 tar -zxvf mongo-shake-v2.8.1.tgz配置 同构环境下主要参数 启动 执行下述命令启动同步任务&#xff0c;并打印日志信息&#xff0c;-verbose 0表示将日志打印到文件&#xff0c;在后台运行 …

【Linux从入门到放弃】Linux基本指令大全

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; L…

黑苹果之微星(MSI)主板BIOS详细设置篇

很多童鞋安装黑苹果的时候会卡住&#xff0c;大部分原因是cfg lock 没有关闭&#xff0c;以及USB端口或SATA模式设置错误。 为了避免这些安装阶段报错的情况发生&#xff0c;今天给大家分享一下超详细的BIOS防踩坑设置指南--微星&#xff08;MSI&#xff09;主板BIOS篇&#xf…

springcloud总结篇

一.整体结构 springcloud总体架构 对比学习 二.具体 1.场景模拟 订单服务调用库存服务来更新数据库中的库存 2.springcloud问题解析 Eureka OpenFeign &#xff08;RibbonRestTemplate&#xff09; Hystrix Gateway config Bus 订单服务只知道库存服务的名称…

Python测试-unittest,2022-11-27

(2022.11.27 Sun) unittest是Python自带的单元测试框架。unittesthtml和pytestallure(测试报告)成为常用的自动测试和报告的框架组合。 unittest-archi-2022-11-23-2114.png 概念 test case测试用例&#xff1a;测试用例是测试的基本单元&#xff0c;用于测试一组特定输入的特…

OpenCV图像特征提取学习四,SIFT特征检测算法

一、SIFT特征检测概述 SIFT的全称是Scale Invariant Feature Transform&#xff0c;尺度不变特征变换&#xff0c;由加拿大教授David G.Lowe提出的。SIFT特征具有对旋转、尺度缩放、亮度变化等保持不变性&#xff0c;是一种非常稳定的局部特征。 1.1 SIFT算法具的特点 图像…

平衡搜索树——AVL树小记

文章目录二叉搜索树平衡搜索树AVL树定义AVL中平衡(Balance)因子的定义AVL树插入规则AVL树失衡情况左左失衡/右右失衡左右失衡RL失衡代码左旋-调整平衡插入调整平衡因子AVL树正确性的验证二叉搜索树 理想情况下&#xff0c;二叉搜索树的查找时间复杂度是0(log(n)) 但是&#xff…