spring依赖注入底层原理解析
spring之bean对象生命周期步骤详情
流程:
UserService.class —>推断构造方法—>普通对象----依赖注入------>初始化(afterPropertiesSet方法)------>初始化后(AOP)------>代理对象----->放入Map<baenName,Bean对象>
推断构造方法
@Component
public class UserService implements InitializingBean {
@Autowired
private OrderService orderService;
//无参构造方法
public UserService() {
System.out.println(8);
}
//有参构造方法
public UserService(OrderService orderService) {
this.orderService = orderService;
System.out.println(1);
}
//有参构造方法
public UserService(OrderService orderService, OrderService orderServicel) {
this.orderService = orderService;
System.out.println(2);
}
}
以上如何选择呢?
spring会默认使用无参构造方法,如果没有无参的有多个有参的构造方法spring就会报错
如果有多个就可以明确给spring指定哪一个构造方法-------在构造方法上加@Autowired 注解
依赖注入
判断普通对象中是否有Autowired注解再进行依赖注入
源码大体逻辑:
依赖注入的话如何判断注入对象就是想要的依赖对象呢?
先byType---->再byName 在 Map<beaName,Bean对象> 中寻找
spring中使用 对象类型 和 对象名字进行识别唯一的
类型可以一样 名字必须不一样
在Bean中的地址不一样生成的Bean不同
初始化
初始化必须实现spring提供的指定方法
import org.springframewolk.beans.factory.InitializingBean;//实现一个接口
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService implements InitializingBean {
@Autowired
private OrderService orderService;
//初始化执行自己定义
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(orderService);
}
public void test() {
System.out.println(orderService);
}
}
源码中判断UserService是否实现了InitializingBean接口,如果实现了就调用afterPropertiesSet自己定义初始化方法
AOP
UserServiceProxy对象===UserService代理对象----->UserService代理对象.target
UserService代理对象.test()
class UserServiceProxy extends UserService {
UserService target;
public void test(){
// 切面逻辑
// target.test() //UserService普通对象.test()
}
放入Map<baenName,Bean对象>
放入Bean对象到Map<String,Object>的API(自己调用方法),一般是再UserService.class方法上面加Component注解,加入到Map<String,Object>的
//放入Bean对象到Map<String,Object>的API
Object o = new Object();|I
applicationContext.getBeanFactory().registerSingleton( beanName: "xxx",o);
放入Map<String,Object>的源码
spring事务
流程:
Spring事务切面逻辑----->@Transactional开启Spring事务----->利用事务管理器新建一个数据库连接conn ThreadLocal------>conn.autocommit=false------>target.test() //UserService普通对象.test() jdbcTemplate 执行sql1.sql2 ----->conn.rollback()conn.commit()
1、@Transactional
2、开启Spring事务
3、利用事务管理器新建一个数据库连接conn ThreadLocal
4、conn.autocommit=false
5、target.test() // UserService普通对象.test() jdbcTemplate执行sql1.sql2
6、conn.rollback()conn.commit()
准备Bean对象
配置事务创建链接数据库的对象Bean相当于mybatis对象
@ComponentScan("com.zhouyu")
@EnableTransactionManagement //用于启用基于注解的事务管理
@Configuration //通过配置类可以定义和组装Spring Bean。 返回的是同一个dataSource对象 AppConfig代理对象
public class AppConfig {
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
//利用事务管理器创建数据库链接
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = newDataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager:
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.seturl("jdbc :mysql://127.0.0.1:3306/tuling");
dataSource.setUsername("root");
dataSource.setPassword("Zhouyu123456***");
returm dataSource;
}
@EnableTransactionManagement 是Spring框架提供的一个注解,用于启用基于注解的事务管理。通过使用这个注解,你可以开启Spring对事务的自动管理功能,使得你可以在方法上使用 @Transactional 注解来声明事务。
@EnableTransactionManagement 主要有以下两个属性:
- mode(默认为 AdviceMode.PROXY):指定事务代理的模式。可以选择的值有 AdviceMode.PROXY 和
AdviceMode.ASPECTJ。默认是 AdviceMode.PROXY,表示使用基于代理的方式实现事务管理。如果选择
AdviceMode.ASPECTJ,表示使用基于AspectJ的方式实现事务管理。 - proxyTargetClass(默认为 false):用于确定代理是否应该使用目标类的类代理,而不是目标类实现的接口。如果设置为
true,代理将使用目标类的类代理(CGLIB代理),如果设置为 false,代理将使用目标类实现的接口代理(JDK动态代理)。
当你在配置类上使用 @EnableTransactionManagement 注解时,Spring框架会自动扫描带有 @Transactional 注解的方法,并在这些方法周围织入事务管理的逻辑。如果一个带有 @Transactional 注解的方法执行过程中出现了异常,Spring会自动回滚事务。这个注解的作用是简化事务管理的配置和使用,提高开发效率。
测试事务
class UserService{
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void test() {
jdbcTemplate.execute( sql: "insert into t1 values(1,1,1,1,'1')");
//抛空指针异常,触发事务回滚
throw new NullPointerException();
}
}
主程序逻辑
检查数据库中数据是否插入成功
事务失效
1、原因:
一个对象调用了另一个对象
代理对象和普通对象是两个对象
class UserService{
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void test() {
jdbcTemplate.execute( sql: "insert into t1 values(1,1,1,1,'1')");
throw new NullPointerException();
a();
}
//多个事务报错propagation = Propagation.NEVER
@Transactional(propagation = Propagation.NEVER)
public void a(){
jdbcTemplate.execute( sql: "insert into t1 values(2,2,2,2, '2' )");
}
}
以上原因一个对象调用了另一个对象的a()
使用this.a()不能解决,因为this是普通对象
解决方法:
1、新建一个Base类,把需要调用的功能拿到另一个Bean对象中
新建类UserServiceBase,把UserService的a方法删掉,不要有相同的方法
2、自己注入自己
1、原因:
@ComponentScan("com.zhouyu")
@EnableTransactionManagement //用于启用基于注解的事务管理
@Configuration //AppConfig代理对象来掉用
public class AppConfig {
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
//利用事务管理器创建数据库链接
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = newDataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager:
}
//创造dataSource对象
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.seturl("jdbc :mysql://127.0.0.1:3306/tuling");
dataSource.setUsername("root");
dataSource.setPassword("Zhouyu123456***");
returm dataSource;
}
}
@Configuration 中使用的是super.方法
AOP中使用的是target.方法