实践课:实现一个简易版的springboot中的@EnableConfigurationProperties自动注入组件

1.如何在spring中,为bean初始化属性???
答:spring中的BeanPostProcessor能够完成对bean的初始化加工.
2.我应该从哪里获取到我在配置文件中配置的属性呢?
答:可以在Environment对象的属性中获取,我们可以通过ApplicationContextAware让spring给我注入context,进一步获取该对象.
现在我们已经可以完成对一个bean进行属性注入了,来看一下实现吧:

public class PropBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, PriorityOrdered {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        UserProperties annotation = bean.getClass().getAnnotation(UserProperties.class);//等同于@ConfigurationProperties注解
        if(annotation != null) {
            String prefix = annotation.prefix();
                Environment environment = this.applicationContext.getEnvironment();
                if (environment instanceof ConfigurableEnvironment) {
                    MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
                    for (PropertySource<?> propertySource : propertySources) {
                        Object property = propertySource.getProperty(prefix);
                        if (property != null) {
                            System.out.println(property);//简单打印,可自行解析,我这里直使用值,简化不必要操作
                            try {
                                Class<?> clazz = bean.getClass();//通过反射注入值
                                Field name = clazz.getDeclaredField("name");
                                name.setAccessible(true);
                                name.set(bean,"my_name");
                                Field age = clazz.getDeclaredField("age");
                                age.setAccessible(true);
                                age.set(bean,18);
                            } catch (NoSuchFieldException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
        }

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 2;
    }
}

3.我自定义的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(UserImportSelector.class)//我们通过import导入了一个ImpoetSelector的实现,用于注入启用功能所需要的功能类
public @interface EnableProp {
    Class value();
}

这样使用

@SpringBootApplication
@EnableProp(User.class)//启用User的属性注入
public class Demo2Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);
        User bean = context.getBean(User.class);
        System.out.println(bean);
    }

}

启用功能苏需要的功能类:

public class UserImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{UserImportBeanDefinitionRegistrar.class.getName(),//实现对User的定义注入
        PropBeanPostProcessor.class.getName()};//实现对bean属性的注入
    }
}

看一下如何对user类注入spring:

public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
        for (String annotationType : annotationTypes) {
            if(annotationType.equals(EnableProp.class.getName())){
                MultiValueMap<String, Object> allAnnotationAttributes = importingClassMetadata.getAllAnnotationAttributes(annotationType);
                List<Object> value = allAnnotationAttributes.get("value");
                Class beanClass = (Class) value.get(0);
                GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
                genericBeanDefinition.setBeanClass(beanClass);
                registry.registerBeanDefinition(beanClass.getName(),genericBeanDefinition);
            }
        }
    }
}

此处,@EnableProp加在那里,importingClassMetadata就是那个类的注解元数据,此处是Demo2Application的注解;在上文中我们获取到EnableProp注解,检查他的value类型,并初始化一个bean定义,注入到文件中

4.再看一下配置文件吧

user:
  name:my_name
  age:18

5.再来看一下运行结果:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.5.RELEASE)

2019-06-10 17:52:21.511  INFO 17032 --- [  restartedMain] com.example.demo2.Demo2Application       : Starting Demo2Application on Think-PC with PID 17032 (E:\idea\damo\demo2\out\production\classes started by Think in E:\idea\damo\demo2)
2019-06-10 17:52:21.516  INFO 17032 --- [  restartedMain] com.example.demo2.Demo2Application       : No active profile set, falling back to default profiles: default
2019-06-10 17:52:21.600  INFO 17032 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
name:my_name age:18
name:my_name age:18
2019-06-10 17:52:22.451  INFO 17032 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2019-06-10 17:52:22.485  INFO 17032 --- [  restartedMain] com.example.demo2.Demo2Application       : Started Demo2Application in 1.719 seconds (JVM running for 6.084)
User{name='my_name', age=18}

猜你喜欢

转载自blog.csdn.net/strive____/article/details/91388778