# 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中,这样无论多少次请求,都只要实例化容器一次