文章目录
视频链接
BeanDefinition
BeanDefinition用来表示Bean定义。
Spring根据BeanDefinition来创造对象。
BeanDefinition中重要的属性
- beanClass
表示bean类型 如UserService.class,OrderService.class
Spring在创建Bean的过程中会根据此属性来实例化得到对象 - scope
bean的作用域
如singleton,单例Bean;prototype,原型Bean. - isLazy
表示bean是否需要懒加载,原型Bean的isLazy属性不起作用
懒加载的bean会在第一次getBean生成
非懒加载的bean在spring启动时就会生成 - dependsOn
该bean创建前所以来的其他bean,该bean创建前,他依赖的bean要创建好 - primary
表示该bean是个主bean。在spring中同一个类型可能有多个bean对象,在进行依赖注入时会判断是否有主bean,如果有则直接注入 - initMethodName
表示一个bean的初始化方法,bean生命周期有个步骤是初始化,Spring会在这个过程中去调用bean的初始化方法,程序员可以自定义逻辑对bean进行初始化。
@Component,@Bean, <bean/>都会解析为BeanDefinition对象。
BeanFactory
一种“spring容器”,用来创建bean,获取bean
BeanFactory利用Beandefinition来生成Bean对象。
核心子接口和实现类:
ListableBeanFactory
ConfigurationBeanFactory
AutowiredCapableBeanFactory
AbstractBeanFactory
DefaultListableBeanFactory:支持单例Bean,Bean别名,父Beanfactory,Bean类型转化,Bean后置处理,FactoryBean,自动装配等等
Bean生命周期
Spring中创建到销毁一个Bean的过程。创建是重点。程序员可以利用Bean生命周期对Bean进行加工。
核心步骤
- BeanDefinition对象创建
- 构造方法推断-选出一个构造方法
- 实例化-构造方法反射得到对象
在Spring中,可以通过BeanPostProcessor机制对实例化进行干预 - 属性填充-属性自动填充
实例化得到的对象中的某些属性还没进行属性填充,属性填充就是自动注入,依赖注入。 - 初始化-对其他属性赋值,校验
程序员可以利用初始化机制对Bean进行自定义加工,比如利用InItializingBean接口来对Bean中的其他属性进行赋值,或者对Bean中的某些属性进行校验。 - 初始化后-AOP,生成代理对象
AOP机制就是在这个步骤中通过BeanPostProcessor机制实现的,初始化后的得到的对象才是真正的Bean对象。
@Autowired
表示某个属性是否需要依赖注入,可以写在属性和方法上。注解中的required属性默认为True,表示如果没有对象注入给属性则抛异常。
写在属性上,Spring在bean的生命周期中的属性填充时,会基于实例化出来的对象,对该对象中加了Autowired的属性自动给属性赋值。
Spring会吸纳根据属性的类型去Spring容器中找出该类型所有的bean对象,找出多个,再根据属性名字确定。如果required为true,并且根据属性信息找不到对象,则直接抛异常。
写在方法上,Spring在bean的生命周期中的属性填充时,会根据方法的参数类型,参数名字从Spring容器中找到对象当做方法入参,自动反射调用该方法。
加载构造方法上,Spring会在推断构造方法阶段,选择该构造方法进行实例化,在反射调用构造方法之前,会先根据构造方法参数类型,参数名从Spring容器中找到Bean对象,当做构造方法入参。
@Resource
和@Autowired类似,也是进行依赖注入的。@Resource是java层面提供的注解,@Autowired是Srping提供的注解,依赖注入的底层实现逻辑也不同。
@Resource中有个name属性,针对name是否有值,@Resource的依赖注入底层流程不同的。
如果有值,那么Spring会根据name直接去Spring容器中寻找Bean对象,如果找到则成功,否则报错。
如果没有值,判断属性名字在Spring容器中是否有bean对象,如果有则成功注入。如果不存在则根据属性类型去Spring容器中找Bean对象,找到一个则进行注入。
@Value
也是进行依赖注入的,只不过@Value从properties文件中取值,并且@Value可以解析SpringEL表达式
@Value(“zhouyu”) 直接将zhouyu赋值给属性,如果属性类型不是String,或者无法进行类型转换,则报错。
@Value(“${zhouyu}”)会把 ${}中字符串当做key去properties文件中找出对应value赋值给属性,如果没找到,则会把“”中当做普通字符串注入给属性。
@Value(“#{zhouyu}”)会把字符串当做Spring表达式来进行解析 Spring会把zhouyu当做beanName,并从Spring容器中找到对应的bean,如果找到则进行属性注入,没找到则报错。
FactoryBean
Spring所提供的一种比较灵活的创建bean的方式,可以通过实现FactoryBean接口中的getObject()方法来返回一个对象,这个对象就是最终的bean对象。
FactoryBean是一个bean对象,也是一个小型工厂,可以生产出其他的bean
beanFactory是一个Spring容器,是一个大工厂,能生产出各种各样的其他bean
factoryBean被广泛应用于Spring内部和与第三方整合的过程中。
ApplicationContext
AppliactionContex是比beanFactory更加强大的Spring容器,它既可以创建bean,获取bean还支持国际化,时间广播,获取资源等beanFactory不具备的功能。
继承的接口有
- EnvironmentCapable
拥有获取环境变量的功能,可以通过applicationContext获取操作系统变量和JVM环境变量。 - ListableBeanFactory
拥有获取所有beanNames,判断某个BeanName是否存在beanDefinition对象,统计beanDefinition个数,获取某个类型对应的所有beanNames等功能。 - HierarchicalBeanFactory
获取父BeanFactory,判断某个name是否存在bean对象的功能 - MessageSource
拥有了国际化功能,比如利用MessageSource对象获取某个国际化资源(比如不通国家语言所对应的字符 ) - ApplicationEventPublisher
事件发布功能 - ResourcePatternResolver
拥有加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。
BeanPostProcessor
Spring提供的扩展机制,可以利用该机制对Bean进行定制化加工,在Spring底层源码实现中,也广泛用到了该机制,BeanPostProcessor通常叫做Bean后置处理器。
BeanPostProcessor是一个接口,我们定制一个后置处理器,就是提供一个类来实现该接口。在spring中存在其他类继承该接口,这些子接口在beanpostprocessor的基础上增加了一些其他的功能。
postProcessbeforeInitialiation
初始化前方法,表示可以利用这个方法来对Bean在初始化前进行自定义加工。
postProcessAfterInitialiation
Bean初始化后进行自定义加工。
instantiationAwareBeanPostPorcessor
BeanPostProcessor的一个接口,
postProcessorBeforeInstantiation()实例化前
postProcessorAfterInstantiation()实例化后
postProcessorProperties()属性注入后
Aop面向切面编程
适合在不修改业务代码的前提下,对某个或者某些业务增加统一的功能,比如日志记录,权限控制,事务管理等,能很好地使得代码解耦,提高开发效率
。
- Advice
通知,建议。在spring中通过定义advice来定义代理逻辑 - Pointcut
切点。表示advice的代理逻辑应用在哪个类哪个方法上。 - Advisor
=advice+pointcut。表示代理逻辑和切点的一个整体。程序员可以通过定义或封装一个Advisor,来定义切点和代理逻辑。 - Weaving
织入。将advice代理逻辑在源代码级别嵌入切点的过程叫做织入。
-Target
被代理对象。在aop生成的代理对象中会持有目标对象。 - JointPoint
表示连接点。在spring aop中就是方法的执行点。
工作原理
aop发生在bean的生命周期过程中的:
1.spring生成bean对象过程中,会先实例化出来一个对象,也就是target对象
2.在对target对象进行属性填充
3.在初始化后步骤中,会判断target对象有没有对应的切面
4.如果有切面,就表示当前对象需要进行aop
5.通过cglib或者jdk动态生成代理对象,作为最终的bean对象
6.代理对象中有一个target属性指向了target对象
javaBean,SpringBean和对象区别
bean肯定是对象
对象 User user =new User();
javaBean user中属性都是私有,对外提供getter和setter。
spring Bean spring生成的对象。
定义bean
1.xml定义 <bean></bean>
ClassPathXmlApplicationContext 基于类中构造方法生成对象
2.类定义@Bean
AnnotationConfigApplicationContext new出来的
3.@Component
以上是声明式的
4.编程式的BeanDefinition
标签、注解、component、BeanDefinition
5. FactoryBean
6.supplier
单例池,单例Bean,单例模式的区别
User 单例Bean==spring容器中只能有一个User类型的bean (×)
单例池,存储单例bean,实现单例bean功能 ConcurrentHashMap stringObject beanName object
非懒加载的单例Bean spring启动时创建好
BeanFactory, ApplicationContext
BeanFactory容器 Beandefinition/对象
BeanFactory继承单例池。
ApplicaitonContext继承 xxxBeanFactory
多了国际化,发布时间,获取环境等方法。
applicationContext常见实现类:applicationConfigApplicationContext,ClassPathXmlApplication,FileSystemXmlApplicaitonContext。
1.可不可以刷新2.spring配置的展现形式
ClassPathXmlApplication 相对于classpath (可刷新)
FileSystemXmlApplicaitonContext 相对于项目工程,也支持绝对路径
AnnotationConfigApplicationContext(不可刷新)
刷新相当于重启。重新加载容器,可以修改。看是否继承
Bean的生命周期
创建生命周期,销毁生命周期
实例化
beanPostProcess 在实例化对象后进行处理,可以类似实现autowired
可以设置指定被代理对象。
实例化前
实现instantiationAwareBeanPostProcessor
重写postProcessBeforeInstantiation
实现实例化前的操作
推断构造方法
- 多个构造方法,spring无法判断时,会先调用无参的构造方法。
- 可以用autowired来指定。
- @Autowired(required=false)时,优先匹配多个参数的构造方法。
- 参数个数相同,且都能匹配到,按照顺序来。
实例化后
实现instantiationAwareBeanPostProcessor
重写postProcessAfterInstantiation return false时,不再走spring的逻辑
初始化
实现InitializingBean接口
重写afterPropertiesSet方法
@PostConstruct 属性注入后,初始化前 针对bean
初始化前
实现BeanPostProcessor接口
重写postProcessorBeforeInitialization
- 返回null不会执行其他的初始化前方法
- 返回bean会接续执行
初始化后
重写postProcessorAfterInitialization
可以在此进行aop
Proxy.newProxyInstance(类加载器,类实现的接口,new InvocationHandler{
@Override
public Object invoke(Object proxy,Method method,object[] args){
sout 代理逻辑
method.invoke(bean,args);
}
});
autowired 先类型匹配再进行名称匹配。
单例bean 根据同一个名字拿,拿到的是同一个bean
原型,多例,不是同一个
单例池,实现单例bean Map存储
spring 定义bean,还得能加载到才能使用。
编程式:有了beandefinition还得registerBeanDenifition 定义对象需要有构造方法(不能是接口)
声明式:有了@Component还得@ComponentScan(“包路径”)
idea 点击属性时,调用的是属性的toString方法
MyBatis
创建后调用方法,会找不到userMapper类
@Mapper到springboot才用到
userMapper接口,需要存储在spring容器中。
可以是实现类或者代理对象,代理对象由mybatis产生,将代理对象放入spring容器中成为springbean
spring事务
- 声明式 @Transan
- 编程式 TransManager创建
srping 定义Bean - 声明式
<Bean/> @BEAN @Component
需要添加扫描才能添加到
- 编程式 beanDefinition
beanDefinition创建对象,设置BeanClass后,调用registerBeanDefinition添加到spring 容器中
接口不可以这样,因为创建bean时,会进行实例化,接口,没有构造方法会实例化失败
新建类实现FactoryBean
定义一个类返回两个对象,注册时xxx为person,&xxx为源对象
其中persion变为了spring对象,因此在该类中getObject方法中放入mapper接口的代理对象。
proxy.newProxyInstance(classLoader(这里使用当前类的),被代理接口,newInvocationHandler){}
null不报空指针是因为toString
最后通过替换FactoryBean实现类中的class,私有属性,新建构造方法传入类,即可复用。
beanDefinition.getConstructArgumentValues(). addGenericArgumentvalue();
注册代理对象类代码优化
新建类继承 importBeanDefinitionRegistarar
在spring启动类上添加注解@Import(LubanImportBeanDefinitionRegistarar)
重写方法,利用spring扫描逻辑进行复制和注册到spring容器中。
在这之前新建类继承ClassPathBeanDefinitionScanner
使用sqlsession获取代理对象。
动态获取路径,手写注解,value值,将import(创建bean的类)放入新写的注解上,利用registerBeanDefinition方法中的AnnotionMetadata
importClassMetadata来获取注解参数来获取path。
循环依赖
java类中相互依赖没有问题。但是在spring中根据bean的生命周期会出现问题。
例如A和B相互依赖
springBean的生命周期:实例化,自动填充,aop,放入单例池。
在自动填充时,他们会寻找依赖的bean,现在单例池中找,然后去spring容器中找,都找不到就回去创建,而相互依赖会导致这个过程一直反复。
解决方法:新增map进行缓存,在生命周期实例化时,将新建但未赋值的对象放入map中。
新建A对象,对a对象中的b对象赋值,发现没有b对象,于是创建b对象,在b对象中对a对象赋值,a对象虽然为未赋值的实例化对象,但是最后在给a中的属性赋值,也就是图中的a.b=b。
在循环依赖的过程中,生命周期有其他属性赋值,因此缓存并不会产生问题。
赋值需要代理对象,否则无法调用方法。产生新问题:提前进行aop
直接将代理对象放入map中。
判断是否有循环依赖,并且有切面,才会提前aop。
在2.2部判断是否有循环依赖,
还在写