以静态方法访问spring bean

Ros*_*osh 35 java spring

我有一个带有静态方法的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变量).

  • 如果您使用方面,这就是一个问题。Spring 没有机会将您的实例包装在拦截器中。 (3认同)

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)

  • 乍一看这是个好主意,但是 `this.ac = ac;` 是不对的。应该是`TestUtils.ac = ac; `。或者您可以为“private static ApplicationContext utilAc”定义不同的名称,然后为“utilAc = ac;”。 (2认同)

Fra*_*man 11

静态方法的结果应仅取决于传递给方法的参数,因此不需要调用任何bean.

如果需要调用另一个bean,那么您的方法应该是独立bean的成员方法.

其他答案为您提供工作解决方案,但事实上它可以做到并不意味着它应该完成.

  • “静态方法的结果应该只取决于传递给方法的参数”,不错的镜头! (2认同)

JRi*_*dsz 9

这对我有用。

使用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)

以静态方法访问Spring bean

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)

高温超导


Tom*_*ols 7

通用解决方案

您可以创建一个允许从静态上下文访问任何 Bean 的类。此处的大多数其他答案仅显示如何静态访问单个类。

添加下面代码中的代理,以防有人在自动装配 ApplicationContext 之前调用 getBean() 方法(因为这会导致空指针)。此处发布的其他解决方案均未处理该空指针。

我博客的详细信息:https : //tomcools.be/post/apr-2020-static-spring-bean/

用法

UserRepository userRepo = StaticContextAccessor.getBean(UserRespository.class)
Run Code Online (Sandbox Code Playgroud)

StaticContextAccessor 的完整代码:

@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)


yng*_*ger 6

类似于@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)


Bij*_*men 0

您概述的方法是我所看到的用于将 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)

更多详细信息请参见此处此处