Spring基本概念

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

  1. 以xml <bean>的形式
  2. @service @Component 注解的方式
  3. FactoryBean
  4. 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的实现

  1. mybatis-spring-boot-starter ; parent -> mybatis-spring-boot; 引入了 mybatis-spring mybatis-spring-boot-autoconfigure
  2. 在mybatis-spring中,@MapperScan extend Import , MapperScannerRegistar implements ImportBeanDefinitionRegistrar
  3. 这个ImportBeanDefinitionRegistrar 比 BeanDefinitionRegistryPostProcessor 多了一个入参,AnnotationMetadata;
  4. 这个MapperScannerRegistar 继承了 spring- context中的 ClassPathBeanDefinitionScanner
  5. 这时它的 useDefaultFilters= false ; 不用spring默认的扫描策略;如过滤@component @Reposigory @Service @Controller
  6. 添加 AnnotationTypeFilter,这个filter有很多构造方法,如 注解的、接口的;
  7. TypeFilter
  8. 用spring doScan那一套;找到BeanDefinitionHolder集合;
  9. 设置 BeanClass 为 MapperFactoryBean extengs FactoryBean 工厂Bean;
  10. 构造Bean的时候,它会调用 MapperFactoryBean.getObject();
  11. SqlSessionDaoSupport getObject -> MapperProxyFactory -> Proxy.newProxyInstance(ClassLoader, MapperProxy) -> MapperProxy implements InvocationHandler -> invoke
  12. MapperMethod INSERT/UPDATE/DELETE/SELECT/FLUSH
  13. 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配置类

  1. 什么样的才符合配置类; 加了 @Configuration @Import @ImportResource @Component @ComponentScan 注解; 排除掉实现了 BeanFactoryPostProcessor BeanPostProcessor EventListenerFactory AopInfrastructureBean
  2. 为什么需要configuration https://www.cnblogs.com/chenhuadong12/p/14245689.html 避免了多例的出现

Spring Enviroment

  1. 包含 profile 和 properties
  2. spring.profile.active=test
  3. properties application.yml
  4. @propertySource("classpath:application.property")

Spring cglib动态代理

CallBack

Spring Aware

  1. 方法 ignoreDependencyInterface 忽略 实现了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 接口的类,忽略这些重载类的setter方法注入;
  2. spring如何解析xml;DOM技术; DocumentBuilderFactory.newInstance() DocumentBuilder.parse(xmlPath); Document; NodeList; NodeList.item Element; getElementsByTagName("name"); 拿到<name> mingzi</name>;
  3. xml中的检验方式 XSD 和 DTD;xsi:shcemalLocation 网址 <!DOCTYPE beans PUBLIC "xxxx" "http://xxxxxx.dtd">;实际上spring会把这些文件放到jar中;
  4. ResourceEntityResolver 就是spring用来校验XSD 和 DTD的;BeansDtdResolver就是用来获取DTD声明文件的解析器,而PluggableSchemaResolver是用来获取XSD声明文件的解析器;
  5. Spring是如何判断xml是xsd 还是dtd的呢?在解析的时候,会解析xml文件头中两个参数 systemId 和 publicId ;如果systemId以dtd结尾,那就认为是DTD文件;systemId长啥样呢
    image.png

    publicId: -//SPRING/DTD BEAN//EN
    systemId: http://www.springframework.org/dtd/spring-beans.dtd

从Spring boot启动开始看Spring加载过程

  1. AbstractApplicationContext refresh()

  2. 根据ClassUtil 看有没有类,默认是 AnnotationConfigurationApplicationContext

  3. refresh 主要过程 initProperties context environment.

  4. 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
处理循环引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容