【问题标题】:Not able to access variables of @ConfigurationProperties class using reflection?无法使用反射访问@ConfigurationProperties 类的变量?
【发布时间】:2019-12-04 04:44:13
【问题描述】:

以下是spring boot项目的YML文件中的条目。

application:
  applicationPath: "/demo"
  defaultFilePath: ${application.applicationPath}childDemo/import_files/
  actDocsPath: ${application.applicationPath}childDemo2/act_docs/
  bgJobsLogs: ${application.applicationPath}childDemo3/bgjobs_logs/

在这些位置,我在我的项目中保存了一些文档。

要求是......在项目启动时我想创建所有这些目录结构,因此我创建了一个类......

package com.sbill.app.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
public class ApplicationProperties {

    @Value("${application.applicationPath}")
    public String applicationPath;

    @Value("${application.defaultFilePath}")
    public String defaultFilePath;

    @Value("${application.actDocsPath}")
    public String actDocsPath;

    @Value("${application.bgJobsLogs}")
    public String bgJobsLogs;

    public String getDefaultFilePath() {
        return defaultFilePath;
    }

    public void setDefaultFilePath(String defaultFilePath) {
        this.defaultFilePath = defaultFilePath;
    }

    public String getActDocsPath() {
        return actDocsPath;
    }

    public void setActDocsPath(String actDocsPath) {
        this.actDocsPath = actDocsPath;
    }

    public String getBgJobsLogs() {
        return bgJobsLogs;
    }

    public String getApplicationPath() {
        return applicationPath;
    }

    public void setApplicationPath(String applicationPath) {
        this.applicationPath = applicationPath;
    }
}

我创建了一个类,我用CommandLineRunner 实现了在启动时调用

package com.sbill.app.config;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.sbill.app.domain.User;
import com.sbill.app.repository.UserRepository;
import com.sbill.app.service.util.FieldReqValidationUtil;

@Component
public class SbillStartupRunner implements CommandLineRunner {

    @Autowired
    ApplicationProperties applicationProperties;

    @Override
    public void run(String... args) throws Exception {

        System.out.println(applicationProperties.getDefaultFilePath());  
        System.out.println(applicationProperties.getApplicationPath()); 

        Field[] fields = applicationProperties.getClass().getDeclaredFields();
        for(Field f : fields){
            f.setAccessible(true);
           Class t = f.getType();
           Object v = f.get(applicationProperties);

           File applicationpath = new File(v.toString());
            if (!applicationpath.exists()) {
                if (applicationpath.mkdirs()) {
                    System.out.println("Directory is created!");
                } else {
                    System.out.println("Failed to create directory!");
                }
            }
           System.out.println(applicationpath.getAbsolutePath());


        }
    }
}

我的问题是:- 使用 setter/getter 路径正在打印,但使用反射我无法访问字段..

【问题讨论】:

  • 你为什么有@Value
  • @chrylis-onstrike- 是的,值注释不应该存在......实际上这个类已经创建,只是我的任务是创建目录,但我不认为这个问题与值注释有关。 .. 使用 setter/getter 我可以访问值
  • 属性(使用 getter/setter)不是Field。由于Field private,您无法访问它。接下来,您可能会得到一个代理类而不是实际类。但是为什么要使用反射呢?只是使用吸气剂而不是用反射来尝试这个?有什么收获?
  • @M.Deinum 我需要遍历 ApplicationProperties.java 的所有字段,这就是为什么使用反射,而不使用 getter 的反射我该怎么做?
  • 为什么?所有领域都有吸气剂......所以你为什么需要反射,没有吸气剂/设置器@ConfigurationProperties将不起作用。看起来您正在尝试使用诸如反射之类的复杂事物来制作通用解决方案。如果你真的想使用反射(我建议不要这样做)是使用 Spring ReflectionUtils.doWithFields 方法并使用 lambda 表达式实现 FieldFilterFieldCallback

标签: java spring-boot reflection


【解决方案1】:

getClass() 将返回对象的实际类,例如它可能是一个子类,getDeclaredFields() 只返回在该类中声明的字段。要获取ApplicationProperties 中声明的字段,只需使用ApplicationProperties.class.getDeclaredFields()

请注意,您可以通过使用AccessibleObject.setAccessible 来改进代码,一次性设置所有对象的可访问性状态,以避免重复进行可能代价高昂的安全检查。此外,这里强烈建议使用NIO,因为它允许在创建目录失败时进行诊断,而不是返回无用的boolean 值。

Field[] fields = ApplicationProperties.class.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for(Field f : fields){
    Object v = f.get(applicationProperties);
    Path p = Files.createDirectories(Paths.get(v.toString()));
    System.out.println(p.toAbsolutePath());
}

【讨论】:

    猜你喜欢
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2021-10-01
    • 1970-01-01
    • 2018-10-17
    • 2015-12-07
    • 1970-01-01
    相关资源
    最近更新 更多