死磕Spring源码-常见底层核心注解
一:Spring框架功能整体介绍
二:根据Spring架构图可知,包含以上的模块儿。下面逐个模块儿进行解释。
1:IOC 和 DI(Inversion of Control I DependencyInjection ( IoC/DI ) 最最最最核心的功能是 :通过多级缓存解决循环依赖问题。
2:Spring Core Container:
模块作用:Core 和 Beans 模块是框架的基础部分,提供 IoC (转控制)和依赖注入特性,Spring Core也是核心层,拥有着BeanFactory这个强大的工厂,是所有bean的管理器。负责发现、创建并处理bean之间的关系的一个工具包。提供了对工厂模式的经典实现,实现对程序单例模式的需要。并真 正地允许你从程序逻辑中分离出依赖关系和配置。core主要包含 Spring 框架基本的核心工具类, Spring 的其他组件都要用到这个包 里的类, Core模块是其他组件的基本核心。
Spring Beans(BeanFactory):其中最重要的两个接口是:BeanFactory和BeanDefinition。BeanFacoty:是springIOC核心工厂接口,根据对象的依赖关系进行创建对象。ApplicationContext就是其中的一个具体实现。要定义一个工厂必须满足三个条件1,需要持有各种bean的定义2,需要持有Bean之间的依赖关系3,需要读取xml配置文件的工具。说白了。BeanFactory就是负责对bean的创建。
3:Context
context负责处理BeanFactory,主要的接口是ApplicationContext。ApplicationContext接口继承了ListableBeanFactory和HierarchicalBeanFactory接口他们都继承了BeanFactory接口。ApplicationContext模构建于 Core 和 Beans 模块基础之上,提供了一种类似JNDI 注册器的框 架式的对象访问方法。 Context 模块继承了 Beans 的特性,为 Spring 核心提供了大量扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对 Context 的透明创 建的支持。 Context 模块同时也支持 J2EE 的一些特 性, ApplicationContext 接口是 Context 模块的关键。
4:ApplicationContext和BeanFactory的主要区别
·1,BeanFactory在启动的时候不会去实例化Bean,只有从容器中拿Bean的时候才会去实例化;BeanFactory是懒加载,BeanFactory需要手动注册。优点是:应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
2,ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化; 优点是1. 所有的Bean在启动的时候都加载,系统运行的速度快; 2. 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题 3. 建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)
5:Expression Language(表达式语言)
模块提供了强大的表达式语言,用于在运行时查询和操纵对象。 它是 JSP 2.1 规范中定义的 unifedexpression language 的扩展。 该语言支持设直/获取属 性的值,属性的分配,方法的调用,访问数组上下文( accessiong the context of arrays )、 容器和索引器、逻辑和算术运算符、命名变量。以及从Spring的 IoC 容器中根据名称检 索对象。 它也支持 list 投影、选择和一般的 list 聚合
三:Spring Data Access/Integration
1:jdbc
模块提供了一个 JDBC 抽象层,它可以消除冗长的 JDBC 编码和解析数据库厂 商特有的错误代码。这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类
2:ORM 模块为流行的对象-关系映射 API
如 JPA、 JDO、 Hibernate、 iBatis 等,提供了 一个交互层。 利用 ORM 封装包,可以混合使用所。有 Spring 提供的特性进行 O/R 映射, 如前边提到的简单声 明性事务管理。OXM 模块提供了一个对 ObjecνXML 映射实现的抽象层。Object/XML 映射实现包括 JAXB、 Castor、 XMLBeans、 JiBX 和 XStrearn
3:JMS ( Java Messaging Service )
模块主要包含了 一些制造和消 费消息的特性。
4:Transaction
支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并 且对所有的 POJO 都适用
5:Spring Web
Web 模块:提供了基础的面向 Web 的集成特性c 例如,多文件上传、使用 servlet listeners 初始化。IoC 容器以及一个面向 Web 的应用上下文。 它还包含 Spring 远程支持中 Web 的相关部分。
6:Spring Aop
AOP是切面编程。Aop Aspects 模块提供了对 AspectJ 的集成支持 。Instrumentation 模块提供了 class instrumentation 支持和 classloader 实现,使得可以在特定的应用服务器上使用。
7:Test
Test 模块支持使用 JUnit 和 TestNG 对 Spring 组件进行测试
四:Spring 容器继承图
一:什么是IOC?以及IOC的作用
上文提到IOC最最最核心的功能是通过多级缓存解决依赖注入问题。IOC被称为控制反转/依赖注入。什么是控制反转?我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversion Principle)
1,什么是依赖倒置原则?
假设我们是一名卖货的商家,比如我们进货,需要从进货市场进货,进货市场要从生产家下订单。这里就出现了一个依赖的关系,商家依赖进货市场,进货市场依赖生产厂家。依赖关系如下图所示
2,敲黑板,划重点.IOC容器的最最最最核心思想........................
ioc的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度.如果用生活中的例子演示,就好比:如果在没有IOC容器之前的概念是,比如你要找一个女朋友,那么可能你需要具备以下几个特征:
生活中的依赖关系:有钱、长得帅、活儿好、会做饭、会收拾家务、温柔。
通过IOC解决依赖关系
以上可知,如果我们要找个女朋友,可能需要依赖很多外在因素。相对困难,复杂,成功率不高。更影响心情。但是有了IOC以后这个问题就可以非常容易的解决。如以下关系图所示。
通过上图可知,资源的拥有者是洗浴中心,但是洗浴中心本身并不使用资源,资源的使用者,不需要依赖那么的外在关系,只要有钱,告诉洗浴中心,我想要找某一个小姐姐,那么洗浴中心,就会给你安排你挑选的那个小姐姐为你服务,比如做一些羞羞的事情。。。。
IOC容器解决了,耦合度的问题,把资源交给第三方来管理(IOC容器)但本身并不使用资源。避免了依赖关系。从而解决耦合度的问题。
IOC源于生活,高于生活。
二:Spring IOC 容器底层注解使用
1,依赖注入和分为XML和注解两种方式,这里主要重点介绍注解的方式,目前SpringBoot 和SpringCloud是趋势,所以以后开发过程中强烈推荐用注解,不仅简洁,方便,又可以提高开发效率。不容易出错,节省了开发时间和改错时间。
2,通过XML的方式配置IOC这里不做介绍,ClassPathXmlApplicationContext负责读取xml内容通过getBean(beanName)的方式获取 bean
3,@Configuration
用于类上面,相当于xml配置文件中的beans标签。负责读取配置类。@Configuration注解的配置类有如下要求:
@Configuration不可以是final类型、@Configuration不可以是匿名类、嵌套的@configuration必须是静态类
4,@Bean注解
@Bean相当于xml配置文件中的bean标签。用于方法上,注入bean实例。通过@Bean的形式是使用的话, bean的默认名称是方法名。若@Bean(value="bean的名称")。那么bean的名称是指定的。
读取容器中的bean:AnnotationConfigApplicationContext;
@ComponentScan
光生明注解是不可以使用的,必须让Spring扫描到才可以被使用.扫描com.jdyun.admin.annotation包下面的类
@ComponentScan(basePackages = {"com.jdyun.admin.annotation"})
排除用法:也可以去除某个注解不被扫描
excludeFilters属性去除某个注解不被扫描
@ComponentScan(basePackages = {"com.jdyun.admin.annotation"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {JdyunService.class})
})
type = FilterType.ANNOTATION,value = {Controller.class}表示Controller注解不被扫描
(type = FilterType.ASSIGNABLE_TYPE,value = {JdyunService.class}表示自定义的类不被扫描
包含用法:包含某些类或注解
包含用法 includeFilters ,注意,若使用包含的用法,需要把useDefaultFilters属性设置为false(true表示扫描全部的)
这里需要补充一个重点:如果includeFilters 使用的是自定义的过滤规则.并且useDefaultFilters=false那么就不会走ComponentScan默认的过滤规则.假设@Controller或者@Compontent等注解不符合自定义的过滤规则.则不会被扫描到.更不会被注入到Spring容器内.如果符合自定义规则的类.即使没有Compontent等注解也会被扫描到并且注入到Spring容器内.
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeWSFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class})
},useDefaultFilters = false)
以上包含Controller注解以及Service注解。
@ComponentScan.Filter type的类型
1注解形式,FilterType.ANNOTATION 例如自定义注解或者@Controller @Service 等等等
2指定类型,FilterType.ASSIGNABLE_TYPE
3aspectj类型的,FilterType.ASPECTJ(不常用)
4正则表达式的 FilterType.REGEX(不常用)
5自定义枚举类型
自定义类型的使用
自定义注解类需要实现TypeFilter并且实现一个match方法
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类的注解源信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前类的class的源信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的资源信息
Resource resource = metadataReader.getResource();
if(classMetadata.getClassName().contains("dao")) {
return true;
}
return false;
}
配置Bean的作用域对象@Scope(value = "prototype")
设置Bean的作用域使用@Scope,@Scpoe有四个值。
1,singleton 单实例的(默认),而且是饿汉加载。容器启动实例就创建好了。所有的bean都是单实例的bean
2,prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)。
3,request 同一次请求
4,session 同一个会话级别
@Lazy
Bean的懒加载@Lazy(主要针对单实例的bean 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象)
@Conditional进行条件判断等.
1,@Conditional注解是什么
@Conditional注解是条件判断注解,可根据一些自定的条件确定是否加载Bean到Spring 容器中,看过springBoot源码的同学会发现,springBoot中大量使用了该注解.
2,@Conditional注解如何使用
自定义的@Conditional注解需要实现Condition接口(自定义类CustomerCondition).并且实现一个boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法.比如可以在该方法内写一段逻辑返回true
if(context.getBeanFactory().containsBean("StudetnAspect ")) {
return true;
}
return false;
自定义注解定义完以后在某个方法上使用自定义的Condition
public class MainConfig {
@Bean
public StudetnAspect studentAspect() {
return new StudetnAspect ();
}
//当切 容器中有StudetnAspect 的组件,那么StudetnAspect 才会被实例化.
@Bean
@Conditional(value = CustomerCondition.class)
public School buildSchool() {
return new School ();
}
}
当加载buildSchool方法的时候,使用条件注解@Conditional(value = CustomerCondition.class),如果CustomerCondition中返回true.那么就创建School对象.总之使用@Conditional注解,需要实现Condition接口.可以在实现方法中写入自己的判断逻辑.这个判断逻辑是跟你使用该注解的方法息息相关.
@Conditional用在方法上只能是一个方法注入一个bean实例,所以@Conditional标注在方法上只能控制一个bean实例是否注入。
@Conditional用在类上会注入一批bean的实例,如下代码所示
@Conditional({CustomerCondition.class})
@Configuration
public class BeanConfig {
@Bean(name = "Student")
public Student student1(){
return new Student();
}
@Bean("Student")
public Student student2(){
return new Student();
}
}
如果CustomerCondition条件为true的话,那么会注入student1和student2两个bean实例
多个条件类判断如下:
@Conditional({CustomerCondition.class,ObstinateCondition.class})
@Configuration
......
判断规则是:
1,CustomerCondition返回结果为true ObstinateCondition返回结果为false 那么不注入.
2,CustomerCondition返回结果为true ObstinateCondition 返回结果为true 则注入.
往IOC 容器中添加组件的方式
1:通过@CompentScan +@Controller @Service @Respository @compent
2:通过@Bean的方式来导入组件(适用于导入第三方组件的类)
3:通过@Import来导入组件 (导入组件的id为全类名路径)
例如:
@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig {
}
4:通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)
public class DemoImportSelector implements ImportSelector {
/可以获取导入类的注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.demo.Car"};
}
5:通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)
public class DemoBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//创建一个bean定义对象 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
//把bean定义对象导入到容器中 registry.registerBeanDefinition("car",rootBeanDefinition); }
}
@Configuration //@Import(value = {Person.class, Car.class}) //
@Import(value = {Person.class, Car.class, DemoImportSelector.class})
@Import(value = {Person.class, Car.class, TulingImportSelector.class, DemoBeanDefinitionRegister.class})
public class MainConfig {
}
6:通过实现FacotryBean接口来实现注册 组件
Bean的初始化方法和销毁方法.
什么是bean的生命周期?
1,bean的创建----->初始化----->销毁方法:由容器管理Bean的生命周期,我们可以通过自己指定bean的初始化方法和bean的销毁方法
@Configuration
public class MainConfig {
//指定了bean的生命周期的初始化方法和销毁方法.
@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car() { return new Car();
}
}
需要注意的是:
1, 针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法
2, 针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受 IOC容器的管理..
2,通过 InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法
3,通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法
4,通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程
1, postProcessBeforeInitialization 在init方法之前调用
2, postProcessAfterInitialization 在init方法之后调用
5,通过@Value +@PropertySource来给组件赋值
自动装配
1,Autowired
1,Autowired 的使用以及介绍
Autowired 默认按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配.比如容器中有两个DemoDao,
一个叫DemoDao1另一个叫DemoDao2
@Autowired
private TulingDao DemoDao1; 装配第一个组件
@Autowired
private TulingDao DemoDao2; 装配第二个组件
2,假设我们需要指定特定的组件来进行装配,我们可以通过使用@Qualifier("demoDao")来指定装配的组件, 或者在配置类上的@Bean加上@Primary注解
@Autowired
@Qualifier(" demoDao ")
private DemoDao DemoDao2;
3,假设我们容器中即没有tulingDao 和tulingDao2,那么在装配的时候就会抛出异常
No qualifying bean of type 'com.jdyun.testautowired.DemoDao' available, 若我们想不抛异常 ,我们需要指定 required为false的时候可以了。
4,@Resource(JSR250规范)
功能和@AutoWired的功能差不多一样,但是不支持@Primary 和@Qualifier的支持
5,@InJect(JSR330规范)
需要导入jar包依赖 功能和支持@Primary功能 ,但是没有Require=false的功能
1,使用Autowired 可以标注在方法上(标注在构造函数上/标注在set方法上/标注在方法的入参)
1:通过@Profile注解 来根据环境来激活标识不同的Bean
1,@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效
2,@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活
3,没有标志为@Profile的bean 不管在什么环境都可以被激活
如果使用@PropertySource(value = {"classpath:ds.properties"})注解 可以实现EmbeddedValueResolverAware类来获取属性
激活切换环境的方法
方法一:通过运行时jvm参数来切换 -Dspring.profiles.active=test|dev|prod
方法二:通过代码的方式来激活
封面图源网络,侵权删除)
如有收获,请帮忙转发,您的鼓励是作者最大的动力,谢谢!
一大波微服务、分布式、高并发、高可用的原创系列文章正在路上,
欢迎关注头条号:java小马哥
周一至周日早九点半!下午三点半!精品技术文章准时送上!!!
十余年BAT架构经验倾囊相授
学习视频资料限时领取
死磕Spring源码-常见底层核心注解相关推荐
- Spring源码系列(十三)——Spring源码编译及详细注解
文章目录 1. 环境搭建 2. 代码编译 2.1 编译代码 2.1.1 build.gradle 2.1.1.1 第一处 2.1.1.2 第二处 2.1.2 gradle.properties 2.1 ...
- Spring源码解析之@Component注解的扫描
阅读须知 Spring源码版本:4.3.8 文章中使用/* */注释的方法会做深入分析 正文 承接Spring源码解析之context:component-scan标签解析,下面就是扫描的流程: Cl ...
- 死磕JDK源码之String
String本质是对char数组的封装 Serializable接口 实现Serializable接口的类可以被序列化 Comparable接口 实现Comparable接口的类可以支持排序,需要重写 ...
- spring源码分析之cache注解
Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如EHCache 或者 OSCache),而是一个对缓存使用的抽象 ...
- Spring源码解析之-- 事务TransactionInterceptor 分析(开启事务)
目录 一.介绍 二.TransactionInterceptor 分析 2. 流程 2.1 invoke 2.1.1 TransactionAspectSupport#invokeWithinTran ...
- Spring源码系列(十二)Spring创建Bean的过程(二)
1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...
- 【Spring源码】4. 自己搞个标签?~自定义标签保姆级全过程(图解向,堆图预警)
[Spring源码系列- IOC] 1 [Spring源码]0.安装Gradle环境 2 [Spring源码]1.下载与编译_pom relocation to an other version nu ...
- Spring源码学习(三)-- 底层架构核心概念解析
前面,我们大概了解了Spring中的一些概念和底层工作流程,这篇是后续看Spring源码所必备的,防止后续看源码的过程中,遇到不会的概念得单独跳出来学习. BeanDefinition BeanDe ...
- Spring源码分析(二):底层架构核心概念解析
本节主要介绍一下Spring底层中用到的"基础设施",是后续看Spring源码所必备的,防止后续看源码的过程中,遇到不会的概念得单独跳出来学习. BeanDefinition Be ...
最新文章
- 力扣(LeetCode)刷题,简单题(第9期)
- 科普丨深度学习引擎的终极形态是什么?
- c ef框架-mysql_.net EF框架 MySql實現實例
- javascript转换金额格式
- 深度学习-Tensorflow2.2-深度学习基础和tf.keras{1}-优化函数,学习速率,反向传播,网络优化与超参数选择,Dropout 抑制过拟合概述-07
- 计算机的好处英语,跪求一篇英语作文 题目:论计算机的优缺点
- Equalize the Remainders(set二分+思维)
- .NET Core很酷,你不得不知
- C# 中使用面向切面编程(AOP)中实践代码整洁
- enumset_枚举集合的EnumSet
- DCC-GARCH模型及动态CoVaR计算 案例与代码
- 在.net2.0下使用System.Web.Script.Serialization;
- jar转apk专辑 android,jar转apk格式转换器
- 机械电子工程专业和计算机科学,机械电子工程专业属于什么类别
- 收藏!从十篇顶会论文解读计算机视觉的未来之路!
- python中空字符串是什么_python为空怎么表示 python如何判断字符串为空
- 第五---七章 交换机和路由器的基本配置
- vue 节流throttling防抖debounce
- maven核心,pom.xml详解
- 网站响应速度慢,这些原因不可不知?