全面了解学习Spring

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);
工厂方法创建对象
推断构造方法*
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值