Spring注入Servlet

tha*_*guy 23 java spring servlets dependency-injection

所以我看到了这个问题:

Spring依赖注入到其他实例

并想知道我的方法是否会成功.

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>
Run Code Online (Sandbox Code Playgroud)

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");
    }
Run Code Online (Sandbox Code Playgroud)

这个工作还是Spring还没准备好在Web应用程序部署中将bean交付给我的servlet?我是否必须做一些更传统的事情,比如把豆子放进去web.xml

Agu*_*hez 39

我想利用Sotirios Delimanolis提供的解决方案,但为混合添加透明自动装配.我们的想法是将普通的servlet转换为支持autowire的对象.

所以我创建了一个父抽象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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一个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());
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,EchoServlet唯一需要做的就是在常见的Spring实践中声明一个bean.魔术是在超类的init()方法中完成的.

我还没有彻底测试过它.但是它使用了一个简单的bean 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>
Run Code Online (Sandbox Code Playgroud)

然后像这样检索它:

WebApplicationContext context = WebApplicationContextUtils
    .getWebApplicationContext(getServletContext());
ctx = context.getAutowireCapableBeanFactory();
ctx.autowireBean(this);
Run Code Online (Sandbox Code Playgroud)

只需要导入spring-web库,而不是spring-mvc.


Sot*_*lis 28

你要做的就是让每个人Servlet都拥有自己的ApplicationContext实例.也许这就是你想要的,但我对此表示怀疑.一个ApplicationContext应该是唯一的应用程序.

这样做的恰当方法是设置你ApplicationContextServletContextListener.

public class SpringApplicationContextListener implements ServletContextListener {
        @Override
    public void contextInitialized(ServletContextEvent sce) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        sce.getServletContext().setAttribute("applicationContext", ac);            
    }
    ... // contextDestroyed
}
Run Code Online (Sandbox Code Playgroud)

现在,所有servlet都可以ApplicationContext通过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");
}
Run Code Online (Sandbox Code Playgroud)

  • 让Spring自己的Web基础结构使用以下web.xml片段加载应用程序上下文:`<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>`然后使用`WebApplicationContextUtils .getWebApplicationContext(getServletContext()检索)`.这只需要弹簧网,而不是spring-mvc. (7认同)

Ari*_*ion 8

到目前为止,这里的答案只对我有用.特别是带有@Configuration注释的类被忽略了,我不想使用xml配置文件.以下是我使用基于Spring(4.3.1)注释的设置进行注射工作的方法:

在web-app下的web.xml中引导AnnotationConfigWebApplicationContext.作为参数,您需要contextClass和contextConfigLocation(您的带注释的配置类):

<context-param>
    <param-name>contextClass</param-name>
    <param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
  </param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.example.config.AppConfig</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)

然后覆盖servlet中的init方法.我使用了一个扩展HttpServlet的抽象类,所以我不必在每个servlet中重复它:

@Configurable
public abstract class MySpringEnabledServlet extends HttpServlet
{
  @Override
  public void init(
      ServletConfig config) throws ServletException
  {
    super.init(config);
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
  }
[...]
}
Run Code Online (Sandbox Code Playgroud)

最后我在web.xml中提到的AppConfig类中有我的主配置:

@Configuration
@ComponentScan(basePackages = "com.example")
@Import(
{ SomeOtherConfig.class })
public class AppConfig
{
}
Run Code Online (Sandbox Code Playgroud)

dependend类注释:

@Component
public class AnnotatedClassToInject
Run Code Online (Sandbox Code Playgroud)

并通过我的servlet中的自动装配注入:

@Autowired
private AnnotatedClassToInject myClass;
Run Code Online (Sandbox Code Playgroud)