Java复习笔记(7)——SSM(2)

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/90903407

四:JPA

1. 事务

事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity )、一致性( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily )。

2. 事务的分类

(1)本地事务

紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。

  • 此种事务处理方式不存在对应用服务器的依赖,因而部署灵活
  • 无法支持多数据源的分布式事务
public void transferAccount() { 
	Connection conn = null; 
	Statement stmt = null; 
	try{ 
		conn = getDataSource().getConnection(); 
		// 将自动提交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
		conn.setAutoCommit(false);
		stmt = conn.createStatement(); 
		// 将 A 账户中的金额减少 500
		stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
		// 将 B 账户中的金额增加 500 
		stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
		// 提交事务
		conn.commit();
		// 事务提交:转账的两步操作同时成功
	} catch(SQLException sqle){ 
		// 发生异常,回滚在本事务中的操做
		conn.rollback();
		// 事务回滚:转账的两步操作完全撤销
		stmt.close(); 
		conn.close(); 
	} 
}

(2)分布式事务

Java 事务编程接口(JTA:Java Transaction API)和 Java 事务服务 (JTS;Java Transaction Service) 为 J2EE 平台提供了分布式事务服务。

分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。

  • 资源管理器:任意类型的持久化数据存储
  • 事务管理器:承担着所有事务参与单元的协调与控制
public void transferAccount() { 
	UserTransaction userTx = null; 
	Connection connA = null; Statement stmtA = null; 
	Connection connB = null; Statement stmtB = null; 
	try{ 
		// 获得 Transaction 管理对象
		userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction"); 
		connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
		connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
		
		// 启动事务		
		userTx.begin(); 
		stmtA = connA.createStatement();// 将 A 账户中的金额减少 500 
		stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
		// 将 B 账户中的金额增加 500 
		stmtB = connB.createStatement(); 
		stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
		userTx.commit();// 提交事务
		// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
	} catch(SQLException sqle){ 
		// 发生异常,回滚在本事务中的操纵
		userTx.rollback();
		// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
	} catch(Exception ne){ } 
}
两阶段提交

两阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做

将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作。
在这里插入图片描述

准备阶段

事务协调者(事务管理器)给每个参与者(资源管理器)发送 Prepare 消息

每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的 redo 和 undo 日志,但不提交,到达一种“万事俱备,只欠东风”的状态。

提交阶段

如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息

参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)

五:Mybatis

Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。

  • 一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。
  • 二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的sqlsession 是可以共享的。
    在这里插入图片描述

Mybatis 的一级缓存原理(sqlsession 级别)

第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。

  • key:MapperID+offset+limit+Sql+所有的入参
  • value:用户信息

同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。

二级缓存原理(mapper 级别)

二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。

mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。

  • key:MapperID+offset+limit+Sql+所有的入参

具体使用需要配置:

  1. Mybatis 全局配置中启用二级缓存配置
  2. 在对应的 Mapper.xml 中配置 cache 节点
  3. 在对应的 select 查询节点中添加 useCache=true

六:Servlet

Servlet 是基于 Java 技术的 Web 组件,由容器管理并产生动态的内容。Servlet 引擎作为 WEB 服务器的扩展提供支持 Servlet 的功能。Servlet 与客户端通过 Servlet 容器实现的请求/响应模型进行交互

Servlet 生命周期

  1. 创建 Servlet 对象,通过服务器反射机制创建 Servlet 对象,第一次请求时才会创建
  2. 调用 Servlet 对象的 init()方法,初始化 Servlet 的信息,init()方法只会在创建后被调用一次
  3. 响应请求,调用 service()或者是 doGet(),doPst()方法来处理请求,这些方法是运行的在多线程状态下的。
  4. 在长时间没有被调用或者是服务器关闭时,会调用 destroy()方法来销毁 Servlet 对象。

七:Struts

工作流程

在这里插入图片描述

工作原理

在这里插入图片描述
在这里插入图片描述

过滤器

