日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/29 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spirng 痛苦源码学习(一)——总起spring(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、總覽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的設計思想是這樣的:
  • 如果一個類只有一個構造方法,那么沒得選擇,只能用這個構造方法
  • 如果一個類存在多個構造方法,Spring不知道如何選擇,就會看是否有無參的構
    造方法,因為無參構造方法本身表示了一種默認的意義
  • 不過如果某個構造方法上加了@Autowired注解,那就表示程序員告訴Spring就
    用這個加了注解的方法,那Spring就會用這個加了@Autowired注解構造方法了
    需要重視的是,如果Spring選擇了一個有參的構造方法,Spring在調用這個有參構造方法
    時,需要傳入參數,那這個參數是怎么來的呢?
    Spring會根據入參的類型和入參的名字去Spring中找Bean對象(以單例Bean為例,
    Spring會從單例池那個Map中去找):
  • 先根據入參類型找,如果只找到一個,那就直接用來作為入參
  • 如果根據類型找到多個,則再根據入參名字來確定唯一一個
  • 最終如果沒有找到,則會報錯,無法創建當前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、對于以上的一些代碼我們放如下問題【希望學完,我自己能解決】
  • 第一行代碼,會構造一個ClassPathXmlApplicationContext對象,
    ClassPathXmlApplicationContext該如何理解,調用該構造方法除開會實例化得到
    一個對象,還會做哪些事情?
  • 第二行代碼,會調用ClassPathXmlApplicationContext的getBean方法,會得到
    一個UserService對象,getBean()是如何實現的?返回的UserService對象和我們自
    己直接new的UserService對象有區別嗎?
  • 第三行代碼,就是簡單的調用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

  • 在有AOP的情況下,我們getBean拿到是cglib的代理對象,代理對象是怎么調普通對象的方法的

  • 先走前置通知

  • 當正在去調用方法的時候,并不是通過代理對象去調的,而是原普通對象來弄的

  • - 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、 事務失效

    • 一個經典的事務失效(方法里面調用方法,事務失效)
  • 由上面分析代理對象我們可以知道,只有當代理對象去調用方法的時候,事務ok
  • 但是你在方法中調用方法的時候,一開始第一個方法你是代理對象調用過來的,但是后面第二個方法是普通對象搞來的,那么就失效了
  • @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事務的代理對象執行某個方法時的步驟:

  • 判斷當前執行的方法是否存在@Transactional注解
  • 如果存在,則利用事務管理器(TransactionMananger)新建一個數據庫連接
  • 修改數據庫連接的autocommit為false
  • 執行target.test(),執行程序員所寫的業務邏輯代碼,也就是執行sql
  • 執行完了之后如果沒有出現異常,則提交,否則回滾
    Spring事務是否會失效的判斷標準:某個加了@Transactional注解的方法被調用時,要判斷到底是不是直接被代理對象調用的,如果是則事務會生效,如果不是則失效。
  • 總結

    以上是生活随笔為你收集整理的Spirng 痛苦源码学习(一)——总起spring(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。