Spring核心概念

BeanDefinition

BeanDefinition用于存储bean信息,比如bean是单例还是原型、bean的类型以及是否懒加载等等,Spring判断bean是否被注册是根据判断判断容器中是否存在该BeanDefinition的,除了使用注解和xml的方式对bean进行注册,开发者还可以自己自定义创建beanDefinition并注册到容器中,如下代码。

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
        beanDefinition.setBeanClassName("userService");
        beanDefinition.setBeanClass(UserServiceImpl.class);
        applicationContext.registerBeanDefinition("userService", beanDefinition);

BeanDefinitionReader

BeanDefinitionReaderBeanDefinition的读取器,用于读取BeanDefinition并注册到Spring容器中,创建该对象是需要传入spring容器对象。这个类的底层是根据传入的class自动创建BeanDefinition并注册到spring容器中,如下以注解的方式进行扫描注册代码,除了使用注解的方式进行扫描,还可以使用xml的方式进行扫描。


        AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
        beanDefinitionReader.registerBean(UserServiceImpl.class);

ClassPathBeanDefinitionScanner

该类用于根据包名扫描并创建BeanDefinition,可以通过使用ClassPathBeanDefinitionScanner扫描包下的所有类,判断类中是否用于Spring容器在注解,如果有则进行扫描注册到容器中,扫描完毕后必须对Spring容器进行刷新,如下代码所示。spring容器注解有service、Component注解等。

        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(applicationContext);
        classPathBeanDefinitionScanner.scan("com.lyra.user.service.impl");
        applicationContext.refresh();

各种BeanDefinition

  1. GenericBeanDefinition是BeanDifinition的基本实现
  2. ScannedGenericBeanDefinition 由AnnotatedBeanDefinitionReader扫描器生成的BeanDefinition
  3. AnnotatedGenericBeanDefinition由AnnotatedBeanDefinitionReader读取器生成的BeanDefinition

BeanFactory和ApplicationContext相关

Spring是以面向接口编程的方式进行编程,通过查看类中继承了扫描接口由此了解到了该类有哪些功能,如Application接口继承了EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory接口标识Application拥有获取环境变量、beanFactory相关功能和拥有父子bean容器的功能,通过实现不同的接口方法来拓展不同的功能。
BeanFactory和ApplicationContext都是接口
BeanFactory提供了最基础的获取bean的操作,由DefaultListableBeanFactory是Beanfactory的实现。
AnnotationConfigApplicationContext底层是由DefaultListableBeanFactory获取bean的。

类型转换

在spring中会需要将String类型转换成其他的类型,这就需要类型转换了。在spring底层获取bean是如果有传入bean类型则会使用instanceof判断类型是否为传入的类型,如果类型一致则强转后返回,如果不一致则调用自定义的类型转换器进行转换,如果转换失败则抛出异常,如下代码所示。
image

PropertyEditor

JDK自带的类型转换器,只能将string类型转换成其他类型,通过继承PropertyEditorSupport以及PropertyEditor接口,在setAsText方法中编写具体转换逻辑,将传入的String类型的字符串转换为User并调用setValue方法进行设置

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
    @Override
    public void (String text) throws IllegalArgumentException {
            User user = new User();
            user.setName(text);
            this.setValue(user);
    }
}

然后将该类注册到CustomEditorConfigurer中即可。

    @Bean
    public CustomEditorConfigurer customEditorConfigurer() {
        CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
        Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();

        // 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
        propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
        customEditorConfigurer.setCustomEditors(propertyEditorMap);
        return customEditorConfigurer;
    }

类型转换之后使用value注解测试如下所示
image
image

ConversionService

比JDK自带的类型转换强大些,支持任意类型转换,不像JDK只支持string类型。通过实现ConditionalGenericConverter接口来完成类型转换,matches用于判断什么时候继续类型转换,getConvertibleTypes方法定义了将什么类型转换为什么类型,convert具体业务转换逻辑,source为被转换的对象,在下方代码例子中为String类型的shabi。

public class StringToUserConverter implements ConditionalGenericConverter {
    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, User.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        User user = new User();
        user.setName((String) source) ;
        return user;
    }
}

之后注册到Spring容器中即可

    @Bean
    public ConversionServiceFactoryBean conversionService() {
        ConversionServiceFactoryBean conversionServiceFactoryBean =
                new ConversionServiceFactoryBean();
        conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

        return conversionServiceFactoryBean;
    }

TypeConverter

将PropertyEditor和ConversionService进行整合,执行时可以将PropertyEditor和ConversionService设置到TypeConverter中,最终由TypeConverter选择使用哪个进行类型转换,ConversionService要比PropertyEditor优先级高一些,这种方式类型转换在Spring源码中用的比较多些。setConversionService传入ConversionService,registerCustomEditor传入PropertyEditor,最后执行convertIfNecessary进行转换即可。

        ConversionServiceFactoryBean bean = applicationContext.getBean(ConversionServiceFactoryBean.class);
        SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        typeConverter.setConversionService(bean.getObject());

        typeConverter.registerCustomEditor(User.class, new JDKStringToUserConverter());

        User value = typeConverter.convertIfNecessary("test", User.class);

比较器

Spring实现了通过实现Ordered接口或使用Order注解来完成对象的比较,从而实现排序。

