首页 > 解决方案 > 使用反射加载随机类并将其注册为springboot中的组件

问题描述

我在应用程序启动后通过反射加载的随机包中有一个随机类,有没有办法将它注册为springboot下的组件并为该类提供诸如等的@Autowired注释@Value

当它在启动时位于同一个包中时它可以工作,但如果在运行时通过另一个 jar 引入它(相同的包或不同的包)它不起作用。

以下是即使在同一个罐子中也不起作用的示例。我无法更改应用程序的配置 - 它会破坏“随机包/随机类”目标。

Spring boot 应用程序包中的代码

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();
        }
    }
}

测试.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 指向那个动态类,但没有运气。

标签: javaspringspring-boot

解决方案


要简单地将字段注入 POJO,就好像它是 Spring 管理的 bean,您可以使用如下内容:

@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


推荐阅读