# Spring底层核心原理
# Bean创建流程
- 通过构造方法(推断构造方法, 以及入参) -> 得到对象
- 依赖注入(对加了Spring注解的属性赋值, 比如@Autowire)
- 初始化前(@PostConstruct)
- 初始化(实现InitializingBean接口)
- 初始化后(AOP) -> 代理对象
- 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 = 普通对象
# 简单的实现原理
- 执行service.xxx方法
- 查看是否有service.xxx切面方法的缓存
- 有缓存,直接执行切面方法
- 没有缓存
- 找出所有切面bean
- 遍历所有切面bean
- 遍历切面bean的所有方法
- 把和指定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;
}
}
- 创建AppConfig代理对象
- 创建jdbcTemplate,发现需要dataSource,在AppConfig代理对象中查找dataSource
- 未找到dataSource,创建dataSource,并缓存在AppConfig代理对象中
- jdbcTemplate创建完成
- 创建transactionManager,发现需要dataSource,在AppConfig代理对象中查找dataSource
- 找到dataSource,直接返回dataSource
- transactionManager创建完成