Spring web应用下怎么方便的获得bean?

本文介绍了一种在Spring Web应用中便捷获取Bean的方法。通过创建一个Servlet在启动时加载Spring上下文,并提供静态方法getBean供其他组件使用。
Spring web应用下怎么方便的获得bean?
如果我们的系统不是分布式的(在分布式里,我一般自己加载spring的配置文件),不是一般的application,通过自己加载Spring的配置文件的方式。而是一般的web应用,我们通过在web.xml里配置spring的配置文件。我们怎么方便的得到一个Bean的实例呢?当然,web应用启动后,它已经创建好一个WebApplicationContext(这个是接口,其实也是ApplicationContext类型的,因为WebApplicationContext继承自ApplictionContext这个接口)类型的实例对象,通过org.springframework.web.context.support.WebApplicationContextUtils里的
getWebApplicationContext(ServletContext sc)可以得到这个对象的引用(这个就像我们一般的java application下得到ApplicationContext类型的引用一样),我们就可以通过它的getBean方法得到我们的bean实例了。但是这里有个问题getWebApplicationContext(ServletContext sc)这个方法的参数ServletContext代表的是你web应用的环境,也就是说,也就是说web应用环境下特有的。这个时候如果你想得到一个bean的话,必须要有这个ServletContext对象存在,如果你每个类里都写一个方法来接受ServletContext对象,从而得到WebApplicationContext类型实例的引用,之后再得到bean,进行你要的操作,这个是不是很麻烦?这个不是要写很多代码么?我觉得可以把获得bean的这个操作的功能代码放在一个Servlet里,让这个Servlet在web应用启动的时候加载,我们之后把这个Servlet当作普通类使用,调用里面的getBean方法就可以了。这个servlet的代码如下:



package jimmee.cn.edu.zju.pdm.framework.server;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class GetBeanServlet extends HttpServlet
...{

private static WebApplicationContext context;

public void init() throws ServletException
...{
context=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
}

public static Object getBean(String id)
...{
Object bean = context.getBean(id);

return bean;
}
}


.Spring在web应用



<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Spring的配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<servlet>
<servlet-name>springInitServlet</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>log4jInitServlet</servlet-name>
<servlet-class>
org.springframework.web.util.Log4jConfigServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>GetBeanServlet</servlet-name>
<servlet-class>jimmee.cn.edu.zju.pdm.framework.server.GetBeanServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<!--Spring配置结束 -->
<servlet-mapping>
<servlet-name>GetBeanServlet</servlet-name>
<url-pattern>/servlet/GetBeanServlet</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>


使用示例:

假使我有一个Person的类,属性有name和age,在spring配置文件里配置的id为“person”

你在你的servlet或者jsp想得到这个实例的时候,直接这么做就可以了:

