Можете ли вы использовать @Autowired со статическими полями?
Есть ли способ использовать @Autowired
со статическими полями. Если нет, есть ли другие способы сделать это?
13 ответов
Короче нет. Вы не можете автоматически связывать или вручную связывать статические поля в Spring. Вы должны написать свою собственную логику, чтобы сделать это.
@Component("NewClass")
public class NewClass{
private static SomeThing someThing;
@Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
@Autowired
может использоваться с сеттерами, чтобы вы могли иметь сеттер, модифицирующий статическое поле.
Только одно последнее предложение... НЕ
Инициируйте свой автопроводной компонент в методе @PostConstruct
@Component
public class TestClass {
private static AutowiredTypeComponent component;
@Autowired
private AutowiredTypeComponent autowiredComponent;
@PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Создайте bean-компонент, который вы можете автоматически связать, который будет инициализировать статическую переменную как побочный эффект.
Хотел добавить к ответам, что статическое поле (или константа) автоматического подключения будет игнорироваться, но также не вызовет никаких ошибок:
@Autowired
private static String staticField = "staticValue";
Вы можете достичь этого с помощью нотации XML и MethodInvokingFactoryBean
, Для примера посмотрите здесь.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
Вы должны стремиться использовать пружинный впрыск, где это возможно, так как это рекомендуемый подход, но это не всегда возможно, поскольку я уверен, что вы можете себе представить, что не все можно извлечь из контейнера с пружиной или вы, возможно, имеете дело с устаревшими системами.
Тестирование заметок также может быть более сложным при таком подходе.
Вы можете использовать ApplicationContextAware
@Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
тогда
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Я использую частный статический внутренний компонент: FieldSetter для ввода статического поля: MyBean, наконец, SelfDestroyBean поможет мне удалить избыточный компонент FiledSetter .
public final class MyClass {
private static MyBean myBean;
@Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
@Autowired
private ApplicationContext context;
@PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
Отказ от ответственности Это ни в коем случае не является стандартом, и вполне может быть лучший весенний способ сделать это. Ни один из приведенных выше ответов не решает проблемы подключения общедоступного статического поля.
Я хотел добиться трех вещей.
- Используйте пружину для "Autowire" (я использую @Value)
- Выставить общедоступное статическое значение
- Предотвратить изменение
Мой объект выглядит так
private static String BRANCH = "testBranch";
@Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
Мы уже отметили 1 и 2, как предотвратить вызовы сеттера, поскольку мы не можем его скрыть.
@Component
@Aspect
public class FinalAutowiredHelper {
@Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
@Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
@Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
Этот аспект закроет все методы, начинающиеся с final, и выдаст ошибку при их вызове.
Я не думаю, что это особенно полезно, но если вам нравится хранить горошек и морковь отдельно, это один из способов сделать это безопасно.
Важно Spring не вызывает ваши аспекты при вызове функции. Сделал это проще, но я разработал логику, прежде чем понять это.
Как правило, установка статического поля по экземпляру объекта - плохая практика.
чтобы избежать дополнительных проблем, вы можете добавить
synchronized
определение, и установить его, только если приватный статический логгер;
@Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Решение 1. Использование конструктора
@Autowired
Для статического поля
@Component
public class MyClass {
private static MyService service;
@Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Решение 2. Использование
@PostConstruct
чтобы установить значение для статического поля
@Component
public class MyClass {
private static MyService service;
@Autowired
private MyService srv;
@PostConstruct
public void init() {
this.service= srv;
}
}