小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

《Spring 手?jǐn)]專欄》第 15 章:萬(wàn)人之?dāng)常ㄟ^(guò)注解給屬性注入配置和Bean對(duì)象

 小傅哥 2021-12-13

作者:小傅哥
博客:https://

?

沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!??

?

目錄

  • 一、前言

  • 二、目標(biāo)

  • 三、方案

  • 四、實(shí)現(xiàn)

    • 1. 工程結(jié)構(gòu)

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

    • 3. 自定義屬性注入注解

    • 4. 掃描自定義注解

    • 5. 在Bean的生命周期中調(diào)用屬性注入

  • 五、測(cè)試

    • 1. 事先準(zhǔn)備

    • 2. 屬性配置文件

    • 3. 單元測(cè)試

  • 六、總結(jié)

  • 七、系列推薦

一、前言

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

你聽(tīng)過(guò)擾動(dòng)函數(shù)嗎?你寫(xiě)過(guò)斐波那契(Fibonacci)散列嗎?你實(shí)現(xiàn)過(guò)梅森旋轉(zhuǎn)算法嗎?怎么 沒(méi)聽(tīng)過(guò)這些寫(xiě)不了代碼嗎!不會(huì)的,即使沒(méi)聽(tīng)過(guò)你一樣可以寫(xiě)的了代碼,比如你實(shí)現(xiàn)的數(shù)據(jù)庫(kù)路由數(shù)據(jù)總是落在1庫(kù)1表它不散列分布、你實(shí)現(xiàn)的抽獎(jiǎng)系統(tǒng)總是把運(yùn)營(yíng)配置的最大紅包發(fā)出去提高了運(yùn)營(yíng)成本、你開(kāi)發(fā)的秒殺系統(tǒng)總是在開(kāi)始后的1秒就掛了貨品根本給不出去。

除了一部分僅把編碼當(dāng)成搬磚應(yīng)付工作外的程序員,還有一部分總是在追求極致的碼農(nóng)。寫(xiě)代碼還能賺錢(qián),真開(kāi)心! 這樣的碼農(nóng)總是會(huì)考慮??還有沒(méi)有更好的實(shí)現(xiàn)邏輯能讓代碼不僅是能用,還要好用呢?其實(shí)這一點(diǎn)的追求到完成,需要大量擴(kuò)展性學(xué)習(xí)和深度挖掘,這樣你設(shè)計(jì)出來(lái)的系統(tǒng)才更你考慮的更加全面,也能應(yīng)對(duì)各種復(fù)雜的場(chǎng)景。

二、目標(biāo)

在目前 IOC、AOP 兩大核心功能模塊的支撐下,完全可以管理 Bean 對(duì)象的注冊(cè)和獲取,不過(guò)這樣的使用方式總感覺(jué)像是刀耕火種有點(diǎn)難用。因此在上一章節(jié)我們解決需要手動(dòng)配置 Bean 對(duì)象到 spring.xml 文件中,改為可以自動(dòng)掃描帶有注解 @Component 的對(duì)象完成自動(dòng)裝配和注冊(cè)到 Spring 容器的操作。

那么在自動(dòng)掃描包注冊(cè) Bean 對(duì)象之后,就需要把原來(lái)在配置文件中通過(guò) property name="token" 配置屬性和Bean的操作,也改為可以自動(dòng)注入。這就像我們使用 Spring 框架中 @Autowired、@Value 注解一樣,完成我們對(duì)屬性和對(duì)象的注入操作。

三、方案

其實(shí)從我們?cè)谕瓿?Bean 對(duì)象的基礎(chǔ)功能后,后續(xù)陸續(xù)添加的功能都是圍繞著 Bean 的生命周期進(jìn)行的,比如修改 Bean 的定義 BeanFactoryPostProcessor,處理 Bean 的屬性要用到 BeanPostProcessor,完成個(gè)性的屬性操作則專門(mén)繼承 BeanPostProcessor 提供新的接口,因?yàn)檫@樣才能通過(guò) instanceof 判斷出具有標(biāo)記性的接口。所以關(guān)于 Bean 等等的操作,以及監(jiān)聽(tīng) Aware、獲取 BeanFactory,都需要在 Bean 的生命周期中完成。那么我們?cè)谠O(shè)計(jì)屬性和 Bean 對(duì)象的注入時(shí)候,也會(huì)用到 BeanPostProcessor 來(lái)完成在設(shè)置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值。整體設(shè)計(jì)結(jié)構(gòu)如下圖:

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