doFilter是过滤器的执行方法,拦截提交的HttpServletRequest请求和HttpServletResponse响应,作为Struts2的核心过滤器
在这里插入图片描述
在这里插入图片描述
过滤器和拦截器的区别:
在这里插入图片描述
过滤器每一次拦截请求时,都会创建新的ActionContext对象,放在ThreadLocal中,因此不需要考虑线程安全

Struts2和1

在这里插入图片描述

八:Tomcat

参考博客:粗浅看 Tomcat系统架构分析

1. Tomcat的结构

在这里插入图片描述
在这里插入图片描述

  • Server 服务器:提供了一种优雅的方式来启动和停止整个系统,不必单独启停连接器和容器
  • Service 服务:把多个Connector、一个Container以及其他组件组装在一起,向外面提供服务。每个服务允许同时支持多种协议,但是每种协议最终执行的Servlet却是相同的
  • Connector 连接器:将Service和Container连接起来。主要负责对外交流,把来自客户端的请求转发到Container,每种协议可使用一种连接器来支持
  • Container 容器:主要处理 Connector 接受的请求,处理内部事务。可以看做Servlet容器
    • Engine:引擎
    • Host :主机
    • Context :上下文
    • Wrapper: 包装器

多个Connector和一个Container 形成了一个Service,多个Service服务形成一个Tomcat,整个Tomcat的生命周期由Server控制

其他组件:

  • Manager – 管理器,用于管理会话Session
  • Logger – 日志器,用于管理日志
  • Loader – 加载器,和类加载有关,只会开放给Context所使用
  • Pipeline – 管道组件,配合Valve实现过滤器功能
  • Valve – 阀门组件,配合Pipeline实现过滤器功能
  • Realm – 认证授权组件

在这里插入图片描述
Valve作为一个个基础的阀门,扮演着业务实际执行者的角色。
Pipeline作为一个管道,可以简单认为是一个Valve的集合,内部会对这个集合进行遍历,调用每个元素的业务逻辑方法invoke()。

2. Tomcat的功能模块

  • Jsper子模块:这个子模块负责jsp页面的解析、jsp属性的验证,同时也负责将jsp页面动态转换为java代码并编译成class文件。(org.apache.jasper包及其子包中的源代码)

  • Servlet和Jsp规范的实现模块:如我们非常熟悉的javax.servlet.Servlet接口、javax.servet.http.HttpServlet类及javax.servlet.jsp.HttpJspPage就位于这个子模块中(javax.servlet包及其子包的源代码)

  • Catalina子模块:规范了Tomcat的总体架构,定义了Server、Service、Host、Connector、Context、Session及Cluster等关键组件及这些组件的实现,这个子模块大量运用了Composite设计模式,同时也规范了Catalina的启动及停止等事件的执行流程。(以org.apache.catalina开头的java源代码)

  • Connectors子模块:如果说上面三个子模块实现了Tomcat应用服务器的话,那么这个子模块就是Web服务器的实现。它接收用户的请求,并把用户请求包装成标准的Http请求(包含协议名称,请求头Head,请求方法等)。同时,这个子模块还按照标准的Http协议,负责给客户端发送响应页面

  • Resource子模块:这个子模块包含一些资源文件,如Server.xml及Web.xml配置文件。严格说来,这个子模块不包含java源代码,但是它还是Tomcat编译运行所必需的。

3. 具体接口

Service

Service 接口

主要作用是关联Connector和 Container
在这里插入图片描述

Lifecycle 接口

主要作用是控制组件的生命周期
在这里插入图片描述
Lifecycle接口的方法的实现都在其它组件中,组件的生命周期由包含它的父组件控制,所以它的 Start 方法自然就是调用它下面的组件的 Start 方法,Stop 方法也是一样。

监听的代码会包围 子组件的启动过程,就是简单的循环启动所有 子组件的Start 方法,但是所有子组件必须要实现Lifecycle接口,这样做会更加灵活。

