精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

萬人之敵,通過注解給屬性注入配置和Bean對象

開發 前端
目前 IOC、AOP 兩大核心功能模塊的支撐下,完全可以管理 Bean 對象的注冊和獲取,不過這樣的使用方式總感覺像是刀耕火種有點難用。

[[415213]]

本文轉載自微信公眾號「bugstack蟲洞棧」,作者小傅哥。轉載本文請聯系bugstack蟲洞棧公眾號。

一、前言

寫代碼,就是從能用到好用的不斷折騰!

你聽過擾動函數嗎?你寫過斐波那契(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 修改屬性值。整體設計結構如下圖:

  • 要處理自動掃描注入,包括屬性注入、對象注入,則需要在對象屬性 applyPropertyValues 填充之前 ,把屬性信息寫入到 PropertyValues 的集合中去。這一步的操作相當于是解決了以前在 spring.xml 配置屬性的過程。
  • 而在屬性的讀取中,需要依賴于對 Bean 對象的類中屬性的配置了注解的掃描,field.getAnnotation(Value.class); 依次拿出符合的屬性并填充上相應的配置信息。這里有一點 ,屬性的配置信息需要依賴于 BeanFactoryPostProcessor 的實現類 PropertyPlaceholderConfigurer,把值寫入到 AbstractBeanFactory的embeddedValueResolvers集合中,這樣才能在屬性填充中利用 beanFactory 獲取相應的屬性值
  • 還有一個是關于 @Autowired 對于對象的注入,其實這一個和屬性注入的唯一區別是對于對象的獲取 beanFactory.getBean(fieldType),其他就沒有什么差一點了。
  • 當所有的屬性被設置到 PropertyValues 完成以后,接下來就到了創建對象的下一步,屬性填充,而此時就會把我們一一獲取到的配置和對象填充到屬性上,也就實現了自動注入的功能。

四、實現

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

  • 在整個類圖中以圍繞實現接口 InstantiationAwareBeanPostProcessor 的類 AutowiredAnnotationBeanPostProcessor 作為入口點,被 AbstractAutowireCapableBeanFactory創建 Bean 對象過程中調用掃描整個類的屬性配置中含有自定義注解 Value、Autowired、Qualifier,的屬性值。
  • 這里稍有變動的是關于屬性值信息的獲取,在注解配置的屬性字段掃描到信息注入時,包括了占位符從配置文件獲取信息也包括 Bean 對象,Bean 對象可以直接獲取,但配置信息需要在 AbstractBeanFactory 中添加新的屬性集合 embeddedValueResolvers,由 PropertyPlaceholderConfigurer#postProcessBeanFactory 進行操作填充到屬性集合中。

2. 把讀取到屬性填充到容器

定義解析字符串接口

cn.bugstack.springframework.util.StringValueResolver

  1. public interface StringValueResolver { 
  2.  
  3.     String resolveStringValue(String strVal); 
  4.  
  • 接口 StringValueResolver 是一個解析字符串操作的接口

填充字符串

  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.  
  • 在解析屬性配置的類 PropertyPlaceholderConfigurer 中,最主要的其實就是這行代碼的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 這是把屬性值寫入到了 AbstractBeanFactory 的 embeddedValueResolvers 中。
  • 這里說明下,embeddedValueResolvers 是 AbstractBeanFactory 類新增加的集合 List embeddedValueResolvers String resolvers to apply e.g. to annotation attribute values

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.      * The actual value expression: e.g. "#{systemProperties.myProp}"
  22.      */ 
  23.     String value(); 
  24.  

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.  
  • AutowiredAnnotationBeanPostProcessor 是實現接口 InstantiationAwareBeanPostProcessor 的一個用于在 Bean 對象實例化完成后,設置屬性操作前的處理屬性信息的類和操作方法。只有實現了 BeanPostProcessor 接口才有機會在 Bean 的生命周期中處理初始化信息
  • 核心方法 postProcessPropertyValues,主要用于處理類含有 @Value、@Autowired 注解的屬性,進行屬性信息的提取和設置。
  • 這里需要注意一點因為我們在 AbstractAutowireCapableBeanFactory 類中使用的是 CglibSubclassingInstantiationStrategy 進行類的創建,所以在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 中需要判斷是否為 CGlib 創建對象,否則是不能正確拿到類信息的。ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;

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.      * 在設置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值 
  38.      * 
  39.      * @param beanName 
  40.      * @param bean 
  41.      * @param beanDefinition 
  42.      */ 
  43.     protected void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) { 
  44.         for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) { 
  45.             if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor){ 
  46.                 PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName); 
  47.                 if (null != pvs) { 
  48.                     for (PropertyValue propertyValue : pvs.getPropertyValues()) { 
  49.                         beanDefinition.getPropertyValues().addPropertyValue(propertyValue); 
  50.                     } 
  51.                 } 
  52.             } 
  53.         } 
  54.     }   
  55.  
  56.     // ... 
  • AbstractAutowireCapableBeanFactory#createBean 方法中有這一條新增加的方法調用,就是在設置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值 的操作 applyBeanPostProcessorsBeforeApplyingPropertyValues
  • 那么這個 applyBeanPostProcessorsBeforeApplyingPropertyValues 方法中,首先就是獲取已經注入的 BeanPostProcessor 集合并從中篩選出繼承接口 InstantiationAwareBeanPostProcessor 的實現類。
  • 最后就是調用相應的 postProcessPropertyValues 方法以及循環設置屬性值信息,beanDefinition.getPropertyValues().addPropertyValue(propertyValue);