四、實(shí)現(xiàn)

1. 工程結(jié)構(gòu)

small-spring-step-14
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── aop
    │           │   ├── aspectj
    │           │   │   └── AspectJExpressionPointcut.java
    │           │   │   └── AspectJExpressionPointcutAdvisor.java
    │           │   ├── framework 
    │           │   │   ├── adapter
    │           │   │   │   └── MethodBeforeAdviceInterceptor.java
    │           │   │   ├── autoproxy
    │           │   │   │   └── MethodBeforeAdviceInterceptor.java
    │           │   │   ├── AopProxy.java
    │           │   │   ├── Cglib2AopProxy.java
    │           │   │   ├── JdkDynamicAopProxy.java
    │           │   │   ├── ProxyFactory.java
    │           │   │   └── ReflectiveMethodInvocation.java
    │           │   ├── AdvisedSupport.java
    │           │   ├── Advisor.java
    │           │   ├── BeforeAdvice.java
    │           │   ├── ClassFilter.java
    │           │   ├── MethodBeforeAdvice.java
    │           │   ├── MethodMatcher.java
    │           │   ├── Pointcut.java
    │           │   ├── PointcutAdvisor.java
    │           │   └── TargetSource.java
    │           ├── beans
    │           │   ├── factory  
    │           │   │   ├── 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  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── Aware.java
    │           │   │   ├── BeanClassLoaderAware.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── BeanFactoryAware.java
    │           │   │   ├── BeanNameAware.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── DisposableBean.java
    │           │   │   ├── FactoryBean.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   ├── InitializingBean.java
    │           │   │   ├── ListableBeanFactory.java
    │           │   │   └── PropertyPlaceholderConfigurer.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── 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 
    │           │   ├── ApplicationContext.java 
    │           │   ├── ApplicationContextAware.java 
    │           │   ├── ApplicationEvent.java 
    │           │   ├── ApplicationEventPublisher.java 
    │           │   ├── ApplicationListener.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java
    │           │   └── UrlResource.java
    │           ├── stereotype
    │           │   └── Component.java
    │           └── utils
    │               ├── ClassUtils.java
    │               └── StringValueResolver.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── IUserService.java
                │   └── UserService.java
                └── ApiTest.java

工程源碼公眾號(hào)「bugstack蟲(chóng)洞?!?,回復(fù):Spring 專欄,獲取完整源碼

自動(dòng)掃描注入占位符配置和對(duì)象的類(lèi)關(guān)系,如圖 15-2

圖 15-2
  • 在整個(gè)類(lèi)圖中以圍繞實(shí)現(xiàn)接口 InstantiationAwareBeanPostProcessor 的類(lèi) AutowiredAnnotationBeanPostProcessor 作為入口點(diǎn),被 AbstractAutowireCapableBeanFactory創(chuàng)建 Bean 對(duì)象過(guò)程中調(diào)用掃描整個(gè)類(lèi)的屬性配置中含有自定義注解 Value、Autowired、Qualifier,的屬性值。
  • 這里稍有變動(dòng)的是關(guān)于屬性值信息的獲取,在注解配置的屬性字段掃描到信息注入時(shí),包括了占位符從配置文件獲取信息也包括 Bean 對(duì)象,Bean 對(duì)象可以直接獲取,但配置信息需要在 AbstractBeanFactory 中添加新的屬性集合 embeddedValueResolvers,由 PropertyPlaceholderConfigurer#postProcessBeanFactory 進(jìn)行操作填充到屬性集合中。

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

定義解析字符串接口

cn.bugstack.springframework.util.StringValueResolver

public interface StringValueResolver {

    String resolveStringValue(String strVal);

}
  • 接口 StringValueResolver 是一個(gè)解析字符串操作的接口

填充字符串

