1.Bean的生命周期底层原理
2.依赖注入
3.初始化底层
4.Aop
5.推断构造方法
6.spring事务底层原理
准备工作
Spring对象
spring中创建的bean和我们普通创建的对象有什么不一样呢?
举例:
Spring中底层创建对象的原理
- 看上图的UserService里面是否有构造方法?-》只有一个无参构造方法
- 那这个构造方法就是生成这个对象的途径。但是无参构造方法不能给orderservice赋值,那orderSevice的值是哪里来的呢?(此时此刻是普通的创建方法)
- 这就是Spring大佬为我们做的是事情-》依赖注入
- 找到对象里面有autowired注解的成员变量赋值,伪代码大概如下图所示
- 目前的动作图如下
- 实际上在依赖注入之后还有初始化前和初始化,初始化后的步骤。 我们现在从一个需求来考虑这些步骤的设计。
- 针对上面的的需求我们加一个@Autowired注解能到达要求吗?显然不能,因为需求是要在数据库里面赋值。这里就可以在我们前面说的初始化前中后里面调用一个赋值admin的方法即可
- 那程序员怎么告诉spring要调用这个赋值方法呢?加@PostConstruct(初始化前处理)注解,加这个注解就能达到目的的原理如下伪代码
- 我们同样可以实现InitializingBean接口的afterPropertiesSet方法不过这是在初始化的时候做操作。对象是否实现了这个接口:instance of xxxxx,然后强转调用方法即可
- 如果我们要在初始化后实现这个需求就需要使用到AOP,生成代理对象,此时的Bean的创建生命周期如下。
- 有个问题:上图都是在只有一个默认无参构造方法的情况下的流程图,那如果它有含参构造方法呢?甚至多个呢?情况如下:1.一个无参,一个有参数,使用无参。2.一个有参构造,使用这个有参构造。3.两个有参,报错,因为有多个构造方法的时候,spring会去找默认构造方法,即无参构造方法。解决没有默认构造方法且有多个有参构造方法报错的方法:在其中一个构造方法中加上@Autowired注解,指定构造方法
- 当spring使用有参构造方法时它会在spring容器中找到入参的对象,作为构造方法的入参,如果这个入参不是bean就会报错
- spring容器找一个bean是怎么找呢?如果先看名字去找,很可能找不到你需要的类型,所以我们按照类的类型去找,那如果找到多个我们就按照名字去找(同类型),如果名字找不到就报错。@Bean会覆盖@Component
- 依赖注入这一步骤也是从spring容器中寻找,先byType在byName
- AOP:加@Aspect和@Componet注解,然后写方法,加@Before注解,配置类上面加上注解@EnableAspectJAutoProxy.此时如果从spring容器中获取对象,那么就会获得一个代理对象
- 通过打断点调试会发现我们获取一个bean(使用了AOP)获取到一个代理对象,他的成员变量是没有值的(不会依赖注入),其实我们回去看流程图,生成代理对象之后也没有对这个代理对象进行依赖注入,那这个代理类对象怎么调用其成员变量呢?操作方法如下:
- 怎么知道要生成代理对象:找出所有切面bean(有@Aspect注解),遍历这些baen,遍历这些bean的所有方法,找到注解中含有对应这个即将要生成的bean的方法,就把所有对应这个bean的切面方法缓存起来,然后执行的时候就可以在缓存中获取
- spring事务:在spring中,如果不在配置类上加@Configuration事务不会回滚。原因是spring中如果创建一个代理对象,同时@Transaltion注解添加到这个方法时,然后由事务管理器创建一个数据库连接,把连接的自动提交置为false。但是此时执行sql语句的jdbctemplate和事务管理器的数据源并不是一个,所以事务失效。加了注解为什么可以能,因为加了@configuration注解,他会变成一个代理模式,遇到一个对象会从容器里面拿,而不是生成。
- 代理对象执行对象方法,事务会生效,但是如果是这个对象的方法内调用其他方法,那就会使得事务失效,如下图所示。解决方法就是在这个类定义一个bean,这个bean是自己,但是通过依赖注入,这个bean会是代理对象