所以我看到了这个问题:
并且想知道我的方法是否可行。
1)在我的Spring应用程序上下文中声明bean
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${jdbc.initialSize}" /> <property name="validationQuery" value="${jdbc.validationQuery}" /> <property name="testOnBorrow" value="${jdbc.testOnBorrow}" /> </bean> <bean id="apiData" class="com.mydomain.api.data.ApiData"> <property name="dataSource" ref="dataSource" /> <property name="apiLogger" ref="apiLogger" /> </bean> <bean id="apiLogging" class="com.mydomain.api.data.ApiLogger"> <property name="dataSource" ref="dataSource" /> </bean>
2)覆盖我的servlet的init方法,如下所示:
@Override public void init(ServletConfig config) throws ServletException { super.init(config); ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); this.apiData = (ApiData)ac.getBean("apiData"); this.apiLogger = (ApiLogger)ac.getBean("apiLogger"); }
这项工作还是Spring目前尚未准备好在Web应用程序部署中将bean交付给我的servlet?我是否需要做一些更传统的事情,例如放入豆子web.xml?
web.xml
你要尝试做的将使每个实例Servlet都有其自己的ApplicationContext实例。也许这就是你想要的,但我对此表示怀疑。一个ApplicationContext应该是唯一的应用程序。
ApplicationContext
进行此操作的适当方法是在中设置你ApplicationContext的ServletContextListener。
ServletContextListener
public class SpringApplicationContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); sce.getServletContext().setAttribute("applicationContext", ac); } ... // contextDestroyed }
现在,你所有的servlet都可以ApplicationContext通过ServletContext属性访问相同的servlet 。
ServletContext
@Override public void init(ServletConfig config) throws ServletException { super.init(config); ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute("applicationContext"); this.apiData = (ApiData)ac.getBean("apiData"); this.apiLogger = (ApiLogger)ac.getBean("apiLogger"); }
我想利用Sotirios Delimanolis提供的解决方案,但要添加透明的自动布线。这个想法是将普通的servlet转变为可感知自动连线的对象。
因此,我创建了一个父抽象servlet类,该类检索Spring上下文,获取具有自动装配功能的工厂,并使用该工厂自动装配servlet实例(实际上是小节)。我还将工厂存储为实例变量,以防子类需要它。
因此,父抽象servlet如下所示:
public abstract class AbstractServlet extends HttpServlet { protected AutowireCapableBeanFactory ctx; @Override public void init() throws ServletException { super.init(); ctx = ((ApplicationContext) getServletContext().getAttribute( "applicationContext")).getAutowireCapableBeanFactory(); //The following line does the magic ctx.autowireBean(this); } }
sevlet子类如下所示:
public class EchoServlet extends AbstractServlet { @Autowired private MyService service; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.getWriter().println("Hello! "+ service.getMyParam()); } }
注意,EchoServlet唯一需要做的就是在普通的Spring实践中声明一个bean。魔术是在超类的init()方法中完成的。
我还没有彻底测试。但是它与一个简单的bean MyService一起工作,该MyService也从Spring管理的属性文件中自动连接了一个属性。
请享用!
注意:
最好使用Spring自己的上下文侦听器加载应用程序上下文,如下所示:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
然后像这样检索它:
WebApplicationContext context = WebApplicationContextUtils .getWebApplicationContext(getServletContext()); ctx = context.getAutowireCapableBeanFactory(); ctx.autowireBean(this);
仅需要导入spring-web库,而无需导入spring-mvc。