更优雅的静态属性注入

在spring中我们可以用@value注解将配置文件中的值注入到对象属性上。同样,在springboot中我们可以在类上使用@ConfigurationProperties注解完成同样的功能。

但对于类变量,即用static修饰的变量也想注入时,@value需要写在set方法上,而@ConfigurationProperties无法对静态属性进行注入。这就不得不为每个属性都加入一个set方法,十分枯燥,繁琐。

闲来无事,想对@ConfigurationProperties注解进行增强,让其可以为静态属性赋值,但又不失简便。

这里我主要是写了两个类,一个是注解类@AutowiredStaticProperty,用它代替@ConfigurationProperties对属性赋值,用法和@ConfigurationProperties一样。。另一个是AutowiredStaticPropertyPostProcessor,作用是在容器启动时解析@AutowiredStaticProperty注解,并为对象赋值。

用法上,只需要将两个类考到项目中,在需要注入到类上加上@AutowiredStaticProperty即可。下面是代码

@AutowiredStaticProperty

package com.zhen.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ConfigurationProperties
@Component
public @interface AutowiredStaticProperty {

@AliasFor(annotation = ConfigurationProperties.class)
String prefix() default "";
}

AutowiredStaticPropertyPostProcessor

/**
*
*/
package com.zhen.util;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
* 自动注入静态属性后置处理器
* 对注解了 @AutowiredStaticProperty 的类自动装配静态属性
*/
@Component
public class AutowiredStaticPropertyPostProcessor
implements BeanPostProcessor, ApplicationContextAware {

private ApplicationContext applicationContext;

/**
* 在bean的初始化方法(afterPropertiesSet,init-method)之前调用。不影响后续spring对bean属性赋值操作
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// 未添加注解的默认spring处理
boolean annotationPresent = bean.getClass()
.isAnnotationPresent(AutowiredStaticProperty.class);
if (!annotationPresent) {
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

// 获取类型转换器 转换类型 (无法获取类型转换器时由spring自己处理)
ConfigurableListableBeanFactory configurableListableBeanFactory = getConfigurableListableBeanFactory();
if (configurableListableBeanFactory == null) {
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

Environment environment = applicationContext.getEnvironment();
TypeConverter typeConverter = configurableListableBeanFactory.getTypeConverter();

AutowiredStaticProperty autowiredStaticPropertyAnnotation = bean.getClass()
.getAnnotation(AutowiredStaticProperty.class);
String prefix = autowiredStaticPropertyAnnotation.prefix();

// 赋值
Field[] declaredFields = bean.getClass().getDeclaredFields();
for (Field field : declaredFields) {
int modifiers = field.getModifiers();

// 非静态变量由系统赋值
if (!Modifier.isStatic(modifiers)) {
continue;
}
if (Modifier.isPrivate(modifiers)) {
field.setAccessible(true);
}

String propertyName = field.getName();
String key = prefix == null ? propertyName : prefix.concat(".").concat(propertyName);
String value = environment.getProperty(key);
Class<?> type = field.getType();
Object valueToUse = typeConverter.convertIfNecessary(value, type);
try {
field.set(bean, valueToUse);
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return bean;
}

/**
* 获取bean工厂
*
* @return
*/
private ConfigurableListableBeanFactory getConfigurableListableBeanFactory() {
if (applicationContext instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
}
return null;
}

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

测试类:

/**
*
*/
package com.zhen.model;

import java.util.List;
import java.util.Map;

import com.zhen.util.AutowiredStaticProperty;

import lombok.Data;


@AutowiredStaticProperty(prefix = "houzhen")
public class TestModel {
public static Long name;

private String age;

private List<String> list;

private Map<String, String> maps;
}

扩展是基于springboot的,只测试了几种简单类型,对于复杂类型如果需要可以自行扩展。欢迎指正

posted @   灵魂守卫  阅读(466)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示