public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            // 加載屬性文件
            DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
            Resource resource = resourceLoader.getResource(location);
            
            // ... 占位符替換屬性值、設(shè)置屬性值

            // 向容器中添加字符串解析器,供解析@Value注解使用
            StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
            beanFactory.addEmbeddedValueResolver(valueResolver);
            
        } catch (IOException e) {
            throw new BeansException("Could not load properties", e);
        }
    }

    private class PlaceholderResolvingStringValueResolver implements StringValueResolver {

        private final Properties properties;

        public PlaceholderResolvingStringValueResolver(Properties properties) {
            this.properties = properties;
        }

        @Override
        public String resolveStringValue(String strVal) {
            return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
        }

    }

}
  • 在解析屬性配置的類(lèi) PropertyPlaceholderConfigurer 中,最主要的其實(shí)就是這行代碼的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 這是把屬性值寫(xiě)入到了 AbstractBeanFactory 的 embeddedValueResolvers 中。
  • 這里說(shuō)明下,embeddedValueResolvers 是 AbstractBeanFactory 類(lèi)新增加的集合 List<StringValueResolver> embeddedValueResolvers String resolvers to apply e.g. to annotation attribute values

3. 自定義屬性注入注解

自定義注解,Autowired、Qualifier、Value

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowired {
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {

    String value() default "";

}  

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {

    /**
     * The actual value expression: e.g. "#{systemProperties.myProp}".
     */

    String value();

}
  • 3個(gè)注解在我們?nèi)粘J褂?Spring 也是非常常見(jiàn)的,注入對(duì)象、注入屬性,而 Qualifier 一般與 Autowired 配合使用。

4. 掃描自定義注解

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

public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessorBeanFactoryAware {

    private ConfigurableListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        // 1. 處理注解 @Value
        Class<?> clazz = bean.getClass();
        clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;

        Field[] declaredFields = clazz.getDeclaredFields();

        for (Field field : declaredFields) {
            Value valueAnnotation = field.getAnnotation(Value.class);
            if (null != valueAnnotation) {
                String value = valueAnnotation.value();
                value = beanFactory.resolveEmbeddedValue(value);
                BeanUtil.setFieldValue(bean, field.getName(), value);
            }
        }

        // 2. 處理注解 @Autowired
        for (Field field : declaredFields) {
            Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
            if (null != autowiredAnnotation) {
                Class<?> fieldType = field.getType();
                String dependentBeanName = null;
                Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);
                Object dependentBean = null;
                if (null != qualifierAnnotation) {
                    dependentBeanName = qualifierAnnotation.value();
                    dependentBean = beanFactory.getBean(dependentBeanName, fieldType);
                } else {
                    dependentBean = beanFactory.getBean(fieldType);
                }
                BeanUtil.setFieldValue(bean, field.getName(), dependentBean);
            }
        }

        return pvs;
    }

}
  • AutowiredAnnotationBeanPostProcessor 是實(shí)現(xiàn)接口 InstantiationAwareBeanPostProcessor 的一個(gè)用于在 Bean 對(duì)象實(shí)例化完成后,設(shè)置屬性操作前的處理屬性信息的類(lèi)和操作方法。只有實(shí)現(xiàn)了 BeanPostProcessor 接口才有機(jī)會(huì)在 Bean 的生命周期中處理初始化信息
  • 核心方法 postProcessPropertyValues,主要用于處理類(lèi)含有 @Value、@Autowired 注解的屬性,進(jìn)行屬性信息的提取和設(shè)置。
  • 這里需要注意一點(diǎn)因?yàn)槲覀冊(cè)?AbstractAutowireCapableBeanFactory 類(lèi)中使用的是 CglibSubclassingInstantiationStrategy 進(jìn)行類(lèi)的創(chuàng)建,所以在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 中需要判斷是否為 CGlib 創(chuàng)建對(duì)象,否則是不能正確拿到類(lèi)信息的。ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;

