使用自定义注解向servlet注入spring bean

xiaoxiao2021-02-28  102

由于servlet容器和spring容器并不是同一个,所以当需要向servlet中注入spring bean是有以下操作:

1、使用proxy servlet(代理servlet),将实际servlet加入spring bean管理,在代理servlet的init方法中找到被代理servlet bean,后续请求处理由被代理servlet处理

2、使用Spring的Autowired注解(在servlet的bean属性中加入此注解,由spring容器自动注入)

代理servlet实现向servlet注入spring bean真的好麻烦,所以我们选择注解实现自动注入,但是不禁又想了想,既然spring可以通过扫描属性注解来自动注入spring bean,那么我们自己定义注解扫描是不是也可以呢?

首先,定义自定义注解

/** * Servlet注入的bean属性注解, 注入操作由AbstractBaseServlet完成 * @author jiashun */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface AnnotationServletBean { }

定义AbstractBaseServlet

/** * 所有Servlet的基类, 用来实现向servlet注入bean */ public abstract class AbstractBaseServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * 日志对象 */ private static Logger LOG = LogFactory.getLogger(AbstractBaseServlet.class); /** * servlet初始化 */ public void init() throws ServletException { /** * 根据Servlet上下文获取spring上下文 */ WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); String className = this.getClass().getName(); Field[] beanFields = getServletBeanFields(); if (beanFields.length == 0) { LOG.info("在类[" + className + "]中未找到具有AnnotationServletBean注解的属性, 注入 spring bean操作结束"); return; } LOG.info("向类 [" + className + "] 注入spring bean 操作开始"); try { for (Field field : beanFields) { field.setAccessible(true); Object value = ctx.getBean(field.getName()); field.set(this, value); LOG.info("向类[" + className + "]注入spring bean [" + field.getName() + "]成功"); } } catch (Exception e) { LOG.error("注入 spring bean 操作失败", e); } LOG.info("向类 [" + className + "] 注入spring bean 操作结束"); } /** * 获取具有AnnotationServletBean属性的servlet属性集合 * @return * 具有AnnotationServletBean注解的属性集合, 不为null */ private Field[] getServletBeanFields() { Field[] fields = ReflectUtil.getDeclaredFields(this.getClass()); if (fields.length > 0) { List<Field> fieldList = new ArrayList<>(); for (Field field : fields) { if (field.getAnnotation(AnnotationServletBean.class) != null) { fieldList.add(field); } } fields = fieldList.toArray(new Field[fieldList.size()]); } return fields; } }

AbstractBaseServlet的大致思想就是在init方法中找到继承类中具有AnnotationServletBean注解的属性,然后通过属性名获取spring bean,再通过反射向继承类注入spring bean属性。

然后我们写一个继承类

/** * 通用登录Servlet * @author jiashun */ public class LoginServlet extends AbstractBaseServlet { private static final long serialVersionUID = 1L; @AnnotationServletBean private WebAppInitializer webappInitializer; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello, This is LoginServlet !"); } }

WebAppInitializer是我自己的项目用到的服务初始化bean,已经发布为spring bean。 我们可以看到LoginServlet的webappInitializer属性具有AnnotationServletBean注解,那么在LoginServlet初始化时会调用执行AbstractBaseServlet的init方法来注入spring bean(具体注入操作就是注入具有AnnotationServletBean注解的属性)

访问LoginServlet服务打印日志:

[WebApp] [INFO] [2017-05-07 09:48:59,645] [http-nio-8080-exec-14] com.jiashun.webapp.common.servlet.AbstractBaseServlet.init(AbstractBaseServlet.java:44) | 向类 [com.jiashun.webapp.common.servlet.LoginServlet] 注入spring bean 操作开始 [WebApp] [INFO] [2017-05-07 09:48:59,647] [http-nio-8080-exec-14] com.jiashun.webapp.common.servlet.AbstractBaseServlet.init(AbstractBaseServlet.java:50) | 向类[com.jiashun.webapp.common.servlet.LoginServlet]注入spring bean [webappInitializer]成功 [WebApp] [INFO] [2017-05-07 09:48:59,647] [http-nio-8080-exec-14] com.jiashun.webapp.common.servlet.AbstractBaseServlet.init(AbstractBaseServlet.java:55) | 向类 [com.jiashun.webapp.common.servlet.LoginServlet] 注入spring bean 操作结束
转载请注明原文地址: https://www.6miu.com/read-70365.html

最新回复(0)