@TOC# Spring系列
记录在程序走的每一步___auth:huf
拨开云雾见天日 守得云开见月明
Spring一定要知道的接口;
该篇章 来由 是因为 Spring底层大量用了 其中的接口实现. 上一篇文章 模拟了Spring 主类的启动. 利用了反射 将目录扫描进来; 并且得到其注解; 然后实现 各种功能; 后面我们一起来阅读Spring源码的时候; 就不再做Spring 接口的说明; 实际上 我们在反射的过程中;我们会去读取项目里的target 文件 实际上取回来的就是Class的目录 而不是.java文件的目录; 在Spring中 有自己的实现方式 在Spring源码中; 使用了ASM技术; 以下 就是ASM的介绍. 本篇文章中不再做任何关于ASM陈述. 后面如果有时间会把ASM列为一个文章去讲解;
什么是ASM
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
与 BCEL 和 SERL 不同,ASM 提供了更为现代的编程模型。对于 ASM 来说,Java class 被描述为一棵树;使用 “Visitor” 模式遍历整个二进制结构;事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解 Java 类文件格式的所有细节:ASM 框架提供了默认的 “response taker”处理这一切。
我们来看关健的第一个接口 :
BeanDefinition
public interface BeanDefinition extends org.springframework.core.AttributeAccessor, org.springframework.beans.BeanMetadataElement {
java.lang.String SCOPE_SINGLETON = "singleton";
java.lang.String SCOPE_PROTOTYPE = "prototype";
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@org.springframework.lang.Nullable java.lang.String s);
@org.springframework.lang.Nullable
java.lang.String getParentName();
void setBeanClassName(@org.springframework.lang.Nullable java.lang.String s);
@org.springframework.lang.Nullable
java.lang.String getBeanClassName();
void setScope(@org.springframework.lang.Nullable java.lang.String s);
@org.springframework.lang.Nullable
java.lang.String getScope();
void setLazyInit(boolean b);
boolean isLazyInit();
}
BeanDefinition 是用来描述一个类的信息; 例如 注解; 里面源码是这样的;
里面有关健的几个方法 一个是setBeanClassName 一个是 setScope 一个是setLazyInit 这里就能知道BeanDefination 的作用了; 它后面继承了一个 BeanMetadataElement接口 是元数据的接口; 该接口之后描述,以下 就是Spring的源码; 从而引出一个功能
我们除了用几种方式来定义Bean:
1.xml–>bean/ 方式
2. @Bean
3. @Component(@Service,@Controller) 这些,我们可以称之申明式定义Bean。
我们还可以编程式定义Bean
//获取到当前容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(testMain.class);
//获取到BeanDefinitgion实现类;
AbstractBeanDefinition beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//穿件BeanDefinition
beanDefinitionBuilder.setBeanClass(StudentServiceImpl.class);
beanDefinitionBuilder.setLazyInit(false);
context.registerBeanDefinition("studentService",beanDefinitionBuilder);
System.out.println(context.getBean("studentService"));//com.huf.service.impl.StudentServiceImpl@60015ef5
//此时打印出来的Bean 就是通过BeanDefinition创建出来的;
Spring为了方便 提供了这么几种Reader (不包括全部) 用法跟以上代码类似;
AnnotatedBeanDefinitionReader :读取类
XmlBeanDefinitionReader : 读取XML
ClassPathBeanDefinitionScanner : 自动扫描
以下是某一种的实现 :其他三个都一样这样实现即可; 代码逻辑瞬间就感觉简洁许多
package com.huf;
import com.huf.service.impl.StudentServiceImpl;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* auth:huf
*/
public class testMain {
public static void main(String[] args) {
//获取到当前容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(testMain.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
annotatedBeanDefinitionReader.registerBean(StudentServiceImpl.class);
System.out.println(context.getBean("studentServiceImpl"));
}
}
我们来看关健的第二个接口 :
BeanFactory
BeanFactory表示Bean工厂,所以很明显,BeanFactory会负责创建Bean,并且提供获取Bean的 API。 而ApplicationContext是BeanFactory的一种,在Spring源码中,是这么定义的:
public interface ApplicationContext extends EnvironmentCapable,
ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
ApplicationContext 也是一个接口 并且实现了BeanFactory ApplicationContext具有更强力的功能 以下是它继承的接口介绍:
EnvironmentCapable: 环境变量(系统变量 还有一个是环境变量)
ListableBeanFactory: ---->BeanFactory
HierarchicalBeanFactory: ---->BeanFactory
MessageSource: 国际化 (不解释)
ApplicationEventPublisher: 事件发布 (监听机制)
ResourcePatternResolver: 资源; 里面是继承了ResourceLoader (Resource资源)
在Spring的源码实现中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory出 来,当使用ApplicationContext的某些方法时,比如getBean(),底层调用的是BeanFactory的 getBean()方法。 在Spring源码中,BeanFactory接口存在一个非常重要的实现类是: **DefaultListableBeanFactory,也是非常核心的。
我们可以直接来使用DefaultListableBeanFactory,而不用使用ApplicationContext的某个 实现类以下是自行写的代码:
/**
* auth:huf
*/
public class testMain {
public static void main(String[] args) {
//AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(testMain.class);
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(StudentServiceImpl.class);
defaultListableBeanFactory.registerBeanDefinition("studentService",beanDefinition);
System.out.printf(defaultListableBeanFactory.getBean("studentService").toString());
}
}
DefaultListableBeanFactory是非常强大的,支持很多功能,可以通过查看 DefaultListableBeanFactory的类继承实现结构来看
- AliasRegistry:支持别名功能,一个名字可以对应多个别名
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
- BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
- SingletonBeanRegistry:可以直接注册、获取某个单例Bean
- SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
- ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有 BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类 型获取{类型:对应的Bean}的映射关系
- HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
- DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直 接注册、获取某个单例Bean的功能
- ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
- FactoryBeanRegistrySupport:支持了FactoryBean的功能
- AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配
- AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了 FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和 获取beanNames
- ConfigurableListableBeanFactory:继承了ListableBeanFactory、 AutowireCapableBeanFactory、ConfigurableBeanFactory
- AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能
- DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了 ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以 DefaultListableBeanFactory的功能很强大
接下来就是两个比较重要的实现类 有关于实现ApplicationContext 的实现类:
1 AnnotationConfigApplicationContext
2 ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
- ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听 器、添加BeanFactoryPostProcessor、设置Environment,获取 ConfigurableListableBeanFactory等功能
- AbstractApplicationContext:实现了ConfigurableApplicationContext接口
- GenericApplicationContext:继承了AbstractApplicationContext,实现了 BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册 BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
- AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的 @Configuration注解,已经可以处理**@Bean注解**),同时可以扫描
- AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了 AnnotationConfigRegistry接口,拥有了以上所有的功能
ClassPathXmlApplicationContext
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而 言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition
上面的图 可以不用完全理解; 再后面源码 陈述完之后 再回头看. 就会清晰很多;
以下对ApplicationContext 接口实现 进行一个功能实现;
MessageSource 国际化;
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
//使用的时候 直接拿到 Context context.getMessage("test", null, new Locale("en_CN"));
Resource 资源;
//这地方与File 类似; 是直接使用容器Context 进行读取资源; 源码中有很多 这样读取资源的方式;
Resource resource = context.getResource("资源路径 可以为网络资源;");
try {
System.out.println(resource.contentLength());
} catch (IOException e) {
e.printStackTrace();
}
------------------------------------------
Resource[] resources = new Resource[0];
try {
resources = context.getResources("classpath:com/huf/*.class");
} catch (IOException e) {
e.printStackTrace();
}
for (Resource resource2 : resources) {
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());
}
Environment: 获取运行时环境
Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);
System.out.println("=======");
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);
System.out.println("=======");
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);
System.out.println("=======");
结果为:
ApplicationListener: 监听机制
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}
//再Context调用 context.publishEvent("kkk"); 即可;
类型转化Editor
在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便 的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。
PropertyEditor 实际上是JDK提供的类型转换;
package com.huf.editor;
import com.huf.entity.Student;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
/**
* 实际上是JDK自带的转换器;
* auth:huf
*/
public class StringToStudentPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
Student student = new Student();
student.setStudentName(text);
this.setValue(student);
}
}
//使用方式:
StringToStudentPropertyEditor propertyEditor = new StringToStudentPropertyEditor();
propertyEditor.setAsText("1");
Student student = (Student) propertyEditor.getValue();
System.out.println(value);
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
propertyEditorMap.put(Student.class, StringToStudentPropertyEditor.class);
customEditorConfigurer.setCustomEditors(propertyEditorMap);
return customEditorConfigurer;
}
ConversionService
Spring提供的 强大类型转换
package com.huf.conversion;
import com.huf.entity.Student;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import java.util.Collections;
import java.util.Set;
/**
* auth:huf
*/
public class StudentConversion implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return sourceType.getType().equals(String.class) && targetType.getType().equals(Student.class)
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Student.class));
}
@Override
public Object convert(Object source, TypeDescriptor typeDescriptor, TypeDescriptor typeDescriptor1) {
Student student = new Student();
student.setStudentName((String)source);
return student;
}
}
//转换方式为:
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StudentConversion());
Student value = conversionService.convert("1", Student.class);
System.out.println(value);
//再ConFig 注册方式为:
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new StudentConversion()));
return conversionServiceFactoryBean;
}
//以下是Spring的方式:
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Student.class, new StringToStudentPropertyEditor());
typeConverter.setConversionService(conversionService);
Student value = typeConverter.convertIfNecessary("1", Student.class);
System.out.println(value);
FactoryBean
factoryBean 是创建Bean的一种方式 与 @Bean是有区别的; 他们之间的生命周期 是不同的;
这里注意了
package com.huf.factorybean;
import com.huf.service.impl.StudentServiceImpl;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
* auth: huf
*/
@Component
public class HufFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new StudentServiceImpl();
}
@Override
public Class<?> getObjectType() {
return StudentServiceImpl.class;
}
}
当我们用context.getBean() 来获取对象的时候; 该对象是StudentServiceImpl对象 以下是截图:
他们两个方式注册成为Bean 但是它们两个的生命周期有什么不一样 以下我来证明:
用@Bean的生命周期是完整的; 也就是走初始化前 初始化后;
在使用FactoryBean的时候 生命周期是不完整的 只执行初始化后:
ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包 含过滤器。 比如以下配置,表示扫描com.huf这个包下面的所有类,但是排除Student类,也就是就算 它上面有@Component注解也不会成为Bean。
@ComponentScan(value = "com.huf",
excludeFilters =
{
@ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE,
classes = Student.class)}.)
@ComponentScan(value = "com.huf",
includeFilters = {
@ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE,
classes = Student.class)})
FilterType分为:
- ANNOTATION:表示是否包含某个注解
- ASSIGNABLE_TYPE:表示是否是某个类
- ASPECTJ:表示否是符合某个Aspectj表达式
- REGEX:表示是否符合某个正则表达式
- CUSTOM:自定义 在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下 Spring扫描过程中会认为类上有@Component注解的就是Bean。
MetadataReader、ClassMetadata、 AnnotationMetadata
在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数 据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。 MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:
class test {
public static void main(String[] args) throws IOException {
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); // 构造一个
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.huf.service.StudentService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName()); // 获取一个AnnotationMetadata,并获取类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
System.out.println(annotationType);
}
}
}
需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。 为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的 类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了 ASM技术。
总结
本文章内容 主要讲述了:
BeanDefinition :
BeanDefinitionReader
AnnotatedBeanDefinitionReader
XmlBeanDefinitionReader
ClassPathBeanDefinitionScanner
BeanFactory
DefaultListableBeanFactory
ApplicationContext
AnnotationConfigApplicationContext
ClassPathXmlApplicationContext
ConversionService
FactoryBean
ExcludeFilter 和 IncludeFilter
MetadataReader、ClassMetadata、 AnnotationMetadata
之后会单独写一篇文章 专门讲解PostProcessor
see you