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底層會調用類的構造方法來完成對象創建
(這里先不管他是怎么拿到構造方法的,反正就是拿構造方法,默認是無參構造器。這里其實有一個推斷構造方法的過程)
多個構造方法,直接報錯(沒有構造器被找到)
解決方法在你需要的構造器上加上@Autowired指定spring用;因為spring比較笨所以你要教他做事
2 Spring的設計思想是這樣的:造方法,因為無參構造方法本身表示了一種默認的意義
用這個加了注解的方法,那Spring就會用這個加了@Autowired注解構造方法了
需要重視的是,如果Spring選擇了一個有參的構造方法,Spring在調用這個有參構造方法
時,需要傳入參數,那這個參數是怎么來的呢?
Spring會根據入參的類型和入參的名字去Spring中找Bean對象(以單例Bean為例,
Spring會從單例池那個Map中去找):
確定用哪個構造方法,確定入參的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該如何理解,調用該構造方法除開會實例化得到
一個對象,還會做哪些事情?
一個UserService對象,getBean()是如何實現的?返回的UserService對象和我們自
己直接new的UserService對象有區別嗎?
二、總覽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、 事務失效
- 一個經典的事務失效(方法里面調用方法,事務失效)
// 解決方法,我們可以注入自己,然后調用方法,這樣的話,我們在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事務的代理對象執行某個方法時的步驟:
Spring事務是否會失效的判斷標準:某個加了@Transactional注解的方法被調用時,要判斷到底是不是直接被代理對象調用的,如果是則事務會生效,如果不是則失效。
總結
以上是生活随笔為你收集整理的Spirng 痛苦源码学习(一)——总起spring(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php写接口curd,接口实战(数据库的
- 下一篇: 如何高效学习-随意信息处理-信息的记忆