public void start() throws LifecycleException {
 
	if (started) {
		log.debug(sm.getString("standardServer.start.started"));
		return;
	}
	 
	lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,  null);
	
	lifecycle.fireLifecycleEvent(START_EVENT,  null);
	
	started = true;
	 
	//监听的代码会包围子组件的启动过程,就是简单的循环启动所有子组件的Start方法
	synchronized (services) {
		for (int i = 0; i < services.length; i++) 
			if (services[i] instanceof Lifecycle)
				((Lifecycle) services[i]).start();
		}
	lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
StandardService 标准实现类

不仅实现了 Service 接口同时还实现了 Lifecycle 接口
在这里插入图片描述
设置container:

//设置container
public void setContainer(Container container) {
 
	Container oldContainer = this.container;
	 
	 //判断当前的这个 Service 有没有已经关联了 Container
	 //如果已经关联了,那么去掉这个关联关系
	if ((oldContainer != null) && (oldContainer instanceof Engine))
		((Engine) oldContainer).setService(null);
	
	//设置Container容器
	this.container = container;
	
	//和Service设置关联 
	if ((this.container != null) && (this.container instanceof Engine))
		((Engine)  this.container).setService(this);
	 
	 //启动container
	if (started && (this.container != null) && (this.container instanceof Lifecycle)){
		try {
			((Lifecycle) this.container).start();	 
		} catch (LifecycleException e) {}
	}
	 
	 //和每一个connector关联 
	synchronized (connectors) {
		for (int i = 0; i < connectors.length; i++)
			connectors[i].setContainer(this.container);
	}
	 
	 //如果以前的那个container已经被启动了,结束它的生命周期
	if (started && (oldContainer != null) && (oldContainer instanceof Lifecycle)){
		try {
			((Lifecycle)  oldContainer).stop();
		} catch (LifecycleException e) {}
	}
	 
	 //最后将这个过程通知感兴趣的事件监听程序
	support.firePropertyChange("container", oldContainer, this.container);
}

添加connector:

public void addConnector(Connector connector) {
 
	synchronized (connectors) {
	 
	 	//与container关联
		connector.setContainer(this.container);
	 
	 	//与service关联
		connector.setService(this);
	 
	 	//使用数组方便检索
	 	//动态扩展数组,加入connector
		Connector results[] = new Connector[connectors.length + 1];
		System.arraycopy(connectors, 0, results, 0, connectors.length);
		results[connectors.length] = connector;
		connectors = results;
	 
	 	//初始化connector
		if (initialized) {
			try {
				connector.initialize();	 
			} catch (LifecycleException e) {
				e.printStackTrace(System.err);
			}
		} 
		
		//启动connector
		if (started && (connector instanceof Lifecycle)) {
			try { 
			
				((Lifecycle) connector).start();
			
			} catch (LifecycleException e) {}
		}
	 
		//最后将这个过程通知感兴趣的事件监听程序
		support.firePropertyChange("connector", null, connector);	 
	}
}

Server

Server 接口

提供一个接口让其它程序能够访问到这个 Service 集合、同时要维护它所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的 Service
在这里插入图片描述

StandardServer 标准实现类

同时实现了 Server、Lifecycle、MbeanRegistration 三个接口的所有方法

添加Service:

public void addService(Service service) {
 
 	//关联server
	service.setServer(this);
 
	synchronized (services) {
	
 	 	//使用数组方便检索
	 	//动态扩展数组,加入service
		Service results[] = new Service[services.length + 1];
		System.arraycopy(services, 0, results, 0, services.length);
		results[services.length] = service;
		services = results;
		 
		 //初始化service
		if (initialized) {
			try {
				service.initialize();
			} catch (LifecycleException e) {
				e.printStackTrace(System.err);
			}
		}
		 
		 //启动service
		if (started && (service instanceof Lifecycle)) {		 
			try {
				((Lifecycle) service).start();
			} catch (LifecycleException e) {}
		}
		
		//最后将这个过程通知感兴趣的事件监听程序
		support.firePropertyChange("service", null, service);
	}
 
}

4. Connector组件

负责接收浏览器的发过来的tcp连接请求,处理这个请求并把产生的Request 和 Response对象传给处理这个请求的线程,处理这个请求的线程就是Container 组件要做的事了。

Connector处理一次请求的顺序

