Spring中的@Autowired与@Resource的区别
我们都知道@Autowired注解可以加在属性或者方法上,那Spring是如何对它进行处理的;
开门见山,@Autowired注解通过处理 -- AutowiredAnnotationBeanPostProcessor进行处理,它实现了个重要的接口:InstantiationAwareBeanPostProcessor 和 postProcessProperties;
通过找到InjectMetaData调用inject方法;如果是属性Field,调用field.set(target, object)方法; 如果是方法,则调用Method.invoke(obj, args); 很简单吧
InjectMetaData有两个子类:
第一个是AutowiredFieldElement, inject(bean,beanName,propertyValues)是它一个非常 重要方法, Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); 从DefaultListableBean获取Bean
第二个是 AutowiredMethodElement
说说注入方式 ShortcutDependencyDescriptor
注入方式在AbstractBeanDefinition中定义了,有Constructor-3、byName-1、byType-2、0-手动注入-Constant that indicates no external autowiring at a
@Autowired和@Resource的区别主要体现在到底选择那个bean注入呢;
@Autowired、@Value、和实现了Inject接口的注解类型;
第三方对象如何注入Spring
- 以xml <bean>的形式
- @service @Component 注解的方式
- FactoryBean
- Configuration @Bean
Mybatis如何动态执行xml或者@Select注解的SQL
第一步:通过Configuration 注册 MapperRegistry 将接口放进knowMapper是这个容器当中;
MapperProxyFactory -> T new Instance(MapperProxy<T> proxy),这个T对象就是 实现了Mapper接口的对象;
Proxy.newProxyInstance(ClassLoader(), new Class[] { mapperInterface }, mapperProxy);
依赖 JDK 动态代理 InvocationHandler.invoke(Proxy,Method,Object[] args)
那最关键的是执行了哪个方法呢? 通过生成了 new MapperProxy<T>(sqlSession, mapperInterface, methodCache); 执行里面的invoke方法;
invoke方法最后还是执行到 MapperMethod里面的exceute(SqlSession, args)方法;
最后最后执行到 sqlSession.insert(String sql, Object param)\ sqlSession.update(String statement) \ update(String statement, Object parameter) \ delete(String statement)
关于mybatis是执行什么样的SQL,还有很深的地方需要去探索
BeanDefinition
ConstructorArgumentValues
可以是 Map<Integer, ValueHolder> List<ValueHolder>,用于方法传递参数
scope
默认singleton 单例
Lazy
默认 false getBean的时候加载
DependentOn
BeanClass
MutablePropertyValues
存Bean对象,依赖注入时用;
调用所有BeanFactoryProcessor
List<BeanFactoryPostProcessor> ,
正常Bean实例化之后,放入单例池当中
Map<String, Object> singletonObjects
Spring实例化bean 与 BeanDefinition 相关
并不是直接与Class相关,所以我们可以修改BeanDefinition中的BeanClassName,改变spring实例化Bean的类型;
BeanFactory
-- BeanPostProcessor
-- BeanFactoryPostProcessor
-- BeanDefinitionRegistryPostProcessor 根据启动的应用上下文是不是BeanDefinitionRegistry 的BeanFactory,然后你的后置处理器是BeanDefinitionFactoryPostProcessor,那就在这里添加BeanDefinition;
-- 普通的后置处理器
// First, register the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
实现了PriorityOrdered接口的,最新被执行 添加/修改BeanDefinition的动作;
// Next, register the BeanPostProcessors that implement Ordered.
// Now, register all regular BeanPostProcessors.
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
为什么最后还要去执行一下呢?因为防止BeanDinition中又带了新的Bean或者BeanDefinitionRegistrar
//// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
父类的BeanFactoryPostProcessers() 方法
// 执行 postProcessBeanFactory
问题1. BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 的关系,谁先执行,为什么?
答案:a. BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
b. 分别对应的方法 void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
和 void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
c. 先执行子类方法--postProcessBeanDefinitionRegistry 后执行父类的方法 -- postProcessBeanFactory
d. BeanDefinitionRegistryPostProcessor 先执行,它会先注入BeanDefinition,BeanFactoryPostProcessor会在Bean实力例之后修改、添加属性;
问题2. @Value是如何实现的
通过AutowiredAnnotationBeanPostProcessor ,Java.inject.Inject 注入方法
a. 构造函数
b. 字段
c. 方法
d. Lookup方法
问题3 @Value转换是如何进行的?比如Map类型数据如何转换
问题4: ImportBeanDifinitionRegistrar 和 BeanDefinitionRegistrarPostProcessor 的区别
都可以注入BeanDefinition执行时机,谁先谁后? 如果BeanDefinitionRegistrarPostProcessor是启动注入或者是内置的,则先于 ImportBeanDifinitionRegistrar
BeanDifinitionRegistrarPostProcessor根据来源的不同,分Api、内置的、
@Import注解注入 ImportBeanDifinitionRegistrar
ClassPathMapperScanner do scan 扩展扫描
Bean的生命周期
执行@PostConstruct 注解,然后执行实现了
@Autowired手动注入 将 setWridType(2) 设置为自动注入
应用1 Mybatis的实现
- mybatis-spring-boot-starter ; parent -> mybatis-spring-boot; 引入了 mybatis-spring mybatis-spring-boot-autoconfigure
- 在mybatis-spring中,@MapperScan extend Import , MapperScannerRegistar implements ImportBeanDefinitionRegistrar
- 这个ImportBeanDefinitionRegistrar 比 BeanDefinitionRegistryPostProcessor 多了一个入参,AnnotationMetadata;
- 这个MapperScannerRegistar 继承了 spring- context中的 ClassPathBeanDefinitionScanner
- 这时它的 useDefaultFilters= false ; 不用spring默认的扫描策略;如过滤@component @Reposigory @Service @Controller
- 添加 AnnotationTypeFilter,这个filter有很多构造方法,如 注解的、接口的;
- TypeFilter
- 用spring doScan那一套;找到BeanDefinitionHolder集合;
- 设置 BeanClass 为 MapperFactoryBean extengs FactoryBean 工厂Bean;
- 构造Bean的时候,它会调用 MapperFactoryBean.getObject();
- SqlSessionDaoSupport getObject -> MapperProxyFactory -> Proxy.newProxyInstance(ClassLoader, MapperProxy) -> MapperProxy implements InvocationHandler -> invoke
- MapperMethod INSERT/UPDATE/DELETE/SELECT/FLUSH
- sql = SqlCommand.getName()
-- TODO 需要研究一下Mybatis的动态代理是如何进行的
Spring注解的高级应用
1 @LookUp
作用在抽象方法上,提供产生原型类;
2 @Supplier
需要静态工厂 或 实例工厂提供Bean的方法上; GenericBeanDefinition definition = new GenericBeanDefinition(); //优先 definition.setInstanceSupplier(); //反射效率低 definition.setFactoryName("factoryName"); definition.setFactoryMethodName("factory-method");
Spring 的注入模型
1 注入方式
a. 构造函数
b. set方法
2 默认手动注入 自动注入
Configuration配置类
- 什么样的才符合配置类; 加了 @Configuration @Import @ImportResource @Component @ComponentScan 注解; 排除掉实现了 BeanFactoryPostProcessor BeanPostProcessor EventListenerFactory AopInfrastructureBean
- 为什么需要configuration https://www.cnblogs.com/chenhuadong12/p/14245689.html 避免了多例的出现
Spring Enviroment
- 包含 profile 和 properties
- spring.profile.active=test
- properties application.yml
- @propertySource("classpath:application.property")
Spring cglib动态代理
CallBack
Spring Aware
- 方法 ignoreDependencyInterface 忽略 实现了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 接口的类,忽略这些重载类的setter方法注入;
- spring如何解析xml;DOM技术; DocumentBuilderFactory.newInstance() DocumentBuilder.parse(xmlPath); Document; NodeList; NodeList.item Element; getElementsByTagName("name"); 拿到<name> mingzi</name>;
- xml中的检验方式 XSD 和 DTD;xsi:shcemalLocation 网址 <!DOCTYPE beans PUBLIC "xxxx" "http://xxxxxx.dtd">;实际上spring会把这些文件放到jar中;
- ResourceEntityResolver 就是spring用来校验XSD 和 DTD的;BeansDtdResolver就是用来获取DTD声明文件的解析器,而PluggableSchemaResolver是用来获取XSD声明文件的解析器;
- Spring是如何判断xml是xsd 还是dtd的呢?在解析的时候,会解析xml文件头中两个参数 systemId 和 publicId ;如果systemId以dtd结尾,那就认为是DTD文件;systemId长啥样呢
publicId: -//SPRING/DTD BEAN//EN
systemId: http://www.springframework.org/dtd/spring-beans.dtd
从Spring boot启动开始看Spring加载过程
AbstractApplicationContext refresh()
根据ClassUtil 看有没有类,默认是 AnnotationConfigurationApplicationContext
refresh 主要过程 initProperties context environment.
-
beanFactory 产生bean对象;
a. 忽略接口方法 EnvironmentAware EmbeddedValueResolverAware ResourceLoaderAware ApplicationEventPublisherAware MessageSourceAware ApplicationContextAware
那是不是就忽略注入实现这些接口的类呢? 不是的,它是指不对这些接口下的方法进入注入;总所周知,注入分为 属性注入、方法注入 @Autowired
b. 注册依赖 BeanFactory ResourceLoader ApplicationEventPublisher ApplicationContext
c. ProcessBeanFactory 允许加入自定义的 scanner扫描包 reader
d. BeanFactoryPostProcessors invokeBeanFactoryPostProcessors
d.1 如果他是一个 BeanDefinitionRegistryPostProcessor
就通过postProcessBeanDefinitionRegistry方法 把它给扔到 Map<String, BeanDefinition> 中去
最先开始它是先处理前面内置的几个
后面它就开始扫描实现了 BeanDefinitionRegistryPostProcessor的Bean类
按照 PriorityOrdered Ordered 的顺序最后还要执行父类的 postProcessBeanFactory 这个方法就是执行注入一个Bean并实例化啦
例子,redis的实例化 用 BeanDefinitionRegistryPostProcessor 注入 BeanDefinition,这里为什么不直接注入Bean呢?
因为有的时候我们需要获取到一些配置类的注解信息,拿到实现了 ExtRedisTemplateConfiguration 的这个BeanDefinition的注解信息,构建RedisTemplate最后执行 postProcessBeanFactory 注入 redisTemplate、stringRedisTemplate 两个通用的
d.2 如果不是 则直接执行 invokeBeanFactoryPostProcessors
d.3 还有再执行一次 invokeBeanFactoryPostProcessors 为什么呢? 因为它有可能产生了新的 BeanFactoryPostProcessor
同样它也是按照 PriorityOrdered Ordered no ordered的顺序来
e. registerBeanPostProcessors 注册BeanPostProcessor接口,那么BeanPostProcessor接口做了什么呢?
方法 postProcessBeforeInitialization(Object bean, String beanName) 执行 afterPropertiesSet 或者 init-method
f. 实例化所有的非懒加载的单例Bean, 先判断是不是工厂Bean
InstantiationAwareBeanPostProcessor
处理循环引用