Spring原理篇(3)--一定要知道的接口以及其应用;

@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的类继承实现结构来看
在这里插入图片描述

  1. AliasRegistry:支持别名功能,一个名字可以对应多个别名
  2. BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
  3. BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
  4. SingletonBeanRegistry:可以直接注册、获取某个单例Bean
  5. SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
  6. ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有 BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类 型获取{类型:对应的Bean}的映射关系
  7. HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
  8. DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直 接注册、获取某个单例Bean的功能
  9. ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  10. FactoryBeanRegistrySupport:支持了FactoryBean的功能
  11. AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配
  12. AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了 FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和 获取beanNames
  13. ConfigurableListableBeanFactory:继承了ListableBeanFactory、 AutowireCapableBeanFactory、ConfigurableBeanFactory
  14. AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能
  15. DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了 ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以 DefaultListableBeanFactory的功能很强大

接下来就是两个比较重要的实现类 有关于实现ApplicationContext 的实现类:

1 AnnotationConfigApplicationContext
2 ClassPathXmlApplicationContext

AnnotationConfigApplicationContext

在这里插入图片描述

  1. ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听 器、添加BeanFactoryPostProcessor、设置Environment,获取 ConfigurableListableBeanFactory等功能
  2. AbstractApplicationContext:实现了ConfigurableApplicationContext接口
  3. GenericApplicationContext:继承了AbstractApplicationContext,实现了 BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册 BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  4. AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的 @Configuration注解,已经可以处理**@Bean注解**),同时可以扫描
  5. 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分为:

  1. ANNOTATION:表示是否包含某个注解
  2. ASSIGNABLE_TYPE:表示是否是某个类
  3. ASPECTJ:表示否是符合某个Aspectj表达式
  4. REGEX:表示是否符合某个正则表达式
  5. 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

猜你喜欢

转载自blog.csdn.net/wenaicoo/article/details/120123270