Tomcat5 中默认的 Connector 是 Coyote,这个 Connector 是可以选择替换的。Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。

Tomcat5将这个过程更加细化,它将 Connector划分成 Connector、Processor、Protocol, 另外Coyote也定义自己的Request 和 Response对象。
在这里插入图片描述

  • 用户发起一个请求
  • HttpConnector通过initialize()方法,初始化一个ServerSocket;同时初始化一个新的线程,等待新的连接请求
  • HttpConnector创建一个线程池,构建出request、response对象,传递给HttpProcesser
  • HttpProcesser中的所有线程进入等待状态
  • 用户的请求到来,HttpConnector将之前初始化的Socket传递给HttpProcesser
  • HttpProcesser激活所有等待的线程,开始执行run()方法
  • HttpProcesser创建SocketInputStream对象,解析HTTP协议,将header组装到request和response中记录信息
  • HttpProcesser将request和response对象传递给Container
  • Container进行servlet处理
  • Container返回request和response对象给HttpProcesser
  • HttpProcesser通过output.flush()方法,将结果返回给客户
  • socket关闭,request和response对象结束生命

多线程的连接请求

HttpConnector.Start:


public void start() throws LifecycleException {
 
	if (started)
		throw new LifecycleException(sm.getString("httpConnector.alreadyStarted"));
		
	threadName = "HttpConnector[" + port + "]";
	 
	lifecycle.fireLifecycleEvent(START_EVENT,  null);
	 
	started = true;
	 
	 //等待请求,直到HttpProcessor 的 assign 激活线程
	threadStart();
	 
	while (curProcessors < minProcessors) {
		if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
			break;
			
		HttpProcessor processor = newProcessor();
		
		recycle(processor);
	}
 
}

HttpProcessor.assign


synchronized void assign(Socket socket) {

//请求还未到达,线程等待 
	while (available) { 
		try {
			wait(); 
		} catch (InterruptedException e) {}
	}
	 
	 //请求的socket到达
	this.socket = socket;
	 
	available = true;
	 
	 //激活线程,处理请求
	notifyAll();
	 
	if ((debug >= 1) && (socket != null))
		log(" An incoming request is being assigned");
}

HttpProcessor.Run

public void run() {
 
	while (!stopped) {
	 
	 	//得到socket
		Socket socket = await();
					 
		if (socket == null)
			continue;
		 
		 //解析socket
		try {
			process(socket);
		} catch (Throwable t) {			
			log("process.invoke", t); 
		}
		
		connector.recycle(this); 
	}
	
	//唤醒其他等待线程
	synchronized (threadSync) {
		threadSync.notifyAll(); 
	}
 
}

HttpProcessor.process

private void process(Socket socket) {
	 
	boolean ok = true;
	 
	boolean finishResponse = true;
	 
	SocketInputStream input = null;
	 
	OutputStream output = null;
	 
	 //获取输入流
	try {
		input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize());
	} catch (Exception e) {
		log("process.create", e); 
		ok = false; 
	}
	 
	keepAlive = true;
	 
	while (!stopped && ok && keepAlive) {
	 
	finishResponse = true;
	 
	try {
		//设置请求和响应
		
		request.setStream(input);
		 
		request.setResponse(response);
		 
		output = socket.getOutputStream();
		 
		response.setStream(output);
		 
		response.setRequest(request);
		 
		 //设置header
		((HttpServletResponse)response.getResponse()).setHeader("Server", SERVER_INFO);
	 
	} catch (Exception e) {
	 
		log("process.create", e);
		ok = false;
	}
	 
	try {	 
		if (ok){
		 
		 	//准备连接
			parseConnection(socket);
			
			//准备请求	 
			parseRequest(input, output);
				 
			if (!request.getRequest().getProtocol().startsWith("HTTP/0"))
				 
				parseHeaders(input);
				 
			if (http11) {
				 
				ackRequest(output);
									 
				if(connector.isChunkingAllowed())					 				
					response.setAllowChunking(true);	 
			}
		}	 
	}
	 
	try {	 
		//设置header
		((HttpServletResponse)  response).setHeader("Date",  FastHttpDateFormat.getCurrentDate());
		 
		 //具体执行业务
		if (ok) 
			connector.getContainer().invoke(request, response);
	}
	 
	try {
		//关闭流	 
		shutdownInput(input);
				 
		socket.close();
	} 
	catch (IOException e) {} 
	
	catch (Throwable e) { 
		log("process.invoke", e); 
	}
	 
	socket = null;
 
}