实现接口

public class OrderB implements Ordered {
    @Override
    public int getOrder() {
        return 10;
    }
}

public class OrderA implements Ordered {
    @Override
    public int getOrder() {
        return 20;
    }
}

新建OrderComparator对象并调用compare方法进行比较,如果参数1 < 参数2则返回-1,如果参数1 > 参数2则返回1,如果相等则返回0,使用list.sort可以对list中的元素进行排序。

        OrderA orderA = new OrderA();
        OrderB orderB = new OrderB();
        OrderComparator orderComparator = new OrderComparator();
        int compare = orderComparator.compare(orderB, orderA);
        System.out.println(compare);
        List<Object> list = new ArrayList<>();
        list.add(orderA);

        list.add(orderB);
        list.sort(orderComparator);

注解

使用注解也一样将注解写在类中,注解的参数就是order的值。

@Order(20)
public class OrderA  {
}
@Order(10)
public class OrderB {
}

Spring提供了AnnotationAwareOrderComparator获取注解中的值并进行比较,其余代码就和实现接口的方法一致了。

        OrderA orderA = new OrderA();
        OrderB orderB = new OrderB();
        OrderComparator orderComparator = new AnnotationAwareOrderComparator();
        int compare = orderComparator.compare(orderB, orderA);
        System.out.println(compare);
        List<Object> list = new ArrayList<>();
        list.add(orderA);

        list.add(orderB);
        list.sort(orderComparator);

元数据读取器

BeanDefinitionClassMetadata不同之处在于BeanDefinition中保存的数据只是bean信息数据,如是不是单例、类型是什么、是不是懒加载之类的,而ClassMetadata中存储的数据就要比BeanDefinition中存储的数据要多一些了,它主要封装的是类信息,比如类中的注解是什么,是否有子类、父类接口什么、是否final属性、是否有指定注解之类的。
SimpleMetadataReader解析类底层使用的是ASM技术,使用ASM的好处是无需将类加载到JVM主便可以分析出类信息,而使用反射技术则需要将类加载到JVM中才可以进行获取类信息,本身仅仅只在使用的时候才进行获取类信息,在一开始将所有类都加载到JVM中有些不好。
ASM的底层原理是根据编译后的class字节码进行分析,根据字节码规则获取类信息。

使用元数据读取器可以获取类的元数据信息传入类的全限定包名,如下代码所示。

        AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory().getMetadataReader("com.lyra.user.service.impl.User").getAnnotationMetadata();
        System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName()));
        System.out.println(annotationMetadata.hasAnnotation(Component.class.getName()));

获取类元数据如下代码所示。

        ClassMetadata classMetadata = new SimpleMetadataReaderFactory().getMetadataReader("com.lyra.user.service.impl.User").getClassMetadata();
        System.out.println(classMetadata.getClassName());

FactoryBean

FactoryBean首先是一个Bean,和Bean注解功能相同,可以通过一系列操作生成一个bean,不同之处在于创建bean的生命周期不同,使用BeanFactory创建的bean不会进行初始化前和依赖注入的操作,而使用Bean注解创建的bean拥有完整的生命周期。
Spring底层在扫描bean时会将实现BeanFctory接口的bean一并扫描并创建BeanDefinitation中去,之后会判断该类是否实现FctoryBean,如果实现Beanctory的话直接强转,然后调用getObject方法创建并存储到map中,使用FactoryBean创建的bean和普通创建的bean使用的单例池map不是同一个map。
FactoryBean创建了两个bean,一个是BeanFactory类型的bean,存储在普通创建的单例池map中,获取该bean需要添加&前缀。另一个bean是getObject获取的bean。
使用时直接实现factoryBean接口,然后将该实现类扫描进Spring容器即可。
由于经历了初始化后的方法,所以AOP也会对FactoryBean创建的bean生效。

@Component
public class LyraFactoryBean implements FactoryBean<UserServiceImpl> {
    @Override
    public UserServiceImpl getObject() throws Exception {
        return new UserServiceImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserServiceImpl.class;
    }
}

ExcludeFilter和IncludeFilter

ExcludeFilter表示排除过滤器,只要被ExcludeFilter标识的,即便添加了bean扫描注解也不会被扫描到Spring容器中,如下所示,即便OrderServiceImpl添加Component注解也不会扫描到Spring容器中表示扫描类型,比如类,注解,切面等等,classes表示排除的类。

@Component("orderService")
public class OrderServiceImpl  {
    public void test() {
        System.out.println("test");
    }
}
@ComponentScan(value = "com.lyra.user.service.impl", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderServiceImpl.class)
})
public class ApplicationConfig {


}

IncludeFilter与之刚好相反,只要被IncludeFilter标识了,即便没用添加bean注解也会扫描到Spring容器中。

public class OrderServiceImpl  {
    public void test() {
        System.out.println("test");
    }
}
@ComponentScan(value = "com.lyra.user.service.impl", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderServiceImpl.class)
})

在Spring底层执行扫描时,会默认使用IncludeFilter添加Component注解,表示在类中只要标识Component就将该类扫描进Spring容器中。

posted @   RainbowMagic  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-05-29 标题
点击右上角即可分享
微信分享提示