在HashMap中存储注入的Spring bean



这是一个关于将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风格编写代码的能力,允许开发人员显式地"请求"所需的对象。这个请求与您自己创建(实例化)对象类似。在我的架构中,"请求一个Bean"取代了"创建一个新实例",这样工厂类语句就可以留在代码中,同时使代码与依赖注入架构一起工作。我将创建一个代码生成器,它将自动为每个需要注入器的类生成所需的注入器方法。

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

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

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

让我知道你的想法。谢谢你花时间看这篇文章。

您可以用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绝对是最好的解决方案。

最新更新