Java 用静态方法访问springbean

Java 用静态方法访问springbean,java,spring,Java,Spring,我有一个带有静态方法的Util类。在我的Util类中,我想使用Springbean,所以我将它们包括在我的Util类中。 据我所知,将SpringBean用作静态字段不是一个好的实践。 但是有没有任何方法可以通过静态方法访问Springbean 我的例子是: public class TestUtils { private static TestBean testBean; public void setTestBean(TestBean testBean) { Tes

我有一个带有静态方法的Util类。在我的Util类中,我想使用Springbean,所以我将它们包括在我的Util类中。 据我所知,将SpringBean用作静态字段不是一个好的实践。 但是有没有任何方法可以通过静态方法访问Springbean

我的例子是:

public class TestUtils {

   private static TestBean testBean;

   public void setTestBean(TestBean testBean) {
     TestUtils.testBean = testBean;
   }

  public static String getBeanDetails() {
    return beanName = testBean.getDetails();
  }
}
我在许多论坛上看到,这不是一种最佳做法。有人能告诉我如何处理这种情况吗

我的配置文件:

<bean id="testUtils" class="com.test.TestUtils">
 <property name="testBean" ref="testBean" />
</bean>

您概述的方法就是我所看到的将Springbean注入实用程序类的方法

<bean id="testUtils" class="com.test.TestUtils">
 <property name="testBean" ref="testBean" />
</bean>

更多的细节是,这是我如何从spring注入静态字段的

<bean id="..." class="...">
 <property name="fieldToBeInjected">
            <util:constant static-field="CONSTANT_FIELD" />
        </property>
</bean>


也许这也会对您有所帮助。

静态方法的结果应该只取决于传递到方法中的参数,因此不需要调用任何bean

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

其他答案为您提供了可行的解决方案,但事实上它是可以做到的,并不意味着它应该做到。

您也可以实现接口,如下所示:

@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) {
    TestUtils.ac = ac;
  }

}

我的方法是针对希望访问的bean实现
初始化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;
    }
}
因此,在静态类中的用法仅为:

MyBean myBean = MyBean.get();

这样,不需要XML配置,您不需要将bean作为构造函数参数传入,调用方也不需要知道或关心bean是使用Spring连接的(即,不需要凌乱的
ApplicationContext
变量)。

类似于@nullPainter的响应,但我们做了以下工作。不需要构造后逻辑。它只是在注入期间直接设置静态成员(在@Autowired方法中)

这对我有用

使用xml配置定义您的bean(老式的):

用静态方法访问Springbean HTH

通用解决方案 您可以创建一个类,允许从静态上下文访问任何Bean。 这里的大多数其他答案仅显示如何静态访问单个类。

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

有关我的博客的详细信息:

用法 StaticContextAccessor的完整代码:
@组件
公共类StaticContextAccessor{
私有静态最终映射类处理程序=new HashMap();
私有静态应用上下文上下文;
@自动连线
公共静态上下文访问器(ApplicationContext ApplicationContext){
上下文=应用上下文;
}
公共静态T getBean(类clazz){
if(上下文==null){
返回getProxy(clazz);
}
返回context.getBean(clazz);
}
私有静态T getProxy(类clazz){
DynamicInvocationhandler invocationhandler=新的DynamicInvocationhandler();
put(clazz,invocationhandler);
return(T)Proxy.newProxyInstance(
clazz.getClassLoader(),
新类[]{clazz},
调用处理程序
);
}
//使用上下文获取实际的bean并将它们提供给调用处理程序
@施工后
私有void init(){
forEach((clazz,invocationHandler)->{
objectbean=context.getBean(clazz);
setActualBean(bean);
});
}
静态类DynamicInvocationhandler实现InvocationHandler{
私有T实际bean;
公共无效setActualBean(T actualBean){
this.actualBean=实际Bean;
}
@凌驾
公共对象调用(对象代理、方法、对象[]args)抛出Throwable{
如果(实际值=null){
抛出新的RuntimeException(“尚未初始化!:(”);
}
返回方法.invoke(actualBean,args);
}
}
}

是的,我认为我们应该使用它作为参数,而不是直接在静态类中设置。根据标准,它说我们不应该将bean用作静态,尽管我们可以用上面的回答中所示的不同方式来实现。感谢您的回复。“静态方法的结果应仅取决于传递给该方法的参数",拍得不错!我不清楚..你能添加testBean配置吗?slick-有没有一个好地方可以为Spring中重复出现的问题找到正确的解决方法..但是如果你使用Aspect,这是一个问题。Spring没有机会将你的实例包装到拦截器中。不需要传递
required=true
参数
@Autowired
的默认值。因此只有
@Autowired public void setMyManager(MyManager manager){MyManager=manager;}
就足够了。需要@Service annotation,这没有什么意义为什么使用spring bean作为静态字段不是一个好的做法?@user59290:因为静态字段不受spring的控制,它们受类加载器的约束。spring不能像管理对象那样分解类。乍一看,这是个好主意,but
this.ac=ac;
不正确。它应该是
TestUtils.ac=ac;
。或者您可以为
private static application上下文utilAc
定义不同的名称,然后
utilAc=ac;
。ac是否可以为null,并导致NPE问题?
@Service
public class MyBean implements InitializingBean {
    private static MyBean instance;

    @Override
    public void afterPropertiesSet() throws Exception {
        instance = this;
    }

    public static MyBean get() {
        return instance;
    }
}
MyBean myBean = MyBean.get();
@Service
public class MyUtil {

    private static MyManager myManager;

    @Autowired(required = true)
    public void setMyManager(MyManager manager) {
        myManager = manager;
    }

    public static MyManager getMyManager() {
        return myManager;
    }
}
<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> 
@Bean(name = "someBean2")
public MySpringComponent loadSomeSpringComponent() {

  MySpringComponent bean = new MySpringComponent();
  bean.setSomeProperty("1.0.2");
  return 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");
  }
}   
UserRepository userRepo = StaticContextAccessor.getBean(UserRespository.class)
@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);
        }
    }
}