文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

万人之敌,通过注解给属性注入配置和Bean对象

2024-12-02 23:54

关注

一、前言

写代码,就是从能用到好用的不断折腾!

你听过扰动函数吗?你写过斐波那契(Fibonacci)散列吗?你实现过梅森旋转算法吗?怎么 没听过这些写不了代码吗!不会的,即使没听过你一样可以写的了代码,比如你实现的数据库路由数据总是落在1库1表它不散列分布、你实现的抽奖系统总是把运营配置的最大红包发出去提高了运营成本、你开发的秒杀系统总是在开始后的1秒就挂了货品根本给不出去。

除了一部分仅把编码当成搬砖应付工作外的程序员,还有一部分总是在追求极致的码农。写代码还能赚钱,真开心! 这样的码农总是会考虑??还有没有更好的实现逻辑能让代码不仅是能用,还要好用呢?其实这一点的追求到完成,需要大量扩展性学习和深度挖掘,这样你设计出来的系统才更你考虑的更加全面,也能应对各种复杂的场景。

二、目标

在目前 IOC、AOP 两大核心功能模块的支撑下,完全可以管理 Bean 对象的注册和获取,不过这样的使用方式总感觉像是刀耕火种有点难用。因此在上一章节我们解决需要手动配置 Bean 对象到 spring.xml 文件中,改为可以自动扫描带有注解 @Component 的对象完成自动装配和注册到 Spring 容器的操作。

那么在自动扫描包注册 Bean 对象之后,就需要把原来在配置文件中通过 property name="token" 配置属性和Bean的操作,也改为可以自动注入。这就像我们使用 Spring 框架中 @Autowired、@Value 注解一样,完成我们对属性和对象的注入操作。

三、方案

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

四、实现

