文章目录

  • 前言
  • 一、总览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 {@Autowiredprivate DogService dogService;private String initStr;public void testMethod() {System.out.println("111");}// 这里就是你想在bean创建的时候给他赋值implements InitializingBean@Overridepublic 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 {@Autowiredprivate 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");}@Overridepublic 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@Beanpublic JdbcTemplate jdbcTemplate() {// 将连接交给他return new JdbcTemplate(dataSource());}// 创建数据库连接@Beanpublic 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;}// 交给事务管理@Beanpublic 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 {@Autowiredprivate DogService dogService;@Autowiredprivate 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拿出来的都是一个代理对象,所以就解决了

@Autowiredprivate 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注解的方法被调用时,要判断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效。

Spirng 痛苦源码学习(一)——总起spring(一)相关推荐

  1. Spring源码学习(一)--Spring底层核心原理解析

    目录 Spring中是如何创建一个对象? Bean的创建过程 推断构造方法 AOP大致流程 Spring事务 最近在跟视频学习spring源码,将每节课记录下来,以后好来复习. 首先把Spring中核 ...

  2. Vuex源码学习(五)加工后的module

    没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection 感谢提出代码块和截图建议的小伙伴 代码块和截图的区别: 代码块部分希望大家按照我 ...

  3. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  4. Simple-Faster-RCNN源码学习笔记

    Simple-Faster-RCNN 源码学习 项目github地址: https://github.com/chenyuntc/simple-faster-rcnn-pytorch 源码 源文件: ...

  5. nginx源码学习资源

    nginx源码学习是一个痛苦又快乐的过程,下面列出了一些nginx的学习资源. 首先要做的当然是下载一份nginx源码,可以从nginx官方网站下载一份最新的. 看了nginx源码,发现这是一份完全没 ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)(转)

    阅读目录 一.MVC原理解析 1.MVC原理 二.HttpHandler 1.HttpHandler.IHttpHandler.MvcHandler的说明 2.IHttpHandler解析 3.Mvc ...

  7. Promise源码学习(2)

    Promise源码学习(2) 本篇为上一篇源码学习(1)的补充,主要是来介绍Promise.all()和Promise.race()方法. 闲话少叙,进入正题 Promise.race() 首先来简单 ...

  8. STL源码学习之空间配置

    STL的空间配置器主要用于内存的分配.填充.释放等操作,在学习它之前,需要深入一点理解new和delete.由于new和delete分两段操作:内存配置和对象构建(析构),本文亦将按此进行分类,其中第 ...

  9. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

最新文章

  1. 【二级java】二叉树序列
  2. oracle怎么查看一个表或一个索引占用多少空间
  3. 面试:Java反射到底慢在哪?
  4. CentoS 下安装gitlab
  5. VC++ 使用TeeChart图表控件(1)
  6. Go 内存对齐的那些事儿
  7. createBindingContext in SAP UI5
  8. OptaPlanner –具有真实道路距离的车辆路线
  9. 白盒测试 | 用例设计方法之判定覆盖
  10. python中索引越界的常见原因
  11. Go语言path is relative, but relative import paths are not supported in module mode
  12. 词频统计(仍需完善版)
  13. VS2015打开编译VS2013工程时提示fatal error C1083: 无法打开包括文件: “afxwin.h”: No such file or directory
  14. Kotlin 第一弹:自定义 ViewGroup 实现流式标签控件
  15. EcShop开发手册
  16. 万字博客带你全面剖析Spring的依赖注入
  17. 如何在iPhone或iPad上使用Safari下载文件
  18. linux搭建h5学习日记
  19. 优化大师优化后 出现的问题
  20. 局域网联机一起过关的游戏

热门文章

  1. Python数据类型,字符编码,文件处理
  2. 高性能php开发框架,PHP高性能框架选择
  3. 触点通RTC文档管理模块
  4. 对于gta5加mod的一些记录
  5. 2022爱分析 地产科技应用实践报告
  6. CUG中国地质大学(武汉)现代软件工程燃气投诉用例图活动图
  7. 手机/网页端实现自动打卡
  8. SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers
  9. 学php c语言,一个学过C语言的小编学习PHP编程微课是什么样的一种体验?-php是什么文件...
  10. 考不上的本科都是智商有问题的boss面试公司火了,当事者却凉凉了