Загрузка случайного класса с использованием отражения и регистрация его в качестве компонента в Springboot - PullRequest
0 голосов
/ 15 февраля 2020

У меня есть случайный класс в случайном пакете, который загружается через отражение после запуска приложения, есть ли способ зарегистрировать его как компонент под Springboot и иметь аннотации, такие как @Autowired и @Value et c работа для этого класса.

Он работает, когда он находится в одном и том же пакете во время запуска, но если ввести его еще раз во время выполнения (тот же пакет или нет), он не работает.

Ниже приведены примеры, которые не работать, даже если он находится в одной банке. Я не могу изменить конфигурацию приложения - оно победит цель «случайный пакет / случайный класс».

Код в пакете загрузочного приложения Spring

package sample.app
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        // Code that starts app
        //
        //
        try {
            Thread.sleep(7000);
            Class test = Class.forName("test.Test", true, Application.class.getClassLoader());
            System.out.println(test.getMethod("getName").invoke(null));     //NPE
            System.out.println(test.getMethod("getProfiles").invoke(null)); //NPE
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Test. java

package test;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

@DependsOn("blaaaaaaaah")
@ComponentScan
public class Test {

    @DependsOn("blaaaaaaaah")
    public static String getName() {
        return SpringGetter.instance.getApplicationName();
    }

    @DependsOn("blaaaaaaaah")
    public static String[] getProfiles() {
        String[] profiles = SpringGetter.instance.getEnv().getActiveProfiles();
        if (profiles == null || profiles.length == 0) {
            profiles = SpringGetter.instance.getEnv().getDefaultProfiles();
        }
        return profiles;
    }

}

SpringGetter. java

package test;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component("blaaaaaaaah")
public class SpringGetter implements InitializingBean {
    public static SpringGetter instance;

    @Value("${spring.application.name}")
    private  String applicationName;
    @Autowired
    private Environment env;

    public SpringGetter() {
        System.out.println("consASFJEFWEFJWDNFWJVNJSBVJWNCJWBVJNVJNVJSNJSNCSDJVNSVJtruct");
    }

    public String getApplicationName() {
        return applicationName;
    }

    public void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }

    public Environment getEnv() {
        return env;
    }

    public void setEnv(Environment env) {
        this.env = env;
    }

    @PostConstruct
    public void setInstance() {
        instance = this;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        instance = this;
    }
}

РЕДАКТИРОВАТЬ: мне удалось динамически создать класс SpringGetter как часть того же пакета, что и класс Application (класс с @SpringBootApplication) , Я получил Test. java, чтобы указать на этот динамический c класс, но пока не повезло.

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

Если вы используете Spring 5, взгляните на метод registerBean () из GenericApplicationContext. Вы можете найти пример здесь: https://www.baeldung.com/spring-5-functional-beans

Проблема в вашем классе Test также может заключаться в том, что вы не загружаете контекст Spring Boot из основного класса. Для этого вы можете использовать аннотацию SpringBootTest.

0 голосов
/ 15 февраля 2020

Чтобы просто вставить поля в POJO, как если бы это был бин, управляемый Spring, вы можете использовать что-то вроде следующего:

@Component
public class BeanInitializer implements ApplicationContextAware {

  private AutowireCapableBeanFactory beanFactory;

  @Override
  public void setApplicationContext(final ApplicationContext applicationContext) {
      beanFactory = applicationContext.getAutowireCapableBeanFactory();
  }

  public void initializeObject(Object pojo) {
      beanFactory.autowireBean(pojo);
  }
}

Заметьте , однако, что это только вставляет поля, помеченные как @Autowired или @Injected. Он не создает прокси, которые поддерживают стратегии перехвата методов, основанные, например, на @Transactional, @Async, et c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...