假设来自客户的请求为:
http://localhost:8080/test/index.jsp请求被发送到本机端口8080,被在那里侦听Copote HTTP/1.1 Connector,然后
1.Connector把该请求交给它所在的Service的Engine来处理,并等待Engine来处理,并等待Engine的回应。
2.Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host。
3.Engine获得请求localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为Engine的默认主机)
4.localhost Host获得请求/test/index.jsp,匹配它所拥有的所有的Context
5.Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“”的Context去处理)
6.path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet。
7.Context匹配到URL Pattern为*.jsp的servlet,对应于JspServlet类,构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法。
8.Context把执行完了之后的HttpServletResponse对象返回给Host
9.Host把HttpServletResponse对象返回给Engine
10.Engine把HttpServletResponse对象返回给Cconnector
11.Connector把HttpServletResponse对象返回给客户browser
在Bootstrap中我们可以看到有如下三个classloader
1.为什么要设计多个类加载器?
如果所有的类都使用一个类加载器来加载,会出现什么问题呢?
假如我们自己编写一个类java.util.Object,他的视线可能有一定危险性或者隐藏的bug。而我们知道Java自带的核心类里面也有java.util.Object,如果我们知道Java自带的核心类里面也有java.util.Object,如果JVM启动的时候先行加载的是我们自己编写的java.util.Object,那么就有可能出现安全问题!
所以Sun(后被Oracle收购)采用了另外一种方式来保证最基本的,也是最核心的功能不会被破坏。你猜的没错,那就是双亲微拍模式!
2.什么是双亲委派模型?
双亲委派模型解决了类错乱加载的问题,也设计得非常精妙。
双亲委派模式对类加载器定义来层级,每个类加载器都有一个父类加载器。在一个类需要加载的时候,首先委派给父类加载器来加载器,而父类加载器又委派给祖父类加载器来加载,以此类推。如果父类以及上面的类加载器都加载不了,那么由当前类加载器来加载,并将被加载的类缓存起来。
所以上述类是这么加载的
Java自带的核心类:由启动类加载器加载。
Java支持的可扩展类:由扩展类加载器加载。
我们自己编写的类:默认由应用程序类加载器或者其子类加载。
为什么Tomcat 的类加载器也不是双亲委派模型?
Java默认的类加载机制是通过双亲委派模型来实现的,而Tomcat实现的方式又和双亲委派模型有所区别。
原因在于一个Tomcat容器允许同时运行多个Web程序,每个Web程序依赖的类又必须是相互隔离的。因此,如果Tomcat使用双亲委派模式来加载类的话,将导致Web程序依赖的类变成共享的。
我们看下几个Container之间的关系:
从上图上,我们可以看出Container顶层也是基于Lifecycle的组件设计得。
1.在设计Container组件层次组件时,上述4个组件分别做什么的呢?为什么要四种组件呢?
engine:表示整个container的servlet引擎,多数情况下包含一个或多个子容器,这些字容器要么是Host,要么是Context实现,或者是其他自定义组。
Host:表示包含多个Context的虚拟主机。
Context:表示一个ServletContext,表示一个web app,他通常包含一个或者多个wrapper。
wrapper:表示一个servlet定义的(如果servlet本身实现了SingleThreadModel,则可能支持多个servlet实例)。
2.结合整体的框架图中上述组件部分,我们看下包含了什么?
很明显,除了四个组件的嵌套关系,Container中还包含了Realm,Cluster,Listeners,Pipleline等支持组件。
这一点,还可以通过相关注释可以看出:
1.Server以及他组件
2.Server后续组件生命周期以及初始化
3.Server的依赖结构
1.Tomcat 希望将Executor也纳入Lifecycle生命周期管理,所以让他实现了Lifecycle接口;
2.引入超时机制:也就是说当work queue满时,会等待指定时间,如果超时将抛出RejectedExcutionException,所以这里增加了一个void execute(Runnable command,long timeout,TimeUnit unit )方法;其实本质上,他构造来JUC中TreadPoolExcutor,通过他调用ThreadPoolExecutor的void execute(Runnable command,long timeout,TimeUnit unit)方法。
责任链模式:管道机制
在软件开发的常接触的责任链模式是FilterChain,他体现在很多软件设计中:
1.比如Spring Security框架中
2.比如HttpServletRequest处理的过滤器中
当一个request过来的时候,需要对这个request做一系列的加工,使用责任链模式可以使每个加工组件化,减少耦合。也可以使用在当一个request过来的时候,需要找到合适的加工方式。当一个加工方式不适合这个request的时候,传递到下一个加工方法,该加工方式再尝试对request加工。
网上找了图,这里我们后文将通过Tomcat请求处理向你阐述。
外观模式:request请求
观察者模式:事件监听
Java中的事件机制的参与者有3种角色
1.Event Source:事件源,发起事件的主体。
2.Event Object:事件状态对象,传递的信息载体,就好比Watcher的update方法的参数,可以是事件源本身,一般作为参数存在listener的方法中。
3.Event Listener:事件监听器,当他监听到event object产生的时候,他就调用相应的方法,进行处理。
其实还有个东西比较重要:事件环境,在这个环境中,可以添加事件监听器,可以产生事件,可以触发事件监听器。
模板方式:Lifecycle
LifecycleBase是使用了状态机+模板模式来实现的。模板方法有下面这几个:
Spring是一个控制反转和面向切面的容器框架。
Spring有七大功能模块:
1.Core
Core模块是Spring的核心类库,Core实现了IOC功能。
2.AOP
Spring AOP模块是Spring的AOP库,提供了AOP(拦截器)机制,并提供常见的拦截器,供用户自定义和配置。
3.orm提供常用ORM框架的管理和支持,hibernate,mybatis等。
4.Dao Spring提供对JDBC的支持,对JDBC进行封装。
5.Web对Struts2的支持。
6.Contrext
Context模块提供框架式的Bean的访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。
7.MVC
MVC模块为Spring提供了一套轻量级的MVC实现,即Spring MVC。
借助Spring实现具有依赖关系的对象之间的解耦。
对象A运行需要对象B,由主动创建变为IOC容器注入,这便是控制反转。
获得依赖对象的过程被反转了,获取依赖对象的过程由自身创建变为由IOC容器注入,这便是依赖注入。
Bean Factory是Spring最底层接口,包含Bean的定义,管理bean的加载,实例化,控制bean的生命周期,特点是每次获取对象时才会创建对象。ApplicationContext是Bean factory的子接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,每次容器启动时就会创建所有对象。ApplicationContext的额外功能:
继承MessageSource,支持国际化;
统一的资源文件访问方式
提供在监听器中注册bean
同时加载多个配置文件
载入多个(有继承关系)上下文,使得每个上下文都专注于一个特定的层次,比如应用的web层。
2.Bean Factory通常是以编程的方式被创建,ApplicationContext可以以声明的方式创建,如使用ContextLoader。
3.Bean Factory和ApplicationContext都支持Bean PostProcesssor,BeanFactoryPostProcessor,但Bean Factory需要手动注册,Application Context则是自动注册。
JavaConfig是Spring3.0新增的概念,就是以注解的形式取代Spring中繁琐的XML文件。Java Config结合了XML的解耦和Java编译时检查的优点。
@Configuration,表示这个类是配置类。
@ComponentScan,相当于xml的
@Bean,相当于xml的
@EnableWebMvc,相当于xml的
@ImportResource,相当于xml的
@PropertySource,用于读取properties配置文件
@Profile,一般用于多环境配置,激活时可用@ActiveProfile(“dev")注解
1.xml配置文件方式
2.基于注解的方式,项目越来越大,基于xml注解配置太麻烦,Spring2.x时代提供了生命bean的注解。
2.1Bean的定义相关注解 @Component,@Controller,@Service,@Repository
2.2Bean色注入相关注解@AutoWire
3.基于Java的方式Spring3.x以后,可以通过Java代码装配@Bean。
Spring容器中的bean可以有5个作用范围:
1.singleton:这种bean范围是默认的,这种范围确保不管接受多少请求,每个容器中只有一个bean实例,单例模式。
2.prototype:为每一个bean提供一个实例。
3.request:在请求bean范围内为每一个来自客户端的网络请求创建一个实例,在请求完毕后,bean会失效并被垃圾回收器回收。
4.session:为每个session创建一个实例,session过期后,bean会随之消失。
5.global session:global session和Portlet应用相关。当你的应用部署在Portlet
容器中工作时,他包含了很多portlet。如果你想要声明让所有的porlet公用全局的存储变量的话,那么全局变量需要存储在global session中。
在Spring框架中,无论何时bean被使用时,当仅被调用一个属性。可以将这个bean声明为内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现。
比如,在我们的应用程序中,一个Customer类引用了一个Person类,我们要做的是创建一个Person实例,然后在Customer内部使用。
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。
但实际上,大部分的Spring bean并没有可变的状态,所以在某种程度上说Spring的单例bean时线程安全的。如果你的bean有多种状态的话,比如view model,需要自行保证线程安全啦。
最浅显的解决方案就是将多态bean的作用域由singleton变更为propertype。
Spring支持IOC,自动装配不用实例化,直接从bean容器中取。
1.配置在xml中
2.@Autowired自动装配
要使用@Autowired,需要注册AutowiredAnnotationBeanPostProcessor,可以有以下两种方式来实现:
1.引入配置文件中的下引用
2.在bean配置文件中直接引入AutowiredAnnotationBeanProcessor