# Spring底层核心原理

# Bean创建流程

  1. 通过构造方法(推断构造方法, 以及入参) -> 得到对象
  2. 依赖注入(对加了Spring注解的属性赋值, 比如@Autowire)
  3. 初始化前(@PostConstruct)
  4. 初始化(实现InitializingBean接口)
  5. 初始化后(AOP) -> 代理对象
  6. bean

# 初始化顺序

@PostConstruct 早于 afterPropertiesSet

# InitBeanServiceImpl

package cn.com.grasswort.test;

import javax.annotation.PostConstruct;

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

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author liuxiaolu
 * @date 2022/08/10
 */
@Service
public class InitBeanServiceImpl implements InitializingBean {

    /**
     * 初始化之前
     */
    @PostConstruct
    public void beforeInit() {
        System.out.println("对象初始化之前调用 @PostConstruct");
    }

    /**
     * 初始化
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("对象初始化调用 InitializingBean");
    }

    public void sayHi() {
        System.out.println("Hello Spring!");
    }

}

# MainTest

package cn.com.grasswort.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author liuxiaolu
 * @date 2021/12/1
 */
@Configuration
@ComponentScan("cn.com.grasswort.test")
public class MainTest {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainTest.class);
        InitBeanServiceImpl bean = context.getBean(InitBeanServiceImpl.class);
        bean.sayHi();

    }

}

# 执行结果

对象初始化之前调用 @PostConstruct
对象初始化调用 InitializingBean
Hello Spring!

Process finished with exit code 0

# 测试通过构造方法得到对象

  • 当一个类存在多个构造方法时,spring初始化的时候默认会去找无参构造方法。如果不存在无参构造方法,则会初始化报错。
  • 当一个类只有一个构造方法,那么初始化就会用这个构造方法

# 测试

package cn.com.grasswort.test;

import org.springframework.stereotype.Service;

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author liuxiaolu
 * @date 2022/08/10
 */
@Service
public class ConstructServiceImpl {

    /**
     * 方法1
     * 存在多个构造方法的时候,默认调用无参构造方法
     */
    public ConstructServiceImpl() {
        System.out.println("1");
    }

    /**
     * 方法2
     */
    public ConstructServiceImpl(InitBeanServiceImpl initBeanService) {
        System.out.println("2");
    }

    /**
     * 方法3
     */
    public ConstructServiceImpl(InitBeanServiceImpl initBeanService1, InitBeanServiceImpl initBeanService2) {
        System.out.println("3");
    }

    /**
     * 方法4
     */
    @Autowired
    public ConstructServiceImpl(InitBeanServiceImpl initBeanService1, InitBeanServiceImpl initBeanService2, InitBeanServiceImpl initBeanService3) {
        System.out.println("4");
    }
    
    public void sayHi() {
        System.out.println("Hello Spring!");
    }

}

# 说明

  • 方法1,方法2,方法3共存的情况下,默认使用方法1去初始化对象
  • 方法1不存在,存在方法2和方法3,初始化报错
  • 只存在方法2,或者方法3,可以初始化成功
  • 方法2和方法3需要入参InitBeanServiceImpl,当spring容器中只存在一个类型为InitBeanServiceImpl的对象时,会直接注入。如果根据类型找到了多个,再根据入参名称找指定的对象。如果根据名称找不到指定对象,会报错。
  • 存在多个构造方法的情况下,可以通过注解@Autowired指定需要调用的构造方法。方法1,2,,3,4都存在的情况下,会调用方法4

# 补充:什么情况下,在一个spring容器汇总存在多个相同对象

package cn.com.grasswort.test;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author liuxiaolu
 * @since 2022/8/10
 */
@Component
public class MultiInitBeanConfig {

    @Bean
    public InitBeanServiceImpl initBeanService1() {
        return new InitBeanServiceImpl();
    }

    @Bean
    public InitBeanServiceImpl initBeanService2() {
        return new InitBeanServiceImpl();
    }

    @Bean
    public InitBeanServiceImpl initBeanService3() {
        return new InitBeanServiceImpl();
    }
}

# AOP

代理类 -> 代理对象 —> 代理对象.target = 普通对象

# 简单的实现原理

  1. 执行service.xxx方法
  2. 查看是否有service.xxx切面方法的缓存
  3. 有缓存,直接执行切面方法
  4. 没有缓存
    1. 找出所有切面bean
    2. 遍历所有切面bean
    3. 遍历切面bean的所有方法
    4. 把和指定service.xxx所匹配的切面方法缓存,并执行切面方法

# 事务

  • 事务的大致流程(通过代理对象执行对应方法的时候生效,结合分析事务失效的场景)
  • 当调用XxxService.test方法时,触发代理对象的test方法调用
class XxxServiceProxy implements XxxService {
   XxxService target;

   public void test() {
      // 1. 判断是否有@Transacitonal注解
      // 2. 创建一个数据库连接conn(事务管理器dataSource)
      // 3. conn.autocommit=false
      try {
         // 4. 执行真实的方法
         target.test();
         
         // 5. 提交事务
         conn.commit();
      } catch (Exception e) {
          // 6. 异常回滚
         conn.rollback();
      }
   }
}

# @Configuration的作用

以下面的代码为例

package cn.com.grasswort.test.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author xiaolu liu
 * @since 2022/8/11
 */
@Configuration
public class AppConfig {

	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dataSource());
	}

	@Bean
	public PlatformTransactionManager transactionManager() {
		DataSourceTransactionManager txManager = new DataSourceTransactionManager();
		txManager.setDataSource(dataSource());
		return txManager;
	}

	@Bean
	public DataSource dataSource() {
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&useSSL=false");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		return dataSource;
	}
}
  1. 创建AppConfig代理对象
  2. 创建jdbcTemplate,发现需要dataSource,在AppConfig代理对象中查找dataSource
  3. 未找到dataSource,创建dataSource,并缓存在AppConfig代理对象中
  4. jdbcTemplate创建完成
  5. 创建transactionManager,发现需要dataSource,在AppConfig代理对象中查找dataSource
  6. 找到dataSource,直接返回dataSource
  7. transactionManager创建完成
Last Updated: 8/11/2022, 11:37:30 PM