0 Prefacio
Recientemente, tengo que completar el componente del kit de herramientas del middleware, que implica leer el archivo de configuración de la matriz de objetos y cargarlo como un bean. Debido a la spring 4.3.25.RELEASE
versión utilizada, muchas características relacionadas con Springboot no pueden ser compatibles, por lo que esto se registra. Para facilitar el seguimiento estudiantes que tienen la misma situación para referirse
1. Obtenga el archivo de configuración de la matriz de objetos
Primero, el archivo de configuración de la matriz de objetos es el siguiente:
minio.clients[0].name=xxx
minio.clients[0].endpoint=http://ip1:9000
minio.clients[0].access.key=admin
minio.clients[0].secret.key=asd
minio.clients[0].default.bucket=wu
minio.clients[1].name=yyy
minio.clients[1].endpoint=http://ip2:9000
minio.clients[1].access.key=admin
minio.clients[1].secret.key=asd
minio.clients[1].default.bucket=wu
El formato convertido a yml es el siguiente:
minio:
clients:
- name: xxx
endpoint: http://ip1:9000
access:
key: admin
secret:
key: asd
default:
bucket: wu
- name: yyy
endpoint: http://ip2:9000
access:
key: admin
secret:
key: asd
default:
bucket: wu
Si es un proyecto Springboot, podemos usar uno directamente @ConfigurationProperties(prefix="minio.clients")
y luego configurar una clase de entidad para lograrlo. Sin embargo, debido a que aquí nos encontramos con una versión anterior del proyecto Spring, esta anotación no es compatible. Así que intenta implementarlo de otras maneras.
En primer lugar, el formulario @Value@Value
puede ayudarnos a leer elementos de configuración, pero solo se puede usar para elementos de configuración de tipos básicos o matrices de tipos básicos. Para archivos de configuración de matrices de nuestros elementos de objetos, no es compatible. En primavera , Excepto por este método, también Environment
se puede implementar directamente mediante objetos operativos.
Formulario de entorno
Puede ver que podemos obtener los elementos de configuración que queremos a través del método Environment.getProperty, por lo que este método es obviamente factible.
Al mismo tiempo, cuando el entorno lee el elemento de configuración, necesita especificar el archivo de configuración, por lo que debe declararlo con ayuda. Al mismo tiempo, @PropertySource
debido a que se trata de un conjunto de herramientas, significa que es posible que el archivo de configuración no esté disponible. . Si no, no hay necesidad de inicializar el bean. Si hay un archivo de configuración correspondiente, el bean se inicializará automáticamente. , esto es lo que queremos lograr
Haga clic en @PropertySource
la anotación y podremos ver un ignoreResourceNotFound
atributo. El nombre del atributo nos ha dicho su función. Al establecer su valor en verdadero, podemos leer el elemento de configuración cuando el archivo de configuración existe, y no se informará ningún error cuando no exista. .
El ejemplo completo es el siguiente:
@Configuration
@PropertySource(value = {
"classpath:applicaiton.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {
@Resource
private Environment environment;
...
}
¿Cómo obtener dinámicamente elementos de configuración de matriz de longitud no fija?
En segundo lugar, debemos observar los requisitos aquí, porque en realidad se pueden obtener múltiples configuraciones de minio.clients, aquí solo enumeramos dos, porque lo que se implementa es un conjunto de herramientas, y se pueden configurar muchas más en el futuro, por lo que la longitud es inesperado..
Luego necesitamos obtener la longitud de esta matriz. Si es Springboot, podemos List<配置实体类> list
obtener la longitud de la colección directamente a través de la colección definida. Sin embargo, aquí en primavera, no podemos obtener directamente la longitud de la matriz, por lo que para Para satisfacer la demanda, solo podemos tomar una forma estúpida de definir directamente una configuración de longitud minio.clients.length=2
. Si hay una forma mejor en el futuro, puede dejar un mensaje para discutir.
for
Luego podemos obtener los elementos de configuración repitiendo el código.
2. Cómo registrar frijoles en el contenedor Spring
Al mismo tiempo, debido a que mis necesidades aquí también necesitan inicializar las correspondientes MinioClient
, entonces los beans creados deben registrarse en el contenedor de primavera. Además de @Bean
las anotaciones, el registro en el contenedor es el siguiente:
@Configuration
public class MinioConfiguration {
/**
* 对象存储服务的url
*/
@Value("${minio.endpoint:null}")
private String endpoint;
/**
* 用户ID
*/
@Value("${minio.access.key:null}")
private String accessKey;
/**
* 账户密码
*/
@Value("${minio.secret.key:null}")
private String secretKey;
/**
* 默认桶名
*/
@Value("${minio.default.bucket:null}")
private String defaultBucketName = "wu";
@Bean
public MinioClient minioClient() throws Exception{
MinioProperties minioProperties = new MinioProperties(endpoint, accessKey, secretKey, defaultBucketName);
if(StringUtils.isEmpty(minioProperties.getEndpoint())){
return null;
}
return new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
}
}
También puedes BeanFactory
registrarte a través de, como se muestra a continuación.
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("beanName", new MinioClient());
Puede ver que debido a que necesitamos leer elementos de configuración en un bucle, la cantidad de beans es variable, por lo que el @Bean
formulario fijo definitivamente no funcionará. Solo podemos registrarnos a través de beanFactory.
Tiempo de registro de beans
Sabemos que los beans deben registrarse cuando se inicia el proyecto, pero hay muchas etapas durante el inicio. Por ejemplo, los beans que inicializamos en realidad deben pasarse @Autowired
o @Resource
referenciarse, por lo que definitivamente debemos registrar estos dos. Regístrelo antes de hacer referencia. de lo contrario obtendrá un error que indica que no se puede encontrar el bean.
Hay varias formas de ejecutar el método cuando el proyecto comienza en primavera. El método más utilizado @PostConstruct
es el método anotado, pero el orden de ejecución de este método es @Bean
>> , por lo que definitivamente no funcionará.@Autowired
@PostConstruct
Así que intentamos otra forma BeanFactoryPostProcessor
de lograrlo declarando la interfaz postProcessBeanFactory方法
, lo que puede realizar algunas modificaciones personalizadas en beanFactory y podemos registrar los beans en estas modificaciones.
Al mismo tiempo, debido a que necesitamos obtener elementos de configuración a través del Medio Ambiente, también debemos declarar y registrar el Medio Ambiente EnvironmentAware
a través de métodos. Por supuesto, también puede optar por obtenerlos a través desetEnvironment
beanFactory.getBean("environment")
El código de muestra completo es el siguiente:
public class MinioMultiBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware {
private final static Logger log = LogManager.getLogger(MinioMultiBeanFactoryPostProcessor.class);
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if(!environment.containsProperty("minio.clients.length")){
log.error("未识别到minio.clients.length,取消配置多个minioClient");
return;
}
Integer length = 0;
try {
length = environment.getProperty("minio.clients.length", Integer.class);
}catch (Exception e){
throw new RuntimeException("minioClient初始化失败,minio.clients.length数据类型为Int");
}
for (int i = 0; length != null && i < length; i++) {
String name = environment.getProperty("minio.clients["+i+"].name");
String endpoint = environment.getProperty("minio.clients["+i+"].endpoint");
String access = environment.getProperty("minio.clients["+i+"].access.key");
String secret = environment.getProperty("minio.clients["+i+"].secret.key");
String bucket = environment.getProperty("minio.clients["+i+"].default.bucket");
try{
// 自定义对象
MinioProperties minioProperties = new MinioProperties(endpoint, access, secret, bucket);
// 创建client
MinioClient minioClient = new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
beanFactory.registerSingleton(name+"MinioClient", minioClient);
}catch (Exception e){
log.error(String.format("minioClient初始化失败:%s", ExceptionUtil.getErrorInfo(e)));
}
}
}
}
Luego necesitamos combinar la secuencia @Bean
> mencionada anteriormente @Autowired
, porque lo que personalizamos BeanFactoryPostProcessor
ahora es solo una clase simple, y también necesitamos declararla como un bean para lograr el propósito de modificar BeanFactory, por lo que @Bean
la inicializamos a través de
@Configuration
@PropertySource(value = {
"classpath:application.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {
@Bean
public MinioMultiBeanFactoryPostProcessor minioMultiBeanFactoryPostProcessor(){
return new MinioMultiBeanFactoryPostProcessor();
}
}
En este punto, hemos completado la operación de inicialización de beans dinámicos. El método anterior es aplicable a cualquier proyecto de Spring y es más adecuado para proyectos que necesitan construir paquetes intermedios. Puede consultarlo de forma selectiva.