1. 工程结构

  1. small-spring-step-14 
  2. └── src 
  3.     ├── main 
  4.     │   └── java 
  5.     │       └── cn.bugstack.springframework 
  6.     │           ├── aop 
  7.     │           │   ├── aspectj 
  8.     │           │   │   └── AspectJExpressionPointcut.java 
  9.     │           │   │   └── AspectJExpressionPointcutAdvisor.java 
  10.     │           │   ├── framework  
  11.     │           │   │   ├── adapter 
  12.     │           │   │   │   └── MethodBeforeAdviceInterceptor.java 
  13.     │           │   │   ├── autoproxy 
  14.     │           │   │   │   └── MethodBeforeAdviceInterceptor.java 
  15.     │           │   │   ├── AopProxy.java 
  16.     │           │   │   ├── Cglib2AopProxy.java 
  17.     │           │   │   ├── JdkDynamicAopProxy.java 
  18.     │           │   │   ├── ProxyFactory.java 
  19.     │           │   │   └── ReflectiveMethodInvocation.java 
  20.     │           │   ├── AdvisedSupport.java 
  21.     │           │   ├── Advisor.java 
  22.     │           │   ├── BeforeAdvice.java 
  23.     │           │   ├── ClassFilter.java 
  24.     │           │   ├── MethodBeforeAdvice.java 
  25.     │           │   ├── MethodMatcher.java 
  26.     │           │   ├── Pointcut.java 
  27.     │           │   ├── PointcutAdvisor.java 
  28.     │           │   └── TargetSource.java 
  29.     │           ├── beans 
  30.     │           │   ├── factory   
  31.     │           │   │   ├── annotation 
  32.     │           │   │   │   ├── Autowired.java 
  33.     │           │   │   │   ├── AutowiredAnnotationBeanPostProcessor.java 
  34.     │           │   │   │   ├── Qualifier.java 
  35.     │           │   │   │   └── Value.java 
  36.     │           │   │   ├── config 
  37.     │           │   │   │   ├── AutowireCapableBeanFactory.java 
  38.     │           │   │   │   ├── BeanDefinition.java 
  39.     │           │   │   │   ├── BeanFactoryPostProcessor.java 
  40.     │           │   │   │   ├── BeanPostProcessor.java 
  41.     │           │   │   │   ├── BeanReference.java 
  42.     │           │   │   │   ├── ConfigurableBeanFactory.java 
  43.     │           │   │   │   ├── InstantiationAwareBeanPostProcessor.java 
  44.     │           │   │   │   └── SingletonBeanRegistry.java 
  45.     │           │   │   ├── support 
  46.     │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java 
  47.     │           │   │   │   ├── AbstractBeanDefinitionReader.java 
  48.     │           │   │   │   ├── AbstractBeanFactory.java 
  49.     │           │   │   │   ├── BeanDefinitionReader.java 
  50.     │           │   │   │   ├── BeanDefinitionRegistry.java 
  51.     │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java 
  52.     │           │   │   │   ├── DefaultListableBeanFactory.java 
  53.     │           │   │   │   ├── DefaultSingletonBeanRegistry.java 
  54.     │           │   │   │   ├── DisposableBeanAdapter.java 
  55.     │           │   │   │   ├── FactoryBeanRegistrySupport.java 
  56.     │           │   │   │   ├── InstantiationStrategy.java 
  57.     │           │   │   │   └── SimpleInstantiationStrategy.java   
  58.     │           │   │   ├── support 
  59.     │           │   │   │   └── XmlBeanDefinitionReader.java 
  60.     │           │   │   ├── Aware.java 
  61.     │           │   │   ├── BeanClassLoaderAware.java 
  62.     │           │   │   ├── BeanFactory.java 
  63.     │           │   │   ├── BeanFactoryAware.java 
  64.     │           │   │   ├── BeanNameAware.java 
  65.     │           │   │   ├── ConfigurableListableBeanFactory.java 
  66.     │           │   │   ├── DisposableBean.java 
  67.     │           │   │   ├── FactoryBean.java 
  68.     │           │   │   ├── HierarchicalBeanFactory.java 
  69.     │           │   │   ├── InitializingBean.java 
  70.     │           │   │   ├── ListableBeanFactory.java 
  71.     │           │   │   └── PropertyPlaceholderConfigurer.java 
  72.     │           │   ├── BeansException.java 
  73.     │           │   ├── PropertyValue.java 
  74.     │           │   └── PropertyValues.java  
  75.     │           ├── context 
  76.     │           │   ├── annotation 
  77.     │           │   │   ├── ClassPathBeanDefinitionScanner.java  
  78.     │           │   │   ├── ClassPathScanningCandidateComponentProvider.java  
  79.     │           │   │   └── Scope.java  
  80.     │           │   ├── event 
  81.     │           │   │   ├── AbstractApplicationEventMulticaster.java  
  82.     │           │   │   ├── ApplicationContextEvent.java  
  83.     │           │   │   ├── ApplicationEventMulticaster.java  
  84.     │           │   │   ├── ContextClosedEvent.java  
  85.     │           │   │   ├── ContextRefreshedEvent.java  
  86.     │           │   │   └── SimpleApplicationEventMulticaster.java  
  87.     │           │   ├── support 
  88.     │           │   │   ├── AbstractApplicationContext.java  
  89.     │           │   │   ├── AbstractRefreshableApplicationContext.java  
  90.     │           │   │   ├── AbstractXmlApplicationContext.java  
  91.     │           │   │   ├── ApplicationContextAwareProcessor.java  
  92.     │           │   │   └── ClassPathXmlApplicationContext.java  
  93.     │           │   ├── ApplicationContext.java  
  94.     │           │   ├── ApplicationContextAware.java  
  95.     │           │   ├── ApplicationEvent.java  
  96.     │           │   ├── ApplicationEventPublisher.java  
  97.     │           │   ├── ApplicationListener.java  
  98.     │           │   └── ConfigurableApplicationContext.java 
  99.     │           ├── core.io 
  100.     │           │   ├── ClassPathResource.java  
  101.     │           │   ├── DefaultResourceLoader.java  
  102.     │           │   ├── FileSystemResource.java  
  103.     │           │   ├── Resource.java  
  104.     │           │   ├── ResourceLoader.java 
  105.     │           │   └── UrlResource.java 
  106.     │           ├── stereotype 
  107.     │           │   └── Component.java 
  108.     │           └── utils 
  109.     │               ├── ClassUtils.java 
  110.     │               └── StringValueResolver.java 
  111.     └── test 
  112.         └── java 
  113.             └── cn.bugstack.springframework.test 
  114.                 ├── bean 
  115.                 │   ├── IUserService.java 
  116.                 │   └── UserService.java 
  117.                 └── ApiTest.java 

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