5. Container 组件

Container容器的设计用的是典型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、Wrapper,这四个组件不是平行的,而是父子关系:Engine包含 Host,Host 包含 Context,Context 包含 Wrapper。

通常一个 Servlet class 对应一个 Wrapper,如果有多个 Servlet 就可以定义多个 Wrapper,如果有多 个 Wrapper 就要定义一个更高的Container 了,如 Context。

Context 还可以定义在父容器Host中,Host 不是必须的,但是要运行 war 程序,就必须要 Host,因为 war 中必有 web.xml 文件, 这个文件的解析就需要 Host 了。

如果要有多个 Host 就要定义一个 top 容器 Engine 了。而 Engine 没有父容器了,一个 Engine 代表 一个完整的 Servlet 引擎。

处理请求

在这里插入图片描述

StandardEngineValve和 StandardHostValve是 Engine和 Host的默认的 Valve,它们是最后一个Valve,负责将请求传给它们的子容器,以继续往下执行。
在这里插入图片描述
从 Tomcat5 开始,子容器的路由放在了 request 中,request 中保 存了当前请求正在处理的 Host、Context 和 wrapper。

具体接口

Engine 接口

在这里插入图片描述

StandardEngine 标准实现类

添加host:

public void addChild(Container child) {
	//只能添加host
	if (!(child instanceof Host)) 
		throw new IllegalArgumentException(sm.getString("standardEngine.notHost"));
	super.addChild(child);
}
 
//Engine没有父容器
public void setParent(Container container) {
	throw new IllegalArgumentException(sm.getString("standardEngine.notParent"));
}
Host 接口

一个Host代表一个虚拟主机,作用是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。它除了关联子容器外,还有就是保存一个主机应该有的信息。
在这里插入图片描述

StandardHost 标准实现类

实现了ContainerBase、Deployer 接口

Context 接口

具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行Servlet了,简单的 Tomcat可以没有 Engine 和 Host。

Context 的作用是管理它里面的Servlet实例,Tomcat5以前是通过一 个Mapper 类来管理的,Tomcat5 以后这个功能被移到了request 中

StandardContext 标准实现类

启动上下文:

public synchronized void start() throws LifecycleException {

 	//初始化
	if( !initialized ) {	 
		try {
			init();
		} catch( Exception ex ) {
			throw new LifecycleException("Error initializaing ", ex);
		}	 
	}
	 
	lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,   null);
	 
	setAvailable(false);
	 
	setConfigured(false);
	 
	boolean ok = true;
	 
	File configBase = getConfigBase();
	 
	 //设置各种资源属性和管理组件
	if (configBase != null) {
	 
		if (getConfigFile() == null) {
		 
			File file = new File(configBase, getDefaultConfigFile());
		 
			setConfigFile(file.getPath());
		 
			try {
		 
				File appBaseFile = new File(getAppBase());
		 
				if (!appBaseFile.isAbsolute()) 
					appBaseFile = new File(engineBase(), getAppBase());
					
				String appBase = appBaseFile.getCanonicalPath();
		 
				String basePath = (new  File(getBasePath())).getCanonicalPath();
		 
				if (!basePath.startsWith(appBase)) {
		 
					Server server = ServerFactory.getServer();
					 
					((StandardServer)  server).storeContext(this);
				}
		 
			} catch (Exception e) {
			 	log.warn("Error storing config file", e);
			}
		 
		} else {
		 
				try {
			 
					String canConfigFile =  (new File(getConfigFile())).getCanonicalPath();
					
					if (!canConfigFile.startsWith (configBase.getCanonicalPath())) {
					
						File file = new File(configBase, getDefaultConfigFile());
						 
						if (copy(new File(canConfigFile), file)) {
							setConfigFile(file.getPath()); 
						}
					}
			 
			} catch (Exception e) {
				log.warn("Error setting config file", e);	 
			}
		 
		}
	 
	}
	
	//获取子容器	 
	Container children[] = findChildren();

	//启动子容器和 Pipeline	 
	for (int i = 0; i < children.length; i++) {
		if (children[i] instanceof Lifecycle)
		 	((Lifecycle)  children[i]).start();	 
	}
	 
	if (pipeline instanceof Lifecycle)
		((Lifecycle) pipeline).start(); 
}