五、測試

1. 事先準備

配置 Dao

  1. @Component 
  2. public class UserDao { 
  3.  
  4.     private static Map<String, String> 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.  
  • 給類配置上一個自動掃描注冊 Bean 對象的注解 @Component,接下來會把這個類注入到 UserService 中。

注解注入到 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.     // ... 
  • 這里包括了兩種類型的注入,一個是占位符注入屬性信息 @Value("${token}"),另外一個是注入對象信息 @Autowired

2. 屬性配置文件

token.properties

  1. token=RejDlI78hu223Opo983Ds 

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="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.     <bean class="cn.bugstack.springframework.beans.factory.PropertyPlaceholderConfigurer"
  10.         <property name="location" value="classpath:token.properties"/> 
  11.     </bean> 
  12.  
  13.     <context:component-scan base-package="cn.bugstack.springframework.test.bean"/> 
  14.  
  15. </beans> 

 

 

在 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()); 
  • 單元測試時候就可以完整的測試一個類注入到 Spring 容器,同時這個屬性信息也可以被自動掃描填充上。

測試結果

測試結果:小傅哥,北京,亦莊,RejDlI78hu223Opo983Ds

Process finished with exit code 0

  • 從測試結果可以看到現在我們的使用方式已經通過了,有自動掃描類,有注解注入屬性。這與使用 Spring 框架越來越像了。

六、總結

 

  • 從整個注解信息掃描注入的實現內容來看,我們一直是圍繞著在 Bean 的生命周期中進行處理,就像 BeanPostProcessor 用于修改新實例化 Bean 對象的擴展點,提供的接口方法可以用于處理 Bean 對象實例化前后進行處理操作。而有時候需要做一些差異化的控制,所以還需要繼承 BeanPostProcessor 接口,定義新的接口 InstantiationAwareBeanPostProcessor 這樣就可以區分出不同擴展點的操作了。
  • 像是接口用 instanceof 判斷,注解用 Field.getAnnotation(Value.class); 獲取,都是相當于在類上做的一些標識性信息,便于可以用一些方法找到這些功能點,以便進行處理。所以在我們日常開發設計的組件中,也可以運用上這些特點。
  • 當你思考把你的實現融入到一個已經細分好的 Bean 生命周期中,你會發現它的設計是如此的好,可以讓你在任何初始化的時間點上,任何面上,都能做你需要的擴展或者改變,這也是我們做程序設計時追求的靈活性。

 

責任編輯:武曉燕 來源: bugstack蟲洞棧
相關推薦

2021-06-03 07:55:12

技術

2023-07-11 09:14:12

Beanquarkus

2017-10-15 21:19:19

科技盛會

2009-06-15 17:48:32

Spring注解注入屬性

2021-07-28 07:53:19

配置Bean掃描

2021-11-11 11:38:56

Robinhood數據泄露網絡攻擊

2013-06-20 09:30:41

華為數據中心萬人桌面云華為

2010-01-06 09:16:10

MySQL

2009-03-10 08:20:35

鴻海招募軟件代工

2011-11-02 09:20:26

華為云計算

2018-10-16 09:35:25

Facebook攻擊漏洞