图 15-2

2. 把读取到属性填充到容器

定义解析字符串接口

cn.bugstack.springframework.util.StringValueResolver

  1. public interface StringValueResolver { 
  2.  
  3.     String resolveStringValue(String strVal); 
  4.  

填充字符串

  1. public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor { 
  2.  
  3.     @Override 
  4.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 
  5.         try { 
  6.             // 加载属性文件 
  7.             DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); 
  8.             Resource resource = resourceLoader.getResource(location); 
  9.              
  10.             // ... 占位符替换属性值、设置属性值 
  11.  
  12.             // 向容器中添加字符串解析器,供解析@Value注解使用 
  13.             StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties); 
  14.             beanFactory.addEmbeddedValueResolver(valueResolver); 
  15.              
  16.         } catch (IOException e) { 
  17.             throw new BeansException("Could not load properties", e); 
  18.         } 
  19.     } 
  20.  
  21.     private class PlaceholderResolvingStringValueResolver implements StringValueResolver { 
  22.  
  23.         private final Properties properties; 
  24.  
  25.         public PlaceholderResolvingStringValueResolver(Properties properties) { 
  26.             this.properties = properties; 
  27.         } 
  28.  
  29.         @Override 
  30.         public String resolveStringValue(String strVal) { 
  31.             return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties); 
  32.         } 
  33.  
  34.     } 
  35.  

3. 自定义属性注入注解

自定义注解,Autowired、Qualifier、Value

  1. @Retention(RetentionPolicy.RUNTIME) 
  2. @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD}) 
  3. public @interface Autowired { 
  4.  
  5. @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) 
  6. @Retention(RetentionPolicy.RUNTIME) 
  7. @Inherited 
  8. @Documented 
  9. public @interface Qualifier { 
  10.  
  11.     String value() default ""
  12.  
  13. }   
  14.  
  15. @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) 
  16. @Retention(RetentionPolicy.RUNTIME) 
  17. @Documented 
  18. public @interface Value { 
  19.  
  20.      
  21.     String value(); 
  22.  

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

4. 扫描自定义注解

cn.bugstack.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

  1. public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware { 
  2.  
  3.     private ConfigurableListableBeanFactory beanFactory; 
  4.  
  5.     @Override 
  6.     public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 
  7.         this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; 
  8.     } 
  9.  
  10.     @Override 
  11.     public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException { 
  12.         // 1. 处理注解 @Value 
  13.         Class clazz = bean.getClass(); 
  14.         clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz; 
  15.  
  16.         Field[] declaredFields = clazz.getDeclaredFields(); 
  17.  
  18.         for (Field field : declaredFields) { 
  19.             Value valueAnnotation = field.getAnnotation(Value.class); 
  20.             if (null != valueAnnotation) { 
  21.                 String value = valueAnnotation.value(); 
  22.                 value = beanFactory.resolveEmbeddedValue(value); 
  23.                 BeanUtil.setFieldValue(bean, field.getName(), value); 
  24.             } 
  25.         } 
  26.  
  27.         // 2. 处理注解 @Autowired 
  28.         for (Field field : declaredFields) { 
  29.             Autowired autowiredAnnotation = field.getAnnotation(Autowired.class); 
  30.             if (null != autowiredAnnotation) { 
  31.                 Class fieldType = field.getType(); 
  32.                 String dependentBeanName = null
  33.                 Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class); 
  34.                 Object dependentBean = null
  35.                 if (null != qualifierAnnotation) { 
  36.                     dependentBeanName = qualifierAnnotation.value(); 
  37.                     dependentBean = beanFactory.getBean(dependentBeanName, fieldType); 
  38.                 } else { 
  39.                     dependentBean = beanFactory.getBean(fieldType); 
  40.                 } 
  41.                 BeanUtil.setFieldValue(bean, field.getName(), dependentBean); 
  42.             } 
  43.         } 
  44.  
  45.         return pvs; 
  46.     } 
  47.  

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

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  1. public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { 
  2.  
  3.     private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); 
  4.  
  5.     @Override 
  6.     protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException { 
  7.         Object bean = null
  8.         try { 
  9.             // 判断是否返回代理 Bean 对象 
  10.             bean = resolveBeforeInstantiation(beanName, beanDefinition); 
  11.             if (null != bean) { 
  12.                 return bean; 
  13.             } 
  14.             // 实例化 Bean 
  15.             bean = createBeanInstance(beanDefinition, beanName, args); 
  16.             // 在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值 
  17.             applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition); 
  18.             // 给 Bean 填充属性 
  19.             applyPropertyValues(beanName, bean, beanDefinition); 
  20.             // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法 
  21.             bean = initializeBean(beanName, bean, beanDefinition); 
  22.         } catch (Exception e) { 
  23.             throw new BeansException("Instantiation of bean failed", e); 
  24.         } 
  25.  
  26.         // 注册实现了 DisposableBean 接口的 Bean 对象 
  27.         registerDisposableBeanIfNecessary(beanName, bean, beanDefinition); 
  28.  
  29.         // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE 
  30.         if (beanDefinition.isSingleton()) { 
  31.             registerSingleton(beanName, bean); 
  32.         } 
  33.         return bean; 
  34.     } 
  35.  
  36.      
  37.     protected void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) { 
  38.         for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) { 
  39.             if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor){ 
  40.                 PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName); 
  41.                 if (null != pvs) { 
  42.                     for (PropertyValue propertyValue : pvs.getPropertyValues()) { 
  43.                         beanDefinition.getPropertyValues().addPropertyValue(propertyValue); 
  44.                     } 
  45.                 } 
  46.             } 
  47.         } 
  48.     }   
  49.  
  50.     // ... 

