14. 通过注解注入属性信息

工程结构

lqf-spring-step-14
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── annotation
│   │           │       │   ├── Autowired.java
│   │           │       │   ├── AutowiredAnnotationBeanPostProcessor.java
│   │           │       │   ├── Qualifier.java
│   │           │       │   └── Value.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       ├── ApplicationContextAwareProcessor.java
│   │           │       └── ClassPathXmlApplicationContext.java
│   │           ├── core
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               ├── ClassUtils.java
│   │               └── StringValueResolver.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── service
    │               ├── IUserService.java
    │               ├── UserDao.java
    │               └── UserService.java
    └── resources
        ├── spring.xml
        └── token.properties

自动扫描注入占位符配置和对象的类关系,如图:

  • 在整个类图中以围绕实现接口 InstantiationAwareBeanPostProcessor 的类 AutowiredAnnotationBeanPostProcessor 作为入口点,被
    AbstractAutowireCapableBeanFactory创建 Bean 对象过程中调用扫描整个类的属性配置中含有自定义注解
    ValueAutowiredQualifier,的属性值。
  • 这里稍有变动的是关于属性值信息的获取,在注解配置的属性字段扫描到信息注入时,包括了占位符从配置文件获取信息也包括 Bean
    对象,Bean 对象可以直接获取,但配置信息需要在 AbstractBeanFactory 中添加新的属性集合 embeddedValueResolvers,由
    PropertyPlaceholderConfigurer#postProcessBeanFactory 进行操作填充到属性集合中。

设计

在完成 Bean 对象的基础功能后,后续陆续添加的功能都是围绕着 Bean 的生命周期进行的,比如修改 Bean 的定义
BeanFactoryPostProcessor,处理 Bean 的属性要用到 BeanPostProcessor,完成个性的属性操作则专门继承 BeanPostProcessor
提供新的接口,因为这样才能通过 instanceof 判断出具有标记性的接口。所以关于 Bean 等等的操作,以及监听 Aware、获取
BeanFactory,都需要在 Bean 的生命周期中完成。在设计属性和 Bean 对象的注入时候,也会用到 BeanPostProcessor 来完成在设置 Bean
属性之前,允许 BeanPostProcessor 修改属性值。整体设计结构如下图:

  • 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性 applyPropertyValues 填充之前 ,把属性信息写入到
    PropertyValues 的集合中去。这一步的操作相当于是解决了以前在 spring.xml 配置属性的过程。
  • 而在属性的读取中,需要依赖于对 Bean 对象的类中属性的配置了注解的扫描,field.getAnnotation(Value.class);
    依次拿出符合的属性并填充上相应的配置信息。
  • 关于 @Autowired 对于对象的注入,其实这一个和属性注入的唯一区别是对于对象的获取 beanFactory.getBean(fieldType)
    ,其他就没有什么差一点了。
  • 当所有的属性被设置到 PropertyValues 完成以后,接下来就到了创建对象的下一步,属性填充,而此时就会把我们一一获取到的配置和对象填充到属性上,也就实现了自动注入的功能。

实现

把读取到属性填充到容器

定义解析字符串接口

源码: lqf.springframework.util.StringValueResolver

  • 接口 StringValueResolver 是一个解析字符串操作的接口

填充字符串

源码: lqf.springframework.beans.factory.config.PropertyPlaceholderConfigurer

  • 在解析属性配置的类 PropertyPlaceholderConfigurer
    中,最主要的其实就是这行代码的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 这是把属性值写入到了
    AbstractBeanFactory 的 embeddedValueResolvers 中。
  • embeddedValueResolvers 是 AbstractBeanFactory 类新增加的集合 List<StringValueResolver> embeddedValueResolvers String
    resolvers to apply e.g. to annotation attribute values

自定义属性注入注解

自定义注解,Autowired、Qualifier、Value

注解1: lqf.springframework.beans.factory.annotation.Autowired
注解2: lqf.springframework.beans.factory.annotation.Qualifier
注解3: lqf.springframework.beans.factory.annotation.Value

  • 个注解在日常使用 Spring 也是非常常见的,注入对象、注入属性,而 Qualifier 一般与 Autowired 配合使用。

扫描自定义注解

源码: lqf.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

  • AutowiredAnnotationBeanPostProcessor 是实现接口 InstantiationAwareBeanPostProcessor 的一个用于在 Bean
    对象实例化完成后,设置属性操作前的处理属性信息的类和操作方法。
  • 核心方法 postProcessPropertyValues,主要用于处理类含有 @Value、@Autowired 注解的属性,进行属性信息的提取和设置。
  • 这里需要注意一点因为我们在 AbstractAutowireCapableBeanFactory 类中使用的是 CglibSubclassingInstantiationStrategy
    进行类的创建,所以在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 中需要判断是否为 CGlib
    创建对象,否则是不能正确拿到类信息的。

向BeanFactory中注册AutowiredAnnotationBeanPostProcessor

源码: lqf.springframework.context.annotation.ClassPathBeanDefinitionScanner

  • 由于AutowiredAnnotationBeanPostProcessor并没有标注@Component,所以是无法在类扫描时注入到beanFactory中的,此处需要我们手动进行注册。

在Bean的生命周期中调用属性注入

  • AbstractAutowireCapableBeanFactory#createBean 方法中有这一条新增加的方法调用,就是在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值 的操作 applyBeanPostProcessorsBeforeApplyingPropertyValues
  • applyBeanPostProcessorsBeforeApplyingPropertyValues 方法中,首先就是获取已经注入的 BeanPostProcessor 集合并从中筛选出继承接口
    InstantiationAwareBeanPostProcessor 的实现类。
  • 调用相应的 postProcessPropertyValues
    方法以及循环设置属性值信息,beanDefinition.getPropertyValues().addPropertyValue(propertyValue);

总结

  • 从整个注解信息扫描注入的实现内容来看,我们一直是围绕着在 Bean 的生命周期中进行处理,就像 BeanPostProcessor 用于修改新实例化
    Bean 对象的扩展点,提供的接口方法可以用于处理 Bean 对象实例化前后进行处理操作。而有时候需要做一些差异化的控制,所以还需要继承
    BeanPostProcessor 接口,定义新的接口 InstantiationAwareBeanPostProcessor 这样就可以区分出不同扩展点的操作了。

  • 接口用 instanceof 判断,注解用 Field.getAnnotation(Value.class);
    获取,都是相当于在类上做的一些标识性信息,便于可以用一些方法找到这些功能点,以便进行处理。所以在我们日常开发设计的组件中,也可以运用上这些特点。

    返回目录