将注入的Spring Bean存储在HashMap中

时间:2015-05-28 21:00:28

标签: java spring dependency-injection

这是一个关于将Spring用于业务对象的问题,以及在将它们注入需要它们的类之后如何存储它们。

在典型的Spring设置中,您可能拥有如下业务对象:

package app.service.impl;

public class MaintainStudent implements app.service.intf.MaintainStudent
{
    protected app.dao.intf.CourseDAO courseDAO;
    protected app.dao.intf.StudentDAO studentDAO;
    protected app.dao.intf.CourseAssignDAO courseAssignDAO;

    //injection methods here
    public void setCourseDAO(app.dao.intf.CourseDAO courseDAO)
    {
        this.courseDAO = courseDAO;
    }

    public void setStudentDAO(app.dao.intf.StudentDAO studentDAO)
    {
        this.studentDAO = studentDAO;
    }

    public void setCourseAssignDAO(app.dao.intf.CourseAssignDAO courseAssignDAO)
    {
        this.courseAssignDAO = courseAssignDAO;
    }
    //end injection methods

    //example business method
    @Override
    @Transactional(rollbackFor={Exception.class})
    public void assignCourse(StudentKey studenKey, CourseKey courseKey)
    {
        courseAssignDAO.assignCourse(studentKey, courseKey);
    }

    //rest of the class here
}

上面的bean XML条目可能如下所示:

<bean id="baseDAO" class="app.dao.base.BaseDAO" abstract="true">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="courseDAO" class="app.dao.impl.CourseDAO"
    parent="baseDAO">
</bean>

<bean id="studentDAO" class="app.dao.impl.StudentDAO"
    parent="baseDAO">
</bean>    

<bean id="courseAssignDAO" class="app.dao.impl.CourseAssignDAO"
    parent="baseDAO">
</bean>

<bean id="maintainStudent" class="app.service.impl.MaintainStudent">
    <property name="courseDAO" ref="courseDAO" />
    <property name="studentDAO" ref="courseAssignDAO" />
    <property name="courseAssignDAO" ref="studentDAO" />
</bean>

我的问题是,将注入的bean存储在HashMap而不是单独的接口变量中是否可以?我问这个问题,因为我正在为我支持的应用程序开发一个移植项目,我正在尝试用Spring替换应用程序的EJB / JDBC事务架构。我使用Struts2和Spring作为应用程序的新架构。我在这个项目中使用Spring主要是为了它的数据库事务功能。现有的应用程序使用工厂类来实例化所有内容,我想出了一种方法,通过将bean存储在HashMap中,使用工厂类将体系结构转换为依赖注入。

下面是使用我的HashMap存储bean的方法的同一业务对象的示例:

package app.service.impl;

public class MaintainStudent extends app.base.BaseBusinessObj
    implements app.service.intf.MaintainStudent
{ 
    //injection methods here
    public void setCourseDAO(app.dao.intf.CourseDAO courseDAO)
    {
        this.springBeans.add(courseDAO.getClass().getName(), courseDAO);
    }

    public void setStudentDAO(app.dao.intf.StudentDAO studentDAO)
    {
        this.springBeans.add(studentDAO.getClass().getName(), studentDAO);
    }

    public void setCourseAssignDAO(app.dao.intf.CourseAssignDAO courseAssignDAO)
    {
        this.springBeans.add(courseAssignDAO.getClass().getName(), courseAssignDAO);
    }
    //end injection methods

    //example business method
    @Override
    @Transactional(rollbackFor={Exception.class})
    public void assignCourse(StudentKey studenKey, CourseKey courseKey)
    {
        app.dao.intf.CourseAssignDAO courseAssignDAO =
            app.dao.fact.CourseAssignDAOFactory.requestBean(this);

        courseAssignDAO.assignCourse(studentKey, courseKey);
    }

    //rest of the class here
}

BaseBusinessObj类:

package app.base;    

public class BaseBusinessObj implements org.springframework.beans.factory.DisposableBean
{
    private Map<String, Object> springBeans = new HashMap<String, Object>();

    public void addBean(String className, Object bean)
    {
        this.springBeans.put(className, bean);
    }

    public Object getBean(String className)
    {
        return this.springBeans.get(className);
    }

    @Override
    public void destroy() throws Exception
    {
        this.springBeans.clear();
    }
}

修改后的bean XML条目:

<bean id="baseBusinessObj" class="app.base.BaseBusinessObj" abstract="true">
</bean>

<bean id="baseDAO" class="app.dao.base.BaseDAO" abstract="true"
    parent="baseBusinessObj">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="courseDAO" class="app.dao.fact.CourseDAOFactory"
    parent="baseDAO">
</bean>

<bean id="studentDAO" class="app.dao.fact.StudentDAOFactory"
    parent="baseDAO">
</bean>

<bean id="courseAssignDAO" class="app.dao.fact.CourseAssignDAOFactory"
    parent="baseDAO">
</bean>

<bean id="maintainStudent" class="app.service.fact.MaintainStudentFactory"
    parent="baseBusinessObj">
    <property name="courseDAO" ref="courseDAO" />
    <property name="studentDAO" ref="courseAssignDAO" />
    <property name="courseAssignDAO" ref="studentDAO" />
</bean>

示例转换后的工厂类,现在提供注入的bean而不是创建新实例:

package app.dao.fact;

public class CourseAssignDAOFactory extends app.dao.impl.CourseAssignDAO
{
    protected CourseAssignDAOFactory()
    {
        super();
    }

    //method formerly called "newInstance()"
    public static app.dao.intf.CourseAssignDAO requestBean(app.base.BaseBusinessObj requester)
    {
        app.dao.intf.CourseAssignDAO result;
        Object requestedBean = requester.getBean(CourseAssignDAOFactory.class.getName());
        result = (app.dao.intf.CourseAssignDAO)requestedBean;

        return result;
    }
}

我的上述架构提供了以传统的非DI样式编写代码的功能,允许开发人员明确“请求”所需的对象。此请求是与自己创建(实例化)对象类似的活动。在我的架构中,'Requesting a Bean'已经取代了'创建新实例',因此Factory类语句可以保留在代码中,同时使代码可以使用依赖注入体系结构。我将创建一个代码生成器,它将自动生成所需的注入器方法到每个需要它们的类中。

我已经测试了上面的架构并且它可以工作。事务在预期时提交和回滚。

我只是想知道我创建的这个架构是否仍然允许Spring按照设计行事。

使用这种架构,在事务完成后,我的所有bean仍然可以被Spring销毁吗?或者由于HashMap存储想法会在内存中挂起对象吗?

让我知道你的想法。感谢您花时间阅读本文。

1 个答案:

答案 0 :(得分:0)

您可以使用Provider<Type>替换工厂并改为注入:

public class CourseAssignDaoUser {

    @Autowired
    private Provider<CourseAssignDao> factory;

    void useDao() {
        CourseAssignDao dao = factory.get();
        // ...
    }
}

甚至直接注入值:

public class CourseAssignDaoUser {

    @Autowired
    private CourseAssignDao dao;

    void useDao() {
        // ...
    }
}

如果由于某种原因无法实现,则可以使用Spring上下文 使用地图:

public class CourseAssignDAOFactory {

    public static CourseAssignDAO requestBean(ApplicationContext context) {
        return context.getBean(CourseAssignDao.class);
    }
}

但是使用@Autowired有或没有Provider绝对是最好的 溶液