springBoot当前的版本是 1.5.9.RELEASE
1.springBoot URL图
springBoot源码分析,我们就根据这个URL图来分析springBoot的源码,从顶级接口出发,一个一个往源码探究说明!
一、BeanFactory使用与介绍
1.BeanFactory说明
Spring中所有的IoC容器都要实现接口BeanFactory,它是一个顶级容器接口;
IOC容器有BeanFactory 和ApplicationContext.通常建议使用后者,因为它包含了前者的功能。Spring的核心是ApplicationContext.它负责管理 beans 的完整生命周期,
为了看清源码,顺便来看看这个BeanFactory接口源码是怎样的,都有哪些方法作用,具体请看源码注释。
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
//它意义是从IOC容器中获取Bean,可以按Bean类型,名称来获取
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
//判断是否包含某个Bean
boolean containsBean(String var1);
//判断是否在spring Ioc中是否为单例,默认情况下,Bean都是以单例的形式存在的
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//判断Bean是否在spring IOC中是否是原型,即不是单例。如果为true,则spring IOC容器会创建一
//个新的Bean返回给调用者
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
//判断JavaBean是否匹配指定的类型
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//获取别名
String[] getAliases(String var1);
}
2.验证方法
如何获取这个BeanFactory对象来验证上面的方法,这里不建议获取BeanFactory对象,从上面的URL图可以看到,ApplicationContext继承了BeanFactory接口,包含了所有BeanFactory接口的方法
故获取ApplicationContext即可验证BeanFactory接口的所有方法
3.方法验证
3.1获取ApplicationContext
3.2定义一个spring IOC容器的对象
3.3测试
二、ListableBeanFactory使用与介绍
正如这个工厂接口的名字所示,这个工厂接口最大的特点就是可以列出工厂可以生产的所有实例.
这个接口是个暴利接口,不再像BeanFactory接口一个一个bean获取,该接口可以一次性获取所有的bean,
当然,拓展接口肯定是后面发现BeanFactory这个接口一个一个获取bean太费劲了所以进行了拓展。
源码如下:
public interface ListableBeanFactory extends BeanFactory {
//暴力获取全部bean的属性
//对于给定的名字是否含有BeanDefinition
boolean containsBeanDefinition(String var1);
//返回工厂的BeanDefinition总数
int getBeanDefinitionCount();
//返回工厂中所有Bean的名字
String[] getBeanDefinitionNames();
//根据bean 的类型获取bean
String[] getBeanNamesForType(ResolvableType var1);
//获取给定类型的bean names(包括子类),通过bean 定义或者FactoryBean的getObjectType判断.
//返回对于指定类型Bean(包括子类)的所有名字
String[] getBeanNamesForType(Class<?> var1);
//返回指定类型的名字 includeNonSingletons为false表示只取单例Bean,true则不是
//allowEagerInit为true表示立刻加载,false表示延迟加载。 注意:FactoryBeans都是立刻加载的
String[] getBeanNamesForType(Class<?> var1, boolean var2, boolean var3);
//如果保护懒加载的类,FactoryBean初始化的类和工厂方法初始化的类会被初始化.
//就是说执行这个方法会执行对应的初始化.
// 根据类型(包括子类)返回指定Bean名和Bean的Map
<T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException;
<T> Map<String, T> getBeansOfType(Class<T> var1, boolean var2, boolean var3) throws BeansException;
//查找使用注解的类
String[] getBeanNamesForAnnotation(Class<? extends Annotation> var1);
//根据注解类型,查找所有有这个注解的Bean名和Bean的Map
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> var1) throws BeansException;
//查找一个类上的注解,如果找不到,父类,接口使用注解也算.
//根据指定Bean名和注解类型查找指定的Bean
<A extends Annotation> A findAnnotationOnBean(String var1, Class<A> var2) throws NoSuchBeanDefinitionException;
}
测试验证通上面验证BeanFactory一样。
三、HierarchicalBeanFactory分析
Hierarchical--层次结构
二级接口,相对于父接口BeanFactory,这个接口只拓展了一个重要的功能---工厂分层
源码如下:
public interface HierarchicalBeanFactory extends BeanFactory {
//返回Bean工厂的父工厂,这个方法实现了工厂分层
BeanFactory getParentBeanFactory();
//判断本地工厂是否包含该Bean(忽略其他所有父工厂),这也是分层思想的体现
boolean containsLocalBean(String var1);
}
四、MessageSource 接口分析
public interface MessageSource {
String getMessage(String var1, Object[] var2, String var3, Locale var4);
//获取信息方法,参数一:参数的键,参数二:动态获取值的键,参数三:本地接口,一些字符集集合
String getMessage(String var1, Object[] var2, Locale var3) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;
}
验证方法,因为ApplicationContext也继承了MessageSource接口,所以也可以直接使用上面验证BeanFactory接口一样.
验证时可以在resources中建一个messages.prperties属性文件,然后在配置文件中设置该路径即可测试
注:这里中文会有乱码,因为这不是我们要测试目的,这里自己去百度如果解决中文乱码问题。
原因:java 内部是用unicode来表示字符的,而message.properties使用的是utf-8字符集
========================================================= 资源加载接口分析 =================================================================================
五、ResourceLoader资源加载接口分析
springboot中资源的加载顶级接口就是这个ResourceLoader接口,该接口有两个接口,一个是获取资源方法,一个是获取类加载方法
public interface ResourceLoader {
String CLASSPATH_URL_PREFIX = "classpath:";
//获取资源加载接口
Resource getResource(String var1);
//获取类加载器
ClassLoader getClassLoader();
}
1.getResource
先看第一个方法 getResource,该方法获取到一个资源加载器对象,我们进去看看这个Resource是个什么东西,Resource源码如下:
public interface Resource extends InputStreamSource {
//判断资源是否存在
boolean exists();
//判断是否可读
boolean isReadable();
//判断资源是否打开
boolean isOpen();
//获取资源的url
URL getURL() throws IOException;
//获取资源的uri
URI getURI() throws IOException;
//获取资源的文件,就是将该资源当成一个文件使用
File getFile() throws IOException;
//获取资源内容长度
long contentLength() throws IOException;
//获取资源最后修改时间戳
long lastModified() throws IOException;
//创建新的Resource
Resource createRelative(String var1) throws IOException;
//获取资源文件名
String getFilename();
//获取资源描述
String getDescription();
}
通过这个Resource接口的源码可以知道,这个方法也不是那么强,故用得也是比较少的。
在spring中资源加载是有三种方式的:
1)ClassPathXmlApplicationContext
通过URL图可以知道ApplicationContext这个接口其实是有被ClassPathXmlApplicationContext实现的,所以可以通过创建ClassPathXmlApplicationContext对象获取ApplicationContext
如:
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-queue.xml");
2)FileSystemXmlApplicationContext
同样通过URL可以知道FileSystemXmlApplicationContext是实现了ApplicationContext这个接口,FileSystemXmlApplicationContext和上面ClassPathXmlApplicationContext
最大的区别在于这个路径的不同,FileSystemXmlApplicationContext是再系统的绝对路径,ClassPathXmlApplicationContext是在项目中的相对路径,所以在项目中经常使用的
是ClassPathXmlApplicationContext,因为你在项目中肯定是相对路径方便的!
如:
ApplicationContext ac1 = new ClassPathXmlApplicationContext("applicationContext-queue.xml");
ApplicationContext ac2 = new FileSystemXmlApplicationContext("C:\\token\\code\\token_code\\xgm\\springBoot-oracle\\springBoot-hibernate\\src\\main\\resources\\applicationContext-queue.xml");
3)WebApplicationContextUtils.getWebApplicationContext(ServletContext)
这个是直接通过 WebApplicationContextUtils 获取ApplicationContext,参数是ServletContext
注:也可以通过一下方法获取ApplicationContext,不过需要是web应用才可以获取到,不是web以后方法获取到的ApplicationContext为空
ApplicationContext currentWebApplicationContext = ContextLoader.getCurrentWebApplicationContext();
如果是想自己创建资源拓展接口,spring提供了ResourceLoaderAware接口,只要实现该接口,spring便会将你的设置的资源注入到spring IOC容器中,
偷偷说明下,ResourceLoaderAware和ApplicationContextAware、BeanNameAware这个接口后面都有后缀名Aware,说明这些接口都是可以拓展的,只要实现这些接口,
剩下的事就交给spring即可!
2.getClassLoader
接着看 ResourceLoader接口的第二个方法 getClassLoader,获取类加载器,一看就不就是java反射那一套东西,具体我们就不看如何去实现了,我们看看这个方法获取到的ClassLoader类加载器
有哪些可以执行的方法,因为ClassLoader是抽象类,所以我们就只看能执行的方法,能执行的方法见下图:
说明如下:
ApplicationContext applicationContext = SpringBootContextUtil.getApplicationContext();
ClassLoader classLoader = applicationContext.getClassLoader();
classLoader.clearAssertionStatus();//清楚断言状态,执行该方法,不管项目中设置了什么断言都不会执行
ClassLoader parent = classLoader.getParent();//返回委托的父类加载器
classLoader.setDefaultAssertionStatus(false);//设置此类加载器的默认断言状态
//设置此中命名的顶级类所需的断言状态类加载器和其中包含的任何嵌套类。
// 此设置优先于类加载器的默认断言状态,并且超过任何适用的每包默认值。
// 如果已初始化命名类,其断言状态无法更改
classLoader.setClassAssertionStatus("ContextTestController",false);//
//classLoader.setPackageAssertionStatus();//设置命名包的包默认断言状态
六、ResourcePatternResolver
Pattern--模式 Resolver--分解器,ResourcePatternResolver字面意思这个接口就是资源模式分解器,源码如下:
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
//根据所给的路径获取多个资源文件,也就是该路径下所有的资源文件
Resource[] getResources(String var1) throws IOException;
}
从源码中可以知道,这个接口就一个方法,获取多个资源。
下个分析是springBoot环境、事件分析
========================================================= 资源加载接口分析 =================================================================================
七、EnvironmentCapable
1.说明分析
Capable--有能力
EnvironmentCapable是springboot的环境接口,该接口主要作用是用于类型检查,源码如下:
public interface EnvironmentCapable {
//返回此类的Environment
Environment getEnvironment();
}
2.验证:
在配置文件中定义一个键值对,获取这个值
当然这个值也可以用@Value来获取
@Value("${common.keli.agreement.webservice}")
private String url;
八、ApplicationEventPublisher
1.分析
spring中的事件发布接口,源码如下:
public interface ApplicationEventPublisher {
//发布事件,参数是上下文事件
void publishEvent(ApplicationEvent var1);
void publishEvent(Object var1);
}
2.验证
2.1定义一个关闭事件,这个事件需要继承ApplicationEvent
2.2 定义一个关闭监听器,这个监听器需要实现ApplicationListener接口,泛型是上面定义的关闭事件
2.3
这个可以像上面获取ApplicationContext对象一样的方法获取,以为ApplicationContext继承了ApplicationEventPublisher,自然也是有发布事件的方法,具体如下:
以上就是springBoot返回ApplicationContext时的八大接口,了解了这八大接口,然后再去研究springboot的启动过程就很容易了,所以在spring中,ApplicationContext是非常非常重要的,
从上面的八大接口中的方法,嘿嘿,我都有,我只要获取到ApplicationContext,spring的世界就可以在里面随便遨游了!
这篇博文是我第一次写,写得不好的地方敬请指正,与大家一起学习进步!