java - 使用反射加载随机类并将其注册为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 指向那个动态类,但没有运气。
解决方案
要简单地将字段注入 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
。