# spirng-servlet **Repository Path**: yao_ming_01/spirng-servlet ## Basic Information - **Project Name**: spirng-servlet - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-04 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Servlet与Spring集成问题 ## 1、添加依赖 ```xml 4.0.0 com.woniuxy spring-shiro 1.0-SNAPSHOT org.springframework spring-webmvc 5.1.14.RELEASE mysql mysql-connector-java 8.0.19 org.projectlombok lombok 1.18.10 javax.servlet javax.servlet-api 4.0.1 ``` ## 2、编写Service\Controller ### Service ```java package com.woniuxy.service.com.woniuxy.service; import com.woniuxy.entity.User; import com.woniuxy.service.UserService; public class UserServiceImpl implements UserService { @Override public void add() { } @Override public User findOne(Integer id) { return null; } } ``` Controller ```java package com.woniuxy.controller; import com.woniuxy.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import java.io.IOException; @WebServlet("/my.do") public class TestController extends HttpServlet { @Autowired UserService userService; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("TestController.service"); System.out.println(userService); } } ``` ## 问题: 注入userService失败; 1、UserService由Spring容器管理 2、Servlet由tomcat容器管理; 3、启动tomcat服务器时spring扫包生成userService实例 4、controller也由tomcat容器实例化; 5、当注入时是无法从spring容器取到service实例的 ## 解决 ### 方法1:暴力 ```java package com.woniuxy.controller; import com.woniuxy.service.UserService; import com.woniuxy.service.com.woniuxy.service.UserServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import java.io.IOException; @WebServlet("/my.do") public class TestController extends HttpServlet { @Autowired UserService userService; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { //在Servlet中new一个容器,再从容器中取出 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext.xml"); UserService userService = ac.getBean(UserServiceImpl.class); System.out.println("TestController.service"); System.out.println(userService); System.out.println(this.userService); } } ``` ### 引入代理Servlet 代理:由servlet实例化,初始化,不被spring管理 ```java package com.woniuxy.controller; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import java.io.IOException; @WebServlet("/my.do") public class DeletingServletProxy extends HttpServlet { public DeletingServletProxy() { System.out.println("实例化代理"); } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("调用service"); ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml"); Servlet testController = (Servlet) ac.getBean("testController"); testController.service(req,res); } } ``` 目标对象:由spring 管理通过代理从容器中取出,即可进行spring的注入功能 ```java package com.woniuxy.controller; import com.woniuxy.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import java.io.IOException; @Controller public class TestController extends HttpServlet { public TestController() { System.out.println("访问目标对象"); } @Autowired UserService userService; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("TestController.service::======"+userService); } } ``` 缺点:每个controller都要对应不同的代理; 解决方式: 1、使用同一个代理在web.xml中通过不同的请求访问,使用不同的名字, 2、代理通过servletname动态获取要从容器中取出的bean,因此servlet的名字为目标对象的类名首字母小写,确保通过名字可以取出 同时减少spring容器创建次数,使用监听器,启动时创建,放入application中 web ```xml testController com.woniuxy.controller.DeletingServletProxy testController /my.do herController com.woniuxy.controller.DeletingServletProxy herController /her.do com.woniuxy.listener.ContextListener ``` 监听器 ```java public class ContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { //创建容器 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext.xml"); //存入application作用域 sce.getServletContext().setAttribute("applicationcontext",ac); System.out.println("将容器放入application中"); } @Override public void contextDestroyed(ServletContextEvent sce) { } } ``` 代理 ```java public class DeletingServletProxy extends HttpServlet { public DeletingServletProxy() { System.out.println("实例化代理"); } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { //获取servlet名字 String servletName = getServletName(); //从application中取出容器 ApplicationContext ac = (ApplicationContext) this.getServletContext().getAttribute("applicationcontext"); //从容器中获取对应的servlet Servlet testController = (Servlet) ac.getBean(servletName); //调用对应的service方法 testController.service(req, res); } } ``` 目标对象 ```java @Controller public class TestController extends HttpServlet { @Autowired UserService userService; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("TestController.service::======"+userService); } } ``` ```java @Controller public class HerController extends HttpServlet { @Autowired UserService userService; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("HerController.service::======"+userService); } } ``` 总结: 1、spring容器和servlet都由tomcat容器管理时,servlet无法享受sping的DI(依赖注入)、Ioc功能,即无法注入实例; 2、当想在servlet中注入spring容器中的实例时,要使用代理,此时,代理由tomcat实例化,目标对象由spring管理,当启动完毕后先调代理,由代理从spring容器中取出对应的目标对象,然后servlet即可享受依赖注入功能; 3、这也是spring-mvc的底层实现原理 4、优化:一个代理对应多个请求;通过代理的display-name访问不同的目标对象;注意:display-name与容器中的实例id保持一致, 5、spring容器获取由监听器负责,启动tomcat就实例化容器,放入application中,这样无论多少次请求,都只要实例化容器一次