如何通过另一个类中的setter或构造函数设置Spring应用程序上下文

时间:2013-07-24 10:03:35

标签: spring

我有一个Spring课程。

@Service("dbManager") 
@Repository
@Transactional
public class DatabaseManager {

    GenericXmlApplicationContext context;

    @PersistenceContext
    private EntityManager em;

    public DatabaseManager(GenericXmlApplicationContext context) {
        this.context = context;
    }

        ....
} //end of class DatabaseManager

我有SpringUtil类

public class SpringUtil {

    public static GenericXmlApplicationContext loadSpringContext(String springXmlFile) {    

        GenericXmlApplicationContext context = new GenericXmlApplicationContext();
        context.load(springXmlFile);
        context.refresh();

        return context;

    } //end of loadSpringContext()

} //end of class SpringUtil

现在我正在使用像

这样的东西
public class Regulator  {

    public static void main( String[] args ) {

        Test test = new Test;
        test.start();

    } //end of main()

} //end of class Regulator

这是测试类

public class Test {

    public void start() {

        String springXmlFile = "classpath:spring/plcb-app-context-xml.xml";
        GenericXmlApplicationContext context = SpringUtil.loadSpringContext(springXmlFile);

    } //end of reportStudent()

 } //end of class Test

但是我收到错误

Could not instantiate bean class [...DatabaseManager]: No default constructor 
found; nested exception is java.lang.NoSuchMethodException: 
...DatabaseManager.<init>()

我希望在创建DatabaseManager类时,然后使用SpringUtil.loadSpringContext(springXmlFile)创建的spring context taht必须传递给它。我该怎么办?

由于

修改 -------------------

public void switchDataSource(DatabaseType databaseType) {

    DriverManagerDataSource dataSource = null;

    if (databaseType == DatabaseType.LEGACY) {

        dataSource = (DriverManagerDataSource)context.getBean("myLegacyDataSource");

    } else if (databaseType == DatabaseType.LS360) {

        dataSource = (DriverManagerDataSource)context.getBean("myLs360DataSource");

    }

    LocalContainerEntityManagerFactoryBean emf = context.getBean("myEmf", LocalContainerEntityManagerFactoryBean.class);
    emf.setDataSource(dataSource);

}

@SuppressWarnings("unchecked")
@Transactional(readOnly=true)
public List<Object> getResultList(String query, Class mappingClass) throws Exception {

    Query emQuery = em.createNativeQuery(query, mappingClass);

    return  emQuery.getResultList();

} //end of findTraineeFromLegacy()

实际上我的DatabaseManager类中有这两种方法。我正在设置上下文,所以我可以从switchDataSource()方法中的上下文中获取bean。

我可以做的一件事就是删除实例并将方法更改为

public void switchDataSource(DatabaseType databaseType, GenericXmlApplicationContext context) {
     ....
}

这就是我这样做的原因?

由于

1 个答案:

答案 0 :(得分:2)

为DatabaseManager建立一个no-arg构造函数。

在DatabaseManager中实现ApplicationContextAware。 Spring会知道这个bean需要通知应用程序上下文:

@Service("dbManager") 
@Repository
@Transactional
public class DatabaseManager implements ApplicationContextAware {

    private ApplicationContext context;
    public DatabaseManager() {...}

    @Override
    public void setApplicationContext(ApplicationContext appContext) {
        this.context = appContext;
    }
} //end of class DatabaseManager
但是,如果你真的需要注射的话,请考虑一下。在大多数情况下,你做错了。


更新

对于您的更新中的要求,您希望数据库管理器根据输入类型切换数据源,尽管执行此类操作似乎不太常见,但您可以简单地为数据库管理器注入Map并执行任何操作你想要的,而不是注入应用程序上下文。

@Service("dbManager") 
@Repository
@Transactional
public class DatabaseManager implements ApplicationContextAware {

    @Resource("&emfBean")
    private LocalContainerEntityManagerFactoryBean emfBean;

    @Resource("dbManagerDsMap")
    private Map<DatabaseType, Datasource> dsMapping;

    public DatabaseManager() {...}

    public void switchDataSource(DatabaseType databaseType) {
        emfBean.setDatasource(dsMapping.get(databaseType));
    }

} //end of class DatabaseManager

但是我强烈建议你不要这样做。考虑为要连接的每个数据库设置单独的entityManagerFactory,并使用正确的emf连接到DB,而不是使用这种奇怪的切换逻辑。我相信应用程序启动后不应该更改。