五、测试

1. 事先准备

配置 Dao

  1. @Component 
  2. public class UserDao { 
  3.  
  4.     private static Map hashMap = new HashMap<>(); 
  5.  
  6.     static { 
  7.         hashMap.put("10001""小傅哥,北京,亦庄"); 
  8.         hashMap.put("10002""八杯水,上海,尖沙咀"); 
  9.         hashMap.put("10003""阿毛,香港,铜锣湾"); 
  10.     } 
  11.  
  12.     public String queryUserName(String uId) { 
  13.         return hashMap.get(uId); 
  14.     } 
  15.  

注解注入到 UserService

  1. @Component("userService"
  2. public class UserService implements IUserService { 
  3.  
  4.     @Value("${token}"
  5.     private String token; 
  6.  
  7.     @Autowired 
  8.     private UserDao userDao; 
  9.  
  10.     public String queryUserInfo() { 
  11.         try { 
  12.             Thread.sleep(new Random(1).nextInt(100)); 
  13.         } catch (InterruptedException e) { 
  14.             e.printStackTrace(); 
  15.         } 
  16.         return userDao.queryUserName("10001") + "," + token; 
  17.     }     
  18.  
  19.     // ... 

2. 属性配置文件

token.properties

  1. token=RejDlI78hu223Opo983Ds 

spring.xml

  1. "1.0" encoding="UTF-8"?> 
  2. "http://www.springframework.org/schema/beans" 
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.        xmlns:context="http://www.springframework.org/schema/context" 
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans 
  6.           http://www.springframework.org/schema/beans/spring-beans.xsd 
  7.    http://www.springframework.org/schema/context"> 
  8.  
  9.     "cn.bugstack.springframework.beans.factory.PropertyPlaceholderConfigurer"
  10.         name="location" value="classpath:token.properties"/> 
  11.      
  12.  
  13.     "cn.bugstack.springframework.test.bean"/> 
  14.  
  15.  

 

 

在 spring.xml 中配置了扫描属性信息和自动扫描包路径范围。

3. 单元测试

  1. @Test 
  2. public void test_scan() { 
  3.     ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml"); 
  4.     IUserService userService = applicationContext.getBean("userService", IUserService.class); 
  5.     System.out.println("测试结果:" + userService.queryUserInfo()); 

测试结果

测试结果:小傅哥,北京,亦庄,RejDlI78hu223Opo983Ds

Process finished with exit code 0

六、总结

 

 

来源: bugstack虫洞栈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