2020-02-03 19:04:50

10萬人場館畫座位

2010-09-09 15:16:03

郭臺銘

2010-09-14 09:11:00

2019-12-16 17:25:04

Python微信群同步直播

2010-05-11 10:35:56

IT企業招聘

2023-08-31 00:03:28

2012-06-01 14:46:13

華為裁員

2018-12-07 09:50:36

裁員失業中年人

2009-11-30 09:17:00

IBM員工數量
點贊
收藏

51CTO技術棧公眾號

亚洲视频二区| 日韩av三区| 亚洲精品老司机| 国产98在线|日韩| 日本熟妇毛耸耸xxxxxx| 亚洲美女久久| 欧美久久高跟鞋激| 成人在线国产视频| 福利片在线看| 国产精品18久久久| 清纯唯美亚洲激情| 希岛爱理中文字幕| 亚洲第一二三区| 欧美伦理视频网站| 5月婷婷6月丁香| av中文字幕在线| 国产成人精品一区二区三区四区 | 成人av.网址在线网站| 久草免费在线视频观看| 久草精品在线| 欧美va亚洲va香蕉在线| 国产第一页视频| 超碰在线观看免费| 国产亚洲欧美日韩日本| 91gao视频| 日韩av免费播放| 欧美日韩第一区| 正在播放欧美视频| 亚洲精品乱码久久久久久久| 全球中文成人在线| 欧美性高潮床叫视频| 欧美一级黄色录像片| 久热av在线| 国产高清亚洲一区| 国产精品视频自在线| 日韩欧美一区二区一幕| 91精品亚洲| 一本色道久久88综合亚洲精品ⅰ | 久久综合久色欧美综合狠狠| 147欧美人体大胆444| 中文字幕av久久爽| 亚洲欧美日韩国产一区二区| 欧美人与物videos| 特一级黄色录像| 欧美国产偷国产精品三区| 亚洲精品一区中文| 免费黄色三级网站| 成人福利一区| 欧美成人综合网站| 中文字幕无码毛片免费看| 久久精品黄色| 欧美色大人视频| 久久精品午夜福利| 在线观看爽视频| 亚洲成a人v欧美综合天堂下载| 粉嫩av一区二区三区天美传媒| a中文在线播放| 国产欧美日韩亚州综合| 小说区图片区图片区另类灬| 韩国福利在线| 国产丝袜欧美中文另类| 欧美日韩一区在线观看视频| 九色在线播放| 国产欧美日韩精品在线| 欧美日韩精品久久久免费观看| 日本私人网站在线观看| 99久久99久久综合| 免费在线成人av| 黄色片在线播放| 国产女主播在线一区二区| 天堂av一区二区| 五月天婷婷在线视频| 国产精品久久久久久福利一牛影视| 天堂√在线观看一区二区| 欧美人xxx| 亚洲人午夜精品天堂一二香蕉| 乱子伦一区二区| 日本动漫理论片在线观看网站| 一区二区三区精品在线| 免费一级特黄毛片| 制服丝袜专区在线| 色94色欧美sute亚洲线路一ni| 男人舔女人下面高潮视频| 国产成人精品一区二区三区视频| 欧美日韩精品欧美日韩精品| 日本黄色一级网站| 久久久久观看| 一区二区三区天堂av| 国产3级在线观看| 亚洲欧美一级二级三级| 性欧美视频videos6一9| 亚洲天堂男人av| 狠狠狠色丁香婷婷综合激情| 91青青草免费观看| 偷拍25位美女撒尿视频在线观看| 久久久亚洲精品一区二区三区 | 国产精品欧美一区二区三区奶水| 国产又大又黑又粗| 成人国产电影网| 日韩欧美在线一区二区| 国产激情视频在线| 日韩欧美成人区| 日本在线播放一区二区| 国产成人tv| 一区二区成人精品| 精品无码m3u8在线观看| 久久九九国产| 亚洲直播在线一区| 蜜桃视频在线观看网站| 亚洲免费在线观看视频| 国产最新免费视频| 国产精选久久| 亚洲人成在线观看网站高清| 亚洲成人生活片| 久久婷婷麻豆| 国产91亚洲精品| 亚洲欧美在线免费| 国产精品永久在线| 99久久精品无免国产免费| a在线播放不卡| 亚洲午夜高清视频| 超碰在线网站| 欧美丰满美乳xxx高潮www| 黄色激情在线观看| 999国产精品999久久久久久| 91黑丝高跟在线| 91午夜交换视频| 久久久精品免费网站| 国产精品成人久久电影| 国产精品亚洲四区在线观看| 国产香蕉一区二区三区在线视频| 国产精彩视频在线观看| 国产原创一区二区三区| 色综合电影网| 视频二区不卡| 国产视频欧美视频| 久久久久99精品| 国产精选一区二区三区 | 日韩精品免费一区二区夜夜嗨| 色妞欧美日韩在线| 欧美视频xxxx| 久久久五月婷婷| 极品美女扒开粉嫩小泬| 欧美经典一区| 欧美巨大黑人极品精男| 91精品国产乱码久久久久| 国产精品午夜在线观看| 午夜激情av在线| 欧美色图在线播放| 国产成人久久久精品一区| 免费在线国产| 色欧美日韩亚洲| 人妻少妇无码精品视频区| 久久久水蜜桃av免费网站| 快播亚洲色图| 亚洲天堂av在线| 精品视频久久久久久| 精品一区二区三区人妻| 大白屁股一区二区视频| 国产一二三四五| 亚洲人成网站在线在线观看| 色婷婷av一区二区三区久久| 麻豆天美蜜桃91| 国产在线观看一区二区| 中文字幕在线亚洲精品| 国产精品久久久久久久久久辛辛| 精品中文字幕在线| 国产黄色一区二区| 一区二区三区四区精品在线视频| 天天看片天天操| 欧美丰满日韩| 丁香婷婷久久久综合精品国产| 超碰超碰在线| 91精品欧美福利在线观看| 91免费公开视频| 国内成人免费视频| 亚洲自拍三区| 国产电影一区二区| 亚洲色图在线观看| 久久久久久久久久码影片| 免费在线性爱视频| 欧美在线三级电影| 蜜桃av免费在线观看| 老司机免费视频一区二区| 一区二区精品视频| 日韩精品视频中文字幕| 91国自产精品中文字幕亚洲| 理论视频在线| 欧美高清hd18日本| 久久久久久久国产视频| 99r精品视频| 国内外免费激情视频| 日韩欧美精品综合| 91免费电影网站| 黑人极品ⅴideos精品欧美棵| 亚洲免费中文字幕| 一级久久久久久久| 一区二区三区在线视频免费观看| youjizz.com日本| 亚洲黄色免费| 一本久道久久综合狠狠爱亚洲精品| 青草综合视频| 欧美激情三级免费| 国产三级视频在线看| 欧美美女网站色| www日韩精品| 国产精品亲子乱子伦xxxx裸| 国产老头和老头xxxx×| 国产视频亚洲| mm131午夜| 欧美精美视频| 亚洲最大福利网| 1234区中文字幕在线观看| 亚洲欧美日韩天堂一区二区| 精品久久在线观看| 精品露脸国产偷人在视频| 日本一二三不卡视频| 粉嫩一区二区三区在线看| 国产午夜福利视频在线观看| 婷婷丁香综合| 免费成人深夜夜行视频| 国产精品亚洲欧美一级在线| 欧美一级大片在线免费观看| 色女人在线视频| 亚洲夜晚福利在线观看| 午夜精品久久久久久久99| 91福利在线播放| 丝袜 亚洲 另类 欧美 重口| 欧美激情资源网| 艳妇乳肉豪妇荡乳xxx| 久久av中文字幕片| www.亚洲天堂网| 日韩视频中文| japanese在线播放| 深爱激情久久| 极品校花啪啪激情久久| 成人动态视频| 69堂成人精品视频免费| aaaa欧美| 国产suv精品一区二区三区88区| 狠狠操一区二区三区| 欧美成在线视频| 色综合久久影院| 亚洲深夜福利视频| 性xxxx搡xxxxx搡欧美| 精品欧美一区二区久久| 国产精品伦一区二区三区| 91国在线观看| 久久精品波多野结衣| 亚洲黄网站在线观看| 久久久99999| 国产精品看片你懂得| 欧美黄色一级生活片| 久久人人爽人人爽| 懂色av粉嫩av蜜乳av| 成人小视频在线| 精品少妇一区二区| 97在线观看视频国产| eeuss中文| 色一情一乱一区二区三区| 欧美日韩国产a| 91丨porny丨在线中文 | 国产精品成人aaaa在线| 亚洲人成网站色在线观看| 一本一本久久a久久| 亚洲特黄一级片| 国产真实乱在线更新| 中文字幕一区日韩精品欧美| 一本在线免费视频| 亚洲免费三区一区二区| 国产一二三四区| 亚洲免费视频中文字幕| 免费一级片在线观看| 午夜一区二区三区视频| 成人午夜视频精品一区| 婷婷久久综合九色综合伊人色| 免费观看一区二区三区毛片| 欧美在线观看禁18| 怡春院在线视频| 欧美精品九九99久久| 3d蒂法精品啪啪一区二区免费| 韩国一区二区av| 中文字幕免费观看| 99久久婷婷国产综合精品首页| 蜜臀久久99精品久久久画质超高清| 在线观看日韩av先锋影音电影院| 成人啪啪免费看| 成人免费看aa片| 中文字幕伦理免费在线视频| 国产精品腿扒开做爽爽爽挤奶网站| 福利一区视频在线观看| 成人在线观看www| 日韩欧美伦理| 欧洲xxxxx| 一区二区三区精品视频在线观看| 337p粉嫩大胆噜噜噜鲁| 久久久一二三| 中文字幕永久有效| 成人午夜又粗又硬又大| 女同毛片一区二区三区| 日本一区二区视频在线| 四虎永久免费在线| 日韩欧美中文免费| 亚洲中文一区二区三区| 日韩欧美国产不卡| 青青草在线免费视频| 欧美成人午夜激情视频| 女人让男人操自己视频在线观看 | 欧美性大战久久久| 精品无码一区二区三区的天堂| 日韩欧美色电影| 欧洲免费在线视频| 久热99视频在线观看| 黄色18在线观看| 亚洲最大的av网站| 国产一区二区三区四区| 国产四区在线观看| 欧美精品99| 国产原创精品在线| gogogo免费视频观看亚洲一| 一级免费黄色录像| 亚洲精品老司机| 亚洲网站免费观看| 亚洲精品福利免费在线观看| 免费在线看黄网站| 91精品国产色综合久久不卡98口| 欧美一区二区三区婷婷| 久久天堂国产精品| 欧美阿v一级看视频| 日韩av.com| 久久婷婷一区二区三区| 精品少妇一二三区| 在线观看欧美精品| 欧洲伦理片一区 二区 三区| 久久久久久久久久久久av| 亚洲欧美专区| 欧美日韩在线播放一区二区| 欧美69视频| 日韩欧美国产片| 久久久久久免费网| 波多野结衣黄色| 亚洲第一男人av| 一二三级黄色片| 免费看欧美女人艹b| avtt香蕉久久| 亚洲男人都懂的| 精品久久久无码中文字幕| 日韩一区视频在线| 在线一区视频观看| 视频一区视频二区视频| 免费亚洲视频| 亚洲欧美日本一区| 欧美色videos| 神马午夜在线观看| 国内偷自视频区视频综合| 亚洲美女色播| 免费cad大片在线观看| 精品一区二区三区免费播放 | 成人99免费视频| 中文在线观看免费网站| 精品日韩一区二区三区| 视频在线这里都是精品| 国产美女精彩久久| 久久中文亚洲字幕| 国产精品拍拍拍| 日本一区二区免费在线| 国产精品毛片久久久久久久av| 中文字幕日韩综合av| 忘忧草在线www成人影院| 日韩黄色影视| 奇米影视在线99精品| 欧美激情久久久久久久| 欧美性色综合网| 国产超级va在线视频| 99在线视频首页| 在线日本成人| 夜夜春很很躁夜夜躁| 欧美日韩一区二区三区四区 | 一区二区三区久久精品| 亚洲午夜剧场| 欧美日韩中文字幕在线播放 | 性高潮久久久久久| 婷婷中文字幕一区三区| 日本护士...精品国| 国产精品美乳在线观看| 亚洲香蕉av| 精品影片一区二区入口| 欧美日韩在线看| 国产在线观看91| 999视频在线观看| 亚洲高清激情| 中文字幕5566| 欧美一级夜夜爽| av中文在线资源库| 精品国产免费久久久久久尖叫| 蜜臀av性久久久久蜜臀aⅴ流畅 | av免费观看在线| 欧美在线视频导航| 日韩黄色大片网站| 中文字幕制服丝袜|