5. 在Bean的生命周期中調(diào)用屬性注入

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

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            // 判斷是否返回代理 Bean 對(duì)象
            bean = resolveBeforeInstantiation(beanName, beanDefinition);
            if (null != bean) {
                return bean;
            }
            // 實(shí)例化 Bean
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 在設(shè)置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值
            applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
            // 給 Bean 填充屬性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注冊(cè)實(shí)現(xiàn)了 DisposableBean 接口的 Bean 對(duì)象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        // 判斷 SCOPE_SINGLETON、SCOPE_PROTOTYPE
        if (beanDefinition.isSingleton()) {
            registerSingleton(beanName, bean);
        }
        return bean;
    }

    /**
     * 在設(shè)置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值
     *
     * @param beanName
     * @param bean
     * @param beanDefinition
     */

    protected void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor){
                PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);
                if (null != pvs) {
                    for (PropertyValue propertyValue : pvs.getPropertyValues()) {
                        beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
                    }
                }
            }
        }
    }  

    // ...
}
  • AbstractAutowireCapableBeanFactory#createBean 方法中有這一條新增加的方法調(diào)用,就是在設(shè)置 Bean 屬性之前,允許 BeanPostProcessor 修改屬性值 的操作 applyBeanPostProcessorsBeforeApplyingPropertyValues
  • 那么這個(gè) applyBeanPostProcessorsBeforeApplyingPropertyValues 方法中,首先就是獲取已經(jīng)注入的 BeanPostProcessor 集合并從中篩選出繼承接口 InstantiationAwareBeanPostProcessor 的實(shí)現(xiàn)類(lèi)。
  • 最后就是調(diào)用相應(yīng)的 postProcessPropertyValues 方法以及循環(huán)設(shè)置屬性值信息,beanDefinition.getPropertyValues().addPropertyValue(propertyValue);

五、測(cè)試

1. 事先準(zhǔn)備

配置 Dao

@Component
public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    static {
        hashMap.put("10001""小傅哥,北京,亦莊");
        hashMap.put("10002""八杯水,上海,尖沙咀");
        hashMap.put("10003""阿毛,香港,銅鑼灣");
    }

    public String queryUserName(String uId) {
        return hashMap.get(uId);
    }

}
  • 給類(lèi)配置上一個(gè)自動(dòng)掃描注冊(cè) Bean 對(duì)象的注解 @Component,接下來(lái)會(huì)把這個(gè)類(lèi)注入到 UserService 中。

注解注入到 UserService

@Component("userService")
public class UserService implements IUserService {

    @Value("${token}")
    private String token;

    @Autowired
    private UserDao userDao;

    public String queryUserInfo() {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return userDao.queryUserName("10001") + "," + token;
    }    

    // ...
}
  • 這里包括了兩種類(lèi)型的注入,一個(gè)是占位符注入屬性信息 @Value("${token}"),另外一個(gè)是注入對(duì)象信息 @Autowired

2. 屬性配置文件

token.properties

token=RejDlI78hu223Opo983Ds

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans"
       xmlns:xsi="http://www./2001/XMLSchema-instance"
       xmlns:context="http://www./schema/context"
       xsi:schemaLocation="http://www./schema/beans
          http://www./schema/beans/spring-beans.xsd
   http://www./schema/context"
>


    <bean class="cn.bugstack.springframework.beans.factory.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:token.properties"/>
    </bean>

    <context:component-scan base-package="cn.bugstack.springframework.test.bean"/>

</beans>
  • 在 spring.xml 中配置了掃描屬性信息和自動(dòng)掃描包路徑范圍。

3. 單元測(cè)試

@Test
public void test_scan() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("測(cè)試結(jié)果:" + userService.queryUserInfo());
}
  • 單元測(cè)試時(shí)候就可以完整的測(cè)試一個(gè)類(lèi)注入到 Spring 容器,同時(shí)這個(gè)屬性信息也可以被自動(dòng)掃描填充上。

測(cè)試結(jié)果

測(cè)試結(jié)果:小傅哥,北京,亦莊,RejDlI78hu223Opo983Ds

Process finished with exit code 0
  • 從測(cè)試結(jié)果可以看到現(xiàn)在我們的使用方式已經(jīng)通過(guò)了,有自動(dòng)掃描類(lèi),有注解注入屬性。這與使用 Spring 框架越來(lái)越像了。

六、總結(jié)

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

七、系列推薦

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多