Spring源码学习Day01
目录
前言
Spring源码学习Day01,描述错误或不严谨之处,请指正
一、配置方式
Spring的XML配置方式
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
StudentService studentService = (StudentService) context.getBean("studentService");
studnetService.learn();
SpringBoot使用类的配置方式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
StudentService studentService = (StudentService) context.getBean("studentService");
studnetService.learn();
二、getBean()如何找到类
context.getBean("studentService");
大致步骤:
1,解析AppConfig.class,得到扫描路径;
2,遍历扫描路径下的所有的Java类,如果发现某些类上存在@Component,@Service等这些注解,就将这些类记录到一个Map对象中,类似于Map<String, Class>;
3,Map对象中的key是Spring根据某种规则生成的对象名称,也就是beanName,而value值就是对应的类;
4,调用context.getBean(“xxxx”)方法时,即可根据传入的key,找到对应的类了。
三、Spring是如何创建Bean对象的
1,大致步骤:
推断构造方法 ➡ 依赖注入 ➡ Aware接口 ➡ @PostConstruct(初始化前)➡ InitializingBean接口(初始化)➡ AOP(初始化后)➡ 代理对象 ➡ bean对象
1,会调用当前对象的构造方法,默认调用无参构造方法,存在多个构造方法时,Spring需要进行“推断构造方法”,选择其中一个构造方法。
2,扫描当前对象哪些属性上有@Autowired注解,进行依赖注入。
3,判断当前对象是否实现了Aware接口,如BeanNameAware,BeanClassLoaderAware,BeanFactoryAware接口,如实现,则Spring会调用其实现的setBeanName(),setBeanClassLoader(),setBeanFactory()方法,Aware回调。
4,扫描当前对象有哪些方法上有@PostConstruct注解,执行这些方法,这一步为初始化前。
5,判断当前对象是否实现了InitializingBean接口,如实现了,执行afterPropertiesSe()方法,这一步为初始化。
6,判断当前对象是否进行了AOP,若需要AOP,则生成动态代理对象,这一步为初始化后;若不需要AOP,则Bean对象创建完成。
2,Bean对象创建完成后:
1,如果Bean对象是单例的,则会将Bean对象存入到Map中,类似于Map<String, Object>,其中key为beanName,value为bean对象,这样,下次获取Bean对象时,直接通过key找到value即可;
2,如果Bean对象是原型的,那么Bean对象不需要存入到Map中,每次调用getBean()方法时,都会执行上述的过程,创建一个新的Bean对象。
3,推断构造方法
Spring如何选择构造方法,有下述两种情况
1,类中只有一个构造方法,Spring只能调用这个构造方法(有参或者无参)。
2,类中有多个构造方法:
(1)有一个无参构造法,Spring则会调用这个无参的构造方法(默认)。
(2)没有无参构造方法,则Spring会报错。
3,如果存在一个加了@Autowired注解的构造方法,那么Spring则会选择这个注入的构造方法,如果这个构造方法是有参数的,那么Spring会根据参数类型,参数名称找到容器中对应的对象,详细过程如下:
(1)先根据参数对象类型去Spring容器中匹配,如果唯一匹配,则直接注入。
(2)如果类型匹配多个,则再根据参数名称匹配,如果唯一匹配,则直接注入。
(3)如果仍然未找到,则会报错,无法创建Bean对象。
总之,上述Spring如何选择构造方法的过程,就叫做“推断构造方法”。
四、AOP大致流程
1,创建完一个Bean对象,Spring是如何判断当前Bean对象是否需要进行AOP,即是否需要进行动态代理,AOP的大致流程如下:
1,扫描所有的切面类。
2,判断切面类中哪些方法是否加了@Before,@After等注解,找到所有的切面方法。
3,根据切面方法的Pointcut,判断是否是当前的Bean对象类型,如是,则需要进行AOP。
2,根据Cglib进行AOP的大致流程:
1,创建一个StudentServiceProxy代理类,继承StudentService类。
2,重写父类中的方法。
3,代理类StudentServiceProxy中的target对象,实际上是普通对象,或者说是被代理的那个StudentService对象,该对象是经过推断构造方法,依赖注入,初始化等过程创建完成的。
4,通过StudentServiceProxy代理类调用父类方法,实际上是先执行切面类中的@Before方法,然后再通过target对象调用test()方法。
简而言之,上述代理类执行过程如下,StudentService代理对象.test() ➡ 执行切面逻辑 ➡ target.test()方法。
五、Spring事务
当我们在一个方法上加上了@Transaction注解时,就表示开启了Spring事务,这个方法所属的类,就会生成代理类。
Spring事务的代理类的执行大致过程如下:
1,判断当前类中的方法,是否存在@Transaction注解。
2,若存在,则事务管理器(TransactionManager)会新建一个数据库连接。
3,修改数据库连接的autocommit为false。
4,执行target.test(),即执行程序员自己写的方法,执行SQL语句。
5,如果抛出异常,则进行事务的回滚,否则正常提交。
Spring事务是否会失效的标准:某个加了@Transaction注解的方法在被调用时,是否是直接被代理对象调用的,如果是,则事务会生效,如果不是,则事务会失效。
总结
本节课,对Spring的配置方式有了个简单的了解,比如有XML方式和配置类方式,但是不管是哪张配置方式,在Spring中,通过context.getBean()方法获取Bean对象的原理都是大致相同的,都是创建了一个Map<String,Class>来保存对象名称(key)以及对应的类(value),然后通过key获得value;接着,进一步了解了Spring创建Bean对象的大致流程,粗略有7步或8步,在这一流程中,又对其中的推断构造方法,AOP动态代理进行了展开说明,如Spring是如何选择构造方法,怎么判断一个Bean对象是否需要进行动态代理,以及Cglib动态代理的大概过程;最后,由AOP引出了在Spring事务中,是如何运用动态代理的。
PS:上述整理,是本人经过一节网课学习后,进行复习整理,如果有错误或不准确的地方,还请各位大佬们指出。