@Autowire替代静态字段的替代方案

时间:2014-01-02 07:22:21

标签: java spring autowired

静态字段@Autowire的替代方法是什么?

我经历了很多问题并理解为什么@Autowired不能用于静态字段。 this问题的接受答案提及

  

你必须编写自己的逻辑才能做到这一点。,因为@Autowired不能   使用。

由于我是依赖注入的新手,我没有得到必须遵循的步骤来编写我们自己的逻辑来执行此操作。

我得到的是new不能用于创建对象,因为它会紧密地耦合2个类,DI意味着它是一个解决方案。同样问题的第二个答案中也不建议使用带有setter的@autowired。那么在不使用@Autowire的情况下实现相同效果的替代方案是什么?

4 个答案:

答案 0 :(得分:4)

我会给你两个选择。第一个目前处于生产环境中。第二种选择是在我再次考虑这个问题后想出来的。

但是,应该避免这种情况,但是如果你有目前不了解Spring的代码,可以使用它。

备选方案1

实施ApplicationContextAware
我遇到了需要自动装配静态字段的情况。我正在处理遗留代码,我们希望在新代码中使用spring和jpa(hibernate)。一般来说静态字段的自动装配是不好的做法,但我相信在考虑应用程序的更大好处时可以激励它。

我们通过实现ApplicationContextAware解决了这种情况。 Se blelow:

public class DbHandler implements ApplicationContextAware {

private static DataSource dataSource;

protected DbHandler(){
    //Needs to be protected (not private) for Spring
}

//This method is used in many places in the code, and we can not change how it is 
//used. We wanted to use a datasource from Spring
public static Connection getConnection() throws java.sql.SQLException {
    return dataSource.getConnection();

}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    DbHandler.dataSource = applicationContext.getBean("dataSource", javax.sql.DataSource.class);
}

}

由于该类不在spring中扫描的包中,我们将其添加到context.xml

<bean id="dbHandler" class="se.ucr.db.DbHandler" depends-on="dataSource"/>

这并不像写@Autowired那么容易,但它确实有效。

备选方案2

创建一个singelton

可以注入的bean:

@Component
public class BeanToInject {

    private static final Logger LOGGER = LoggerFactory.getLogger(BeanToInject.class);

    public String getValue() {
        return "Value from SpringBean";
    }
}

一个简单的Singelton,它将注入上面定义的bean:

public class NeedStaticFieldInjected {

    private static final Logger LOGGER = LoggerFactory.getLogger(NeedStaticFieldInjected.class);

    private static NeedStaticFieldInjected INSTANCE;

    private NeedStaticFieldInjected() {
        //private constructor
    }

    @Autowired
    private BeanToInject beanToInject;

    public static NeedStaticFieldInjected getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new NeedStaticFieldInjected();
        }
        return INSTANCE;
    }


    public static String getValueFromSpringBean() {
        if (INSTANCE.beanToInject  == null)
            return "Not initialized correctly";

        return INSTANCE.beanToInject.getValue();
    }

}

最后,春天语境:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="org.emancipering.components"/>


<bean id="needStaticFieldInjected" class="org.emancipering.components.NeedStaticFieldInjected" factory-method="getInstance" />

</beans>

您将通过静态变量INSTANCE访问自动装配的属性,如NeedStaticFieldInjected .getValueFromSpringBean()所示。这非常接近注入静态场的目的。当然,可以有更多的Autowired属性,但我在这个例子中只添加了一个。

指定factory-method="getInstance"非常重要,否则会失败。

我希望这对某人有用。

答案 1 :(得分:2)

那就是“解决方案”:不要这样做。我没有看到你的代码示例,我会说,如果它依赖于动态(注入)的东西,你为什么要创建“静态”的东西?

通常我会重新考虑责任。将可能的静态部件重定位到静态util类。对于需要注射的部分,请改为创建正常服务。

(是的,总是有解决方法,但是当你需要解决方法时,你应该考虑更好的解决方案)。

答案 2 :(得分:1)

我需要在具有所有静态方法的日志记录类中集成现有类的功能(混淆)。这个日志记录类的静态方法在1000多个地方使用。因此,我可以实现这一点的唯一方法是创建一个混淆类的实例并分配对静态变量的引用并引用静态变量。它奏效了!

private static LogObfuscator staticObfuscator;

@Resource(name = "domain.logging.Obfuscator")
private  LogObfuscator obfuscatorInstance;

@PostConstruct
public void init() {
    staticObfuscator= obfuscatorInstance;
}

答案 3 :(得分:0)

每次刷新上下文(即完成)时,您都可以创建一个触发方法的bean。在该方法中,您将设置您喜欢的任何静态字段,例如,这会将两个bean相互注入,即使它们是静态的。

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

public class ApplicationListenerBean implements ApplicationListener {

    @Autowired
    SomeBean one;

    @Autowired
    SomeOtherBeab two;

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            one.setTwo(two);
            two.setOne(one);
        }
    }
}