Person person=(Person)GetBeanServlet.getBean("person");
<think>我们讨论的是在自定义Servlet中访问Spring管理的Bean。根据引用[2],提到了一种使用自定义注解向Servlet注入Spring Bean的方法。具体来说,是在Servlet初始化时调用一个方法(如AbstractBaseServlet的init方法)来注入具有特定注解(如AnnotationServletBean)的属性。 另外,引用[4]提到了Spring注册Bean的多种方式,其中提到了@Import、@ComponentScan等方式,但更重要的是,它提到了使用FactoryBean接口注册Bean,以及@Configuration和@Bean的方式。这些方式可以帮助我们理解Spring Bean是如何被管理的。 然而,自定义Servlet并不由Spring管理,它是独立的,因此不能直接通过@Autowired等Spring注解来注入Bean。我们需要通过一些手段来获取Spring的上下文,从而获取Bean。 实现方式通常有以下几种: 1. 通过Spring提供的工具类获取ApplicationContext,然后获取Bean。 2. 在Servlet初始化时,通过ServletContext获取Spring的ApplicationContext。 3. 使用Spring提供的DelegatingFilterProxy或者SpringBeanAutowiringSupport。 引用[2]中描述的方法正是第二种方法的一种实现:在Servlet的init方法中,通过自定义的注解来注入属性。具体步骤可能是: - 自定义一个注解(如AnnotationServletBean),用于标记需要注入的属性。 - 在Servlet的初始化方法中,通过反射遍历Servlet的属性,对于有该注解的属性,从Spring的ApplicationContext中获取对应的Bean并注入。 另外,我们还可以通过实现Spring的ApplicationContextAware接口来获取ApplicationContext,但这种方式通常用于Spring管理的Bean,而Servlet不是由Spring管理的。 因此,我们可以这样实现: 步骤一:获取Spring的ApplicationContext。 在Web应用中,Spring的ApplicationContext通常存储在ServletContext中。我们可以通过ServletContext获取。 步骤二:在自定义Servlet的初始化方法中,从ServletContext中获取ApplicationContext,然后根据需要获取Bean。 示例代码: 1. 在Spring启动时,将ApplicationContext存入ServletContext。实际上,Spring已经为我们做了这一步,它将ApplicationContext存储为ServletContext的一个属性,其属性名为`WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`(注意:在Spring中,通常使用`WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`作为key存储根应用上下文)。 2. 在自定义Servlet中,我们可以重写init方法,获取ServletContext,然后获取ApplicationContext。 示例: ```java import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class MyServlet extends HttpServlet { private MyService myService; // 假设这是Spring管理的Bean @Override public void init(ServletConfig config) throws ServletException { super.init(config); // 通过工具类获取ApplicationContext WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); // 从ApplicationContext中获取Bean myService = ctx.getBean(MyService.class); } // ... 其他方法,如doGet, doPost等,就可以使用myService了 } ``` 另外,引用[2]提到了一种使用自定义注解的方式,实际上也是基于同样的原理,只是将注入过程自动化了。 所以,总结回答用户的问题:自定义Servlet可以直接访问Spring管理的Bean,实现方法主要是通过获取Spring的ApplicationContext,然后从中获取所需的Bean。获取ApplicationContext的方式有多种,其中通过WebApplicationContextUtils工具类从ServletContext获取是最常用的方式。 此外,还可以考虑使用Spring提供的`SpringBeanAutowiringSupport`,它可以让Servlet支持自动注入。例如: ```java import org.springframework.web.context.support.SpringBeanAutowiringSupport; import javax.servlet.http.HttpServlet; public class MyServlet extends HttpServlet { @Autowired // 现在可以使用Autowired了 private MyService myService; @Override public void init() { SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext()); } } ``` 这种方式通过调用`processInjectionBasedOnServletContext`方法,将当前Servlet实例中的@Autowired等注解进行注入。其背后也是通过获取ApplicationContext来实现的。 因此,用户可以根据需要选择合适的方式。 相关问题: 1. 如何在Filter中访问Spring管理的Bean? 2. 使用SpringBeanAutowiringSupport注入Bean的原理是什么? 3. 在非Web环境中如何获取Spring管理的Bean? 4. 自定义Servlet如何与Spring MVC的DispatcherServlet共存? 5. 使用WebApplicationContextUtils获取ApplicationContext的原理是什么? </think>### 自定义 Servlet 访问 Spring Bean 的实现方式 是的,自定义 Servlet **可以直接访问 Spring 管理的 Bean**,但需要通过特定技术实现。以下是核心原理和三种实现方法: --- #### ⚙️ 核心原理 Servlet 本身**不由 Spring 管理**,无法直接使用 `@Autowired` 注入。必须通过以下桥梁获取 Spring 容器: ```mermaid graph TD A[自定义Servlet] --> B[获取ServletContext] B --> C[访问SpringWebApplicationContext] C --> D[获取Spring Bean] ``` --- #### ✅ 实现方法 1. **通过 `WebApplicationContextUtils` 工具类(推荐)** 在 Servlet 的 `init()` 方法中获取 Spring 上下文: ```java public class MyServlet extends HttpServlet { private UserService userService; // Spring Bean @Override public void init() { // 关键步骤:获取Spring上下文 WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(getServletContext()); // 获取Bean this.userService = ctx.getBean(UserService.class); } @Override protected void doGet(...) { userService.process(); // 安全使用Spring Bean } } ``` **优势**:无需额外依赖,适用于任何 Servlet 容器[^2][^5]。 2. **使用 `@Autowired` + 初始化支持** 通过 `SpringBeanAutowiringSupport` 启用自动注入: ```java public class MyServlet extends HttpServlet { @Autowired // 直接注解注入 private UserService userService; @Override public void init() { // 启用Spring注入支持 SpringBeanAutowiringSupport .processInjectionBasedOnServletContext(this, getServletContext()); } } ``` **注意**:需确保 Spring 上下文已初始化完成[^2]。 3. **Servlet 注册为 Spring BeanSpring Boot 专用)** 在配置类中将 Servlet 注册为 Bean: ```java @Bean public ServletRegistrationBean<MyServlet> myServlet() { ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(new MyServlet(), "/path"); bean.setLoadOnStartup(1); return bean; } ``` **效果**:Spring 会管理 Servlet 实例,可直接使用 `@Autowired`[^1][^4]。 --- #### ️ 关键注意事项 1. **初始化时机** Bean 访问必须在 `init()` 或之后的方法中执行,不能在构造函数中操作(此时上下文未就绪)。 2. **作用域安全** - 单例 Bean:可安全使用(需确保线程安全) - 原型/会话 Bean:需每次从上下文获取新实例 ```java // 获取原型Bean的正确方式 UserService prototypeBean = ctx.getBean("prototypeUserService"); ``` 3. **依赖查找 vs 依赖注入** 优先使用 `ctx.getBean()` 显式查找,避免隐式注入带来的不可控性。 --- #### 应用场景示例 ```java public class PaymentServlet extends HttpServlet { private PaymentService paymentService; // Spring Bean @Override public void init() { WebApplicationContext ctx = ...; paymentService = ctx.getBean(PaymentService.class); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { // 使用Spring Bean执行业务 PaymentResult result = paymentService.process(req.getParameter("orderId")); resp.getWriter().write(result.toString()); } } ``` --- ### 总结 | 方法 | 适用场景 | 复杂度 | |-------------------------------|-------------------------|--------| | WebApplicationContextUtils | 通用方案,兼容性强 | ★★☆ | | SpringBeanAutowiringSupport | 需要注解风格的代码 | ★★★ | | ServletRegistrationBean | Spring Boot 专用方案 | ★☆☆ | **核心结论**:通过合理访问 `WebApplicationContext`,自定义 Servlet 可安全使用 Spring Bean,但需遵循显式查找原则[^1][^2][^5]。 --- **相关问题** 1. 如何在 Spring Filter 中访问 Service 层 Bean? 2. 非 Web 环境(如定时任务)如何获取 Spring 上下文? 3. Spring Boot 中如何配置 Servlet 的执行顺序? 4. 自定义 ServletSpring MVC 的 DispatcherServlet 有何区别? 5. 如何为自定义 Servlet 配置 Spring 事务管理?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值