Spring的底层的整体了解
1、Bean的声明周期底层原理
2、依赖注入的底层原理
3、初始化底层原理
4、推断构造方法底层原理
5、AOP底层原理
6、Spring事务的底层原理
Spring的大致流程
首先三个类
1、ClassPathXmlApplicationContext("xxx.xml") 过时
2、AnnotationConfigApplicationContext("xxxx.class") 一般整这个
3、XmlWebApplicationContext("xxxx.xml") Spring MVC的
通过这个类可以创建一个对应的对象context(上下文对象)
调用context.getBean("userService");可以获取一个UserService的对象
然后通过这个userService的对象就可以调用它本身的方法了
释义:
1、AnnotationConfigApplication入参一个class,用于加载xxx,class
2、spring会判断xx.class中的@ComponentScan的扫描包路径
3、遍历扫描包下所有标注了@Componet、@Service等注解,那么spring就把这个记录存下来放到一个Map中Map<String, Class> beanName是String,Class存储的是类,对应到spring中设计的是BeanDefinitionMap
4、Spring会根据某个规则生成当前类对应的beanName,作为key存入Map,当前类作为class
5、当调用context.getBean(“beanName”),就可以根据beanName找到对应的Bean类然后去创建对象
Bean的创建过程
接下来要解惑对bean的创建过程、spring到底是如何创建了一个bean,生命周期是怎么样的来进行讲解。
1、利用该类的构造方法来实例化出来一个对象(构造方法的推断,默认采用无参构造方法)
2、得到一个对象之后就需要做属性注入的操作,依赖注入,将@Autowired标注的实体赋值到对象中
3、依赖注入之后,spring会判断该对象有没有实现BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前的对象必须实现接口中定义的setBeanName()、setBeanClassLoader()、setFactory()方法,那么spring就会调用这些方法传入对应的参数(Aware回调)
4、Aware回调之后,spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,spring会调用当前对象的此方法(初始化前)
5、紧接着看一下该对象是否还实现了initalizingBean接口,如果实现了,就表示当前对象需要在初始化做一些操作,必须实现接口中的afterPropertiesSet()方法,那么spring会调用当前对象中的afterPropertiesSet()方法中做一些初始化的操作。
6、最后spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完了,如果需要进行AOP,则会进行创建一个Bean的动态代理对象作为Bean(初始化后)
附加备注:
如果使用了AOP,那么得到的Bean就是xxx类的代理对象
如果不使用AOP,那么得到的Bean就是xxx类的本身对象
spring的推断构造方法
1、如果只有一个构造方法,不管有参无参,使用这个构造方法
2、如果一个类存在多个构造方法
①如果有无参构造和有参构造,使用无参的构造方法
②如果没有无参构造,spring报错
spring依赖注入中的推断构造思想
1、如果一个类只有一个构造方法,只能用这个构造方法
2、如果一个类有多个构造方法,默认会找是否有无参的构造方法,因为无参构造方法本身表示了一种默认的意义
3、如果某个构造方法上被加了@Autowired注解,那就表示告诉spring就用这个加了注解的方法,那spring就会用这个加了@Autowired注解的构造方法,如果是有参的构造方法,spring会根据入参的名字和入参的类型去找bean,先根据Type在根据Name去找,最终如果没有找到,则会报错,无法创建当前Bean对象
AOP的大致流程
Aop就是进行动态代理,在创建一个bean的时候,spring会判断这个bean是不是需要进行Aop,如果需要就进行aop创建代理对象
那么如何判断当前对象是否需不需要Aop呢?
1、遍历所有切面bean
2、遍历切面bean中的每个方法,看是否写了@Before、@After等注解
3、如果写了,则判断对应的Pointcut是否和当前bean对象的类是否匹配
4、如果bean对象的类有匹配上的Pointcut,表示需要进行aop
动态代理
动态代理分JDK动态代理和CGLIB动态代理
JDK动态代理:
CGLIB动态代理:
利用cglib进行AOP的流程
1、生成代理类对象XXXProxy,代理类继承XXX
2、代理类重写了父类方法,比如xxx中的test()方法
3、代理类中还有一个target属性,该属性的值为被代理对象(也是同过xxx类进行推断构造方法实例化出来的对象,进行了依赖注入、初始化等步骤的对象)
4、代理类中test()方法执行的逻辑是,先执行@before中的方法,在调用target.test()方法(被代理类的test方法)
备注:当我们从Spring容器中得到xxx的Bean对象时,拿到的就是xxx对象的代理对象。当执行代理对象的test方法时,先执行切面逻辑---->被代理对象的test方法。具体执行的方法是被代理对象而不是代理对象。
spring事务
当在某个方法上加上@Transaction注解后,就表示该方法在调用时会开启spring的事务,而这个方法所在的类所对应的bean对象就是该类的代理对象
spring事务代理对象执行某个方法时的步骤
1、判断当前执行的方法是否存在@Transaction注解
2、如果存在,则利用事务处理器(@TransactionManager)新建一个数据库链接
3、修改数据库链接的autocommit为fasle
4、执行target.test()方法,执行程序所写的逻辑代码,也就是sql
5、执行完成之后如果没有出现异常则提交,否则则会滚
spring事务是否会失效的判断标准
1、@Transaction注解的方法被调用时,要判断到底是不是直接被代理对象调用的,如果是则事务生效,如果不是则失效
2、方法不是public的
spring官方文档描述:
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
意思为@Transactional注解只能用于public的方法上,否则事务不会失效,如果要用在非public方法上,可以开启AspectJ代理模式。
3、 catch吃掉了异常,异常也不会进行回滚
4、异常类型错误,也不会生效,因为默认回滚的是RuntimeException,如果想触发其他异常的回滚,需要在在注解上配置一下如:
@Transaction(rollbackFor = Exception.class)
不会回滚的实例:public void updateOrder(Order order) { try { // update() } catch { throw new Exception(”更新错误“) }
Spring详细深入
1、BeanDefinition
2、BeanDefinitionReader(xxxReader)和MetadataReader
3、BeanFactory和ApplicationContext
4、
BeanDefinition
BeanDefinition 表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。如
- class,表示Bean类型
- scope,表示Bean作用域,单例或原型等
- lazyInit:表示Bean是否是懒加载
- initMethodName:表示Bean初始化时要执行的方法
- destoryMethodName:表示Bean销毁时要执行的方法
……
Spring中,如果通过一下几种方式定义Bean:
1、 <bean />
2、 @Bean
3、@Component(@Service, @Controller)
这些,我们可以称之为申明式定义Bean
我们还可以编程式定义Bean,那就是直接通过BeanDefinition,比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig,class);
// 生成一个BeanDefinition对象,并设置beanClass,并设置beanClass为User,class,并注册到ApplicationContext中。
AbstarctBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
context.registerBeanDefinition("user", beanDefinition);
System.out.println(context.getBean("user"));
我们还可以直接通过BeanDefinition设置一个bean的其他属性
beanDefinition.setScope("prototype");//设置作用域
beanDefinition.setInitMethodName("init");//设置初始化方法
beanDefinition.setLazyInit(true);//设置是否是懒加载的
和声明式事务、编程式事务类似,通过<bean />,@Baen,@Component等声明式方式所定义的Bean,最终都会被Spring解析成对应的BeanDefinition对象,并放入spring容器中。
BeanDefinitionReader
BeanDefinition读取器 (BeanDefinitionReader),这些BeanDefinitionReader在我们使用Spring时用得少,但在Spring 源码中用得多,相当于Spring源码的基础设施。
个人见解:BeanDefinitionReader的作用是spring加载每个需要加载的类转换成BeanDefinition的过程
AnnotatedBeanDefinitionReader
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,比如
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context); // 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);
System.out.println(context.getBean("user"));
备注:它解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、 @Role、@Description
XmlBeanDefinitionReader
可以解析<bean />标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(context.getBean("user"));
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以 进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在==@Component 注解==,那么就会把这个类解析为一个BeanDefinition,比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.didi.saas.dky");
System.out.println(context.getBean("userService"));
BeanFactory
BeanFactory顾名思义就是创建Bean的工厂,BeanFactpry会负责创建Bean,并提供获取Bean的API
ApplicationContext是BeanFactory的一种
ApplicationContext
spring中的接口如下:
JAVA接口是多实现的,我们发现ApplicationContext不仅实现了BeanFactory还有一些其他的接口,这样就可以理解为ApplicationContext本质是一个BeanFactory并对BeanFactory做了很多的扩展。
Spring的可以干预生命周期的一些操作
1、实例化的一些操作
- 实例化前(impl InstantiationAwareBeanPostProcessor)
- 实例化
- BeanDefinition的后置处理(impl MergedBeanDefinitionPostProcessor)
bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点。就是MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()方法可以对此时的BeanDefinition进行加工 - 实例化后 (impl InstantiationAwareBeanPostProcessor)
重写postProcessAfterInstantiation()
附加:
自动注入
处理属性 (impl InstantiationAwareBeanPostProcessor.postProcessProperties())
执行Aware
2、初始化前
3、初始化
4、初始化后
4、AOP生成代理对象
实例化前
当BeanDefinition对应的类成功加载后就可以实例化对象了,但是在spring中,实例化对象之前,spring提供了一个扩展点,允许用户来控制是否在某个或者某些Bean实例化之前做一些启动动作。这个扩展点就是 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
e.g.:
@Component
public class UserService implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClassm String beanName) throws BeansException
{
return new UserService();
}
}
userService这个Bean,在实例化钱会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后的这一步。
加餐之正常流程-实例化操作
实例化的操作就是根据BeanDefinition去创建一个对象了
Supplier创建对象
首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()的得到对象。的直接使用BeanDefinition对象来设置Supplier。
e.g.
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericaBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>(){
@override
public Object get() {
return new UserService();
}
});
context,registerBeanDefinition("userService", beanDefinition);