我有一个带有静态方法的Util类.在我的Util类中,我想使用spring bean,所以我将它们包含在我的util类中.据我所知,使用spring beans作为静态字段并不是一个好习惯.但有没有办法在静态方法中访问spring bean?
我的例子:
public class TestUtils {
private static TestBean testBean;
public void setTestBean(TestBean testBean) {
TestUtils.testBean = testBean;
}
public static String getBeanDetails() {
return beanName = testBean.getDetails();
}
}
Run Code Online (Sandbox Code Playgroud)
我在很多论坛上都看到这不是最好的做法.有人能告诉我如何处理这种情况吗?
我的配置文件:
<bean id="testUtils" class="com.test.TestUtils">
<property name="testBean" ref="testBean" />
</bean>
Run Code Online (Sandbox Code Playgroud)
nul*_*ter 37
我的方法是为了希望访问实现InitializingBean
或使用的bean @PostConstruct
,并包含对自身的静态引用.
例如:
@Service
public class MyBean implements InitializingBean {
private static MyBean instance;
@Override
public void afterPropertiesSet() throws Exception {
instance = this;
}
public static MyBean get() {
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,静态类中的用法只是:
MyBean myBean = MyBean.get();
Run Code Online (Sandbox Code Playgroud)
这样,不需要XML配置,您不需要将bean作为构造函数参数传递,并且调用者不需要知道或关心bean是否使用Spring连接(即,不需要凌乱)ApplicationContext
变量).
whi*_*ite 13
你也可以实现ApplicationContextAware接口,如下所示:
@Component
public class TestUtils implements ApplicationContextAware {
private static ApplicationContext ac;
public static String getBeanDetails() {
return beanName = ((TestBean) ac.getBean("testBean")).getDetails();
}
@Override
public void setApplicationContext(ApplicationContext ac) {
this.ac = ac;
}
}
Run Code Online (Sandbox Code Playgroud)
Fra*_*man 11
静态方法的结果应仅取决于传递给方法的参数,因此不需要调用任何bean.
如果需要调用另一个bean,那么您的方法应该是独立bean的成员方法.
其他答案为您提供工作解决方案,但事实上它可以做到并不意味着它应该完成.
这对我有用。
使用xml配置定义您的bean(老式):
<bean id="someBean1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${db.driver}</value></property>
<property name="url"><value>${db.url}</value></property>
<property name="username"><value>${db.username_seg}</value></property>
<property name="password"><value>${db.password_seg}</value></property>
</bean>
Run Code Online (Sandbox Code Playgroud)
或者用Java而不是xml定义它(new school)
@Bean(name = "someBean2")
public MySpringComponent loadSomeSpringComponent() {
MySpringComponent bean = new MySpringComponent();
bean.setSomeProperty("1.0.2");
return bean;
}
Run Code Online (Sandbox Code Playgroud)
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
public class TestUtils {
public static void getBeansFromSpringContext() {
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
//for spring boot apps
//ApplicationContext context = SpringApplication.run(Application.class, args)
DataSource datasource = (DataSource)context.getBean("someBean1");
MySpringComponent springBean = (MySpringComponent)context.getBean("someBean2");
}
}
Run Code Online (Sandbox Code Playgroud)
高温超导
您可以创建一个允许从静态上下文访问任何 Bean 的类。此处的大多数其他答案仅显示如何静态访问单个类。
添加下面代码中的代理,以防有人在自动装配 ApplicationContext 之前调用 getBean() 方法(因为这会导致空指针)。此处发布的其他解决方案均未处理该空指针。
我博客的详细信息:https : //tomcools.be/post/apr-2020-static-spring-bean/
UserRepository userRepo = StaticContextAccessor.getBean(UserRespository.class)
Run Code Online (Sandbox Code Playgroud)
@Component
public class StaticContextAccessor {
private static final Map<Class, DynamicInvocationhandler> classHandlers = new HashMap<>();
private static ApplicationContext context;
@Autowired
public StaticContextAccessor(ApplicationContext applicationContext) {
context = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
if (context == null) {
return getProxy(clazz);
}
return context.getBean(clazz);
}
private static <T> T getProxy(Class<T> clazz) {
DynamicInvocationhandler<T> invocationhandler = new DynamicInvocationhandler<>();
classHandlers.put(clazz, invocationhandler);
return (T) Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class[]{clazz},
invocationhandler
);
}
//Use the context to get the actual beans and feed them to the invocationhandlers
@PostConstruct
private void init() {
classHandlers.forEach((clazz, invocationHandler) -> {
Object bean = context.getBean(clazz);
invocationHandler.setActualBean(bean);
});
}
static class DynamicInvocationhandler<T> implements InvocationHandler {
private T actualBean;
public void setActualBean(T actualBean) {
this.actualBean = actualBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (actualBean == null) {
throw new RuntimeException("Not initialized yet! :(");
}
return method.invoke(actualBean, args);
}
}
}
Run Code Online (Sandbox Code Playgroud)
类似于@nullPainter 的响应,但我们做了以下工作。不需要构建后逻辑。它只是在注入期间直接设置静态成员(在@Autowired 方法中)。
@Service
public class MyUtil {
private static MyManager myManager;
@Autowired(required = true)
public void setMyManager(MyManager manager) {
myManager = manager;
}
public static MyManager getMyManager() {
return myManager;
}
}
Run Code Online (Sandbox Code Playgroud)
您概述的方法是我所看到的用于将 Spring bean 注入实用程序类的方法。
<bean id="testUtils" class="com.test.TestUtils">
<property name="testBean" ref="testBean" />
</bean>
Run Code Online (Sandbox Code Playgroud)
另一种选择是:
<bean name="methodInvokingFactoryBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="TestUtils.setInstance"/>
<property name="arguments">
<list>
<ref bean="testBean"/>
</list>
</property>
</bean>
Run Code Online (Sandbox Code Playgroud)
和:
public class TestUtils {
private static testBean;
public static void setInstance(TestBean anInstance) {
testBean = anInstance;
}
public static String getBeanDetails() {
return testBean.getDetails();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
51824 次 |
最近记录: |