热部署:设置reloadable 为 true 和应用被修改时,调用 reload 方法,而 reload方法会先调用 stop方法然后再调用 Start 方法,完成Context 的一次重新加载

在 ContainerBase 类中定义的内部类ContainerBackgroundProcessor运行在一个后台线程中,它会周期的执行 run 方法,它的 run 方法会周期调用所有容器的background-Process 方法

public void backgroundProces() {
 
	if (!started)
	 return;
 
	count = (count + 1) % managerChecksFrequency;
	 
	if ((getManager() != null) && (count == 0)) {
	 
		try {	 
			getManager().backgroundProcess();
		} catch ( Exception x ) {
			log.warn("Unable to perform background process on manager",x); 
		}
	 
	}
	 
	if (getLoader() != null) {	 
		if (reloadable && (getLoader().modified())) {	 
			try {
			 
				Thread.currentThread().setContextClassLoader
				 
				(StandardContext.class.getClassLoader());
				 
				reload();
			 
			} finally {
				
				if (getLoader() != null) 
					Thread.currentThread().setContextClassLoader(getLoader().getClassLoader());
			}	 
		}
	 
		if (getLoader() instanceof WebappLoader) 	 
			((WebappLoader)  getLoader()).closeJARs(false);
	}
}
Wrapper 接口

Wrapper 代表一个Servlet,它负责管理一个 Servlet,包括的 Servlet的装载、初始化、执行以及资源回收。Wrapper是最底层的容器

StandardWrapper 标准实现类

StandardWrapper 实现 了拥有一个 Servlet 初始化信息的ServletConfig, Standard-Wrapper 可以直接和Servlet的各种信息打交道

public synchronized Servlet loadServlet() throws ServletException {
	
	Servlet servlet;
 
	try {
 		//装载Servlet		
		ClassLoader classLoader = loader.getClassLoader();
  		
  		Class classClass = null;
 
		servlet = (Servlet) classClass.newInstance();
 		
 		//Servlet可以获得的信息都在StandardWrapperFacade封装
 		//这些信息又是在 StandardWrapper 对象中拿到的
 		// Servlet 可以通过 ServletConfig 拿到有限的容器的信息
		if ((servlet instanceof ContainerServlet) &&(isContainerProvidedServlet(actualClass)  |((Context)getParent()).getPrivileged() )) {
			((ContainerServlet)  servlet).setWrapper(this);
		} 
	
		classLoadTime=(int) (System.currentTimeMillis() -t1); 
	
		try {
			//初始化servlet
			instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,servlet);
	 
			if( System.getSecurityManager() != null) {
		 
				Class[] classType = new Class[]{ServletConfig.class};
				 
				Object[] args = new Object[]{((ServletConfig)facade)};
				 
				SecurityUtil.doAsPrivilege("init",servlet,classType,args); 
			}
			else 
				servlet.init(facade);	 
			
			//默认
			if ((loadOnStartup >= 0) && (jspFile != null)) {
		 
				if( System.getSecurityManager() != null) {
		 
					Class[] classType = new Class[]{ServletRequest.class,ServletResponse.class};
					 
					Object[] args = new Object[]{req, res};
					 
					SecurityUtil.doAsPrivilege("service",servlet,classType,args); 
				}
			 	else 
					servlet.service(req, res);	 
		}
	}
 	 //通知
	instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet);
	
	return servlet; 
}

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/90903407
今日推荐