tomcat(15)Digester库

【0】README
0.1)本文部分文字描述转自 “how tomcat works”,旨在学习 “tomcat(15)Digester库” 的基础知识;
2)problem+solution:
2.1)problem:如下面的代码,Bootstrap类实例化连接器,servlet容器,Wrapper容器和其它组件,如设置连接器的关联顶层容器,通过set方法将它们联系起来;如监听器组件通过addLifecycleListener来设置等等。这种配置应用程序的方法有一个明显的缺点:即所有的配置都必须硬编码。调整组件配置或属性值都必须要重新编译Bootstrap类。
2.2)solution:Tomcat使用了一种更加优雅的配置方式,即使用一个名为server.xml 的XML 文档来对应用程序进行配置。server.xml文件中的每个元素都会转换为一个java 对象,元素的属性会用于设置java对象 的属性。这样,就可以通过简单地编辑 server.xml文件来修改tomcat的配置了;
看个荔枝)如server.xml文件中的 Context元素表示一个Context实例:<context/>;若要为 Context实例设置path属性和 docBase属性,使用这样的配置:
<context docBase="myApp" path="/myApp" />
Attention)
A1)tomcat使用了开源库Digester来将XML 文档中的元素转换成 java 对象;(干货——开源库Digester的作用)
A2)用来配置web 应用程序的XML 文件的名称是 web.xml,该文件位于web 应用程序的WEB-INF 目录下;(干货——引入了大家熟悉的web.xml)
public final class Bootstrap1 {public static void main(String[] args) {//invoke: http://localhost:8080/app1/Primitive or http://localhost:8080/app1/ModernSystem.setProperty("catalina.base", System.getProperty("user.dir"));Connector connector = new HttpConnector();Wrapper wrapper1 = new StandardWrapper();wrapper1.setName("Primitive");//wrapper1.setServletClass("servlet.PrimitiveServlet");wrapper1.setServletClass("PrimitiveServlet");Wrapper wrapper2 = new StandardWrapper();wrapper2.setName("Modern");//wrapper2.setServletClass("servlet.ModernServlet");wrapper2.setServletClass("ModernServlet");Context context = new StandardContext();// StandardContext's start method adds a default mappercontext.setPath("/app1");context.setDocBase("app1");context.addChild(wrapper1);context.addChild(wrapper2);LifecycleListener listener = new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);Host host = new StandardHost();host.addChild(context);host.setName("localhost");host.setAppBase("webapps");Loader loader = new WebappLoader();context.setLoader(loader);// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");connector.setContainer(host);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) host).start(); // 与以往的Bootstrap.java不同的是,这里是host.start() 而不是 context.start()// make the application wait until we press a key.System.in.read();((Lifecycle) host).stop();}catch (Exception e) {e.printStackTrace();}}
}
【1】Digester库
1)intro:Digester是 Apache 下Jakarta项目下的子项目Commons项目下的一个开源项目;
2)Digester API包含3个包:三者都被打包到 commons-digester.jar 文件中;(package list)
package1)org.apache.commons.digester:该包提供了基于规则的,可处理任意XML 文档的类;
package2)org.apache.commons.digester.rss:该包包含一些可以用来解析与很多新闻源使用的RSS(Rich Site Summary,富站点摘要)格式兼容的XML文档的例子;
package3)org.apache.commons.digester.xmlrules:该包为 Digester库提供了一些基于XML规则的定义;

【1.1】Digester类
1)intro:Digester类可用于解析XML 文档;对于XMl 文档中的每个元素,Digester对象都会检查它是否要做事先预定义的事件。在调用Digester.parse()方法之前,需要先定义好Digester对象执行哪些动作;
2)如何定义在Digester对象遇到某个XMl 元素时它应该执行什么动作呢?—— 程序员先定义好模式,然后将每个模式与一条或多条规则相关联。XML 文档中根元素的模式与元素的名字相同。(干货——引入了模式,且XML 文档中根元素的模式与元素的名字相同
3)看个荔枝:考虑下面的 XML文档:(example.xml)
<?xml version=1.0" encoding="ISO-8859-1">
<employee firstName="pacoson" lastName="xiao"><office><address streetName="Wellington Street" streetNumber="110" /></office>
</employee>
对上述代码的分析(Analysis):
A1)该XML文档中的根元素是 employee,employee元素有一个模式, 名为 employee;
A2)office元素是 employee元素的子元素,子元素的模式是由该元素的父元素的模式再加上 “/” 符号,以及该元素名称拼接而成的,所以office元素的模式是  employee/office;(干货——我们这就了解了如何从XML 文档中推导出元素的模式)
4)下面讨论一下规则(rules):(干货——规则的定义,非常重要)
rule1)一条规则指明了当Digester 对象遇到了某个特殊的模式时要执行的一个或多个动作;规则是 org.apache.commons.digester.Rule 类;Digester类可以包含0个或多个对象;
rule2)Rule类有begin()方法 和 end() 方法。在开始标签调用start()方法,结束标签调用 end() 方法;

5)自定义自己的规则:包括创建对象和设置属性值等的规则;(干货——自定义规则包括创建对象+设置属性+调用方法+创建对象间的关系+验证 XML 文档)
5.1)创建对象:若想要Digester对象在遇到某个特殊字符时创建对象,则需要调用其 addObjectCreate()方法,该方法有4个重载版本;(干货——引入addObjectCreate()方法)
public void addObjectCreate(String pattern, String className) {addRule(pattern,  new ObjectCreateRule(className)); 
}   
public void addObjectCreate(String pattern, Class clazz) {addRule(pattern, new ObjectCreateRule(clazz));
}
public void addObjectCreate(String pattern, String className,  String attributeName) { addRule(pattern,  new ObjectCreateRule(className, attributeName)); 
}
public void addObjectCreate(String pattern,  String attributeName, Class clazz) { addRule(pattern,  new ObjectCreateRule(attributeName, clazz)); 
}
对上述代码的分析(Analysis):
A1)需要传入一个模式和一个Class对象或类名来调用该方法;
看个荔枝) 如我们想让Digester对象在遇到模式employee 时,创建一个 mydiy.Employee 对象,则使用下面的代码来调用 addObjectCreate()方法:
digester.addObjectCreate("employee", "mydiy.Employee.class");
或者
digester.addObjectCreate("employee", "mydiy.Employee");
A2)addObjecdtCreate()方法的最后两个重载版本允许在xml 文档中定义类的名字,而无须将其作为参数传入,这使得类名可以在运行时决定;在上述最后两个重载方法中,参数 attributeName参数指明了 XML 元素的属性的名字,该属性包含了将要实例化的类的名字;
看个荔枝)
step1)添加创建对象的一条规则:digester.addObjectCreate("employee",null,"className");(属性名是 className);
step2)传入XML 元素中的类名: <employee firstName="pacoson" lastName="xiao" className="mydiy.employee">;如果employee元素包含 className属性,那么该属性指定的值会用来作为待实例化的类的名字,如果没有包含 className属性,则会使用默认的类名;(干货——显然意思是说Emplyee类需要依赖 名为className的类对象)
Attention)addObjectCreate()方法创建的对象会被压入到一个内部栈中;

5.2)设置属性:addSetProperties()方法,该方法可以使用Digester对象为创建的对象设置属性。该方法的重载版本有:(干货——引入addSetProperties()方法)
 public void addSetProperties(String pattern) {addRule(pattern,  new SetPropertiesRule()); }public void addSetProperties( String pattern, String attributeName, String propertyName) { addRule(pattern, new SetPropertiesRule(attributeName, propertyName)); }public void addSetProperties(String pattern, String [] attributeNames, String [] propertyNames) { addRule(pattern,  new SetPropertiesRule(attributeNames, propertyNames)); }
看个荔枝)考虑下面的代码:
digester.addObjectCreate("employee", "mydiy.Employee");
digester.addSetProperties("employee");
对以上代码的分析(Analysis):
A1)上面的Digester有两个Rule 对象,分别用来创建对象和设置属性,他们都是通过employee模式触发的。而Rule对象按照其添加到Digester实例中的顺序逐个执行。
A2)对于下面XMl 文档中的employee 元素(该元素匹配 employee模式): <employee firstName="pacoson", lastName="Xiao">;依据Digester的第一条rule,会创建 diy.Employee类的一个实例,依据第二条Rule,调用已经实例化的Employee.setFirstName() and Employee.setLastName(),分别传入pacoson 和 Xiao 来设置属性;
5.3)调用方法:Digetser类允许通过添加一条Rule,使Digester 在遇到与该规则相关联的模式时调用内部栈最顶端对象的 某个方法。这需要用到 addCallMethod()方法,重载版本如下:(干货——引入addCallMethod()方法)
public void addCallMethod(String pattern, String methodName) {addRule( pattern,  new CallMethodRule(methodName)); }public void addCallMethod(String pattern, String methodName, int paramCount) { addRule(pattern, new CallMethodRule(methodName, paramCount)); }public void addCallMethod(String pattern, String methodName, int paramCount, String paramTypes[]) { addRule(pattern, new CallMethodRule( methodName,paramCount,paramTypes));}public void addCallMethod(String pattern, String methodName,int paramCount, Class paramTypes[]) {addRule(pattern,new CallMethodRule(methodName,paramCount,paramTypes));}
5.4)创建对象之间的关系(干货——Digester实例有一个内部栈,用于临时存储创建的对象)(干货——引入addSetNext()方法)
5.4.1)addSetNext()方法:若栈中有两个对象,那么该方法会调用第1个对象的指定方法并将第2个对象作为参数传入该方法来创建第1个对象和第2个对象的关系;
public void addSetNext(String pattern, String methodName) {addRule(pattern,new SetNextRule(methodName));}public void addSetNext(String pattern, String methodName,String paramType) {addRule(pattern,new SetNextRule(methodName, paramType));}
对以上代码的分析(Analysis):参数pattern 指明了触发该规则的具体模式,参数methodName 是将要调用的第1个对象的方法的名称。模式是如下格式:firstObject/secondObject;
看个荔枝)如何创建对象间的关系:
step1)创建两个对象;
digester.addObjectCreate("employee", "mydiy.Employee");
digester.addObjectCreate("employee/office", "mydiy.Office");
step2)创建对象间的关系:需要另外定义一条规则,使用 addSetNext()方法来建立关系(调用addOffice()方法建立关系):
digetster.addSetNext("employee/office", 'addOffice');
5.5)验证XML文档:Digester.validating属性指明了是否要对 XML 文档进行有效性验证。默认case下,其为false;setValidating()方法可以设置其值;(干货——引入setValidating()方法)

【1.2】Digester库荔枝1(如何使用 Digester库动态地创建对象,并设置相应的属性)
1)源代码
public class Test01 {public static void main(String[] args) {String path = System.getProperty("user.dir") + File.separator + "src";File file = new File(path, "employee1.xml");Digester digester = new Digester();// add rules (为模式 employee 添加3条规则)digester.addObjectCreate("employee","com.tomcat.chapter15.digestertest.Employee");digester.addSetProperties("employee");digester.addCallMethod("employee", "printName");try {Employee employee = (Employee) digester.parse(file);System.out.println("First name : " + employee.getFirstName());System.out.println("Last name : " + employee.getLastName());} catch (Exception e) {e.printStackTrace();}}
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<employee firstName="Brian" lastName="May">
</employee>
2)console info
Creating Employee
Setting firstName : Brian
Setting lastName : May
My name is Brian May
First name : Brian
Last name : May
3)info analysis:当调用parse()方法时,它会打开指定的xml 文档,开始解析它;(干货——当调用parse()方法时,它会打开指定的xml 文档,开始解析它,只需要parse方法就可以创建根元素(模式)的相应对象和其关联对象)
step1)Digester类查看 employee 元素的开始标签,这会触发与 employee模式关联的3条规则,按照其被添加到 Digester 对象中的顺序逐个执行;
step2)第一条规则用于创建Employee对象,调用构造函数,打印Creating Employee;
step3)第二条规则设置 Employee对象的属性,在employee 元素中包含两个属性:分别是 firstName 和 lastName, 这会调用调用的set方法,打印 Setting firstName : Brian  Setting lastName : May;
step4第三条规则调用 Employee.printName()方法,打印M y name is Brian May;
【1.3】Digester库荔枝2(如何创建两个对象,并建立他们的关系)
1)源代码
public class Test02 {public static void main(String[] args) {String path = System.getProperty("user.dir") + File.separator + "src";File file = new File(path, "employee2.xml");Digester digester = new Digester();// add rules,添加规则(key)digester.addObjectCreate("employee","com.tomcat.chapter15.digestertest.Employee");digester.addSetProperties("employee");digester.addObjectCreate("employee/office","com.tomcat.chapter15.digestertest.Office");digester.addSetProperties("employee/office");digester.addSetNext("employee/office", "addOffice");digester.addObjectCreate("employee/office/address","com.tomcat.chapter15.digestertest.Address");digester.addSetProperties("employee/office/address");digester.addSetNext("employee/office/address", "setAddress");try {Employee employee = (Employee) digester.parse(file);ArrayList offices = employee.getOffices();Iterator iterator = offices.iterator();System.out.println("-------------------------------------------------");while (iterator.hasNext()) {Office office = (Office) iterator.next();Address address = office.getAddress();System.out.println(office.getDescription());System.out.println("Address : " + address.getStreetNumber()+ " " + address.getStreetName());System.out.println("--------------------------------");}} catch (Exception e) {e.printStackTrace();}}
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<employee firstName="Freddie" lastName="Mercury"><office description="Headquarters"><address streetName="Wellington Avenue" streetNumber="223"/></office><office description="Client site"><address streetName="Downing Street" streetNumber="10"/></office>
</employee>
2)console info
Creating Employee
Setting firstName : Freddie
Setting lastName : Mercury
..Creating Office
..Setting office description : Headquarters
....Creating Address
....Setting streetName : Wellington Avenue
....Setting streetNumber : 223
..Setting office address : ....223 Wellington Avenue
Adding Office to this employee
..Creating Office
..Setting office description : Client site
....Creating Address
....Setting streetName : Downing Street
....Setting streetNumber : 10
..Setting office address : ....10 Downing Street
Adding Office to this employee
-------------------------------------------------
Headquarters
Address : 223 Wellington Avenue
--------------------------------
Client site
Address : 10 Downing Street
--------------------------------
Attention)本文不对 荔枝2的实例程序进行分析了,结合荔枝1的分析,理解这个不难;

【1.4】org.apache.commons.digester.Rule类(最重要的方法start() + end())
1)intro to begin() :当Digester实例 遇到某个XML 元素的开始标签时,会调用它所包含的匹配Rule 对象的begin()方法:
 
public void begin(Attributes attributes) throws Exception {;  // The default implementation does nothing}  public void begin(String namespace, String name, Attributes attributes)throws Exception {begin(attributes);}
2)intro to end():当Digester实例 遇到某个XML 元素的结束标签时,会调用它所包含的匹配Rule 对象的end()方法:
public void end() throws Exception {;  // The default implementation does nothing}  public void end(String namespace, String name)throws Exception {end();}
3)Digester对象是如何完成这些工作的? 当调用Digester.addObjectCreate()方法,addCallMethod()方法,addSetNext()方法或其他方法时,都会间接地调用 Digester.addRule()方法;
 public void addRule(String pattern, Rule rule) {rule.setDigester(this);getRules().add(pattern, rule);}
4)再次review Digester.addObjectCreate()方法的重载version:
public void addObjectCreate(String pattern, String className) {addRule(pattern,  new ObjectCreateRule(className)); 
}   
public void addObjectCreate(String pattern, Class clazz) {addRule(pattern, new ObjectCreateRule(clazz));
}
public void addObjectCreate(String pattern, String className,  String attributeName) { addRule(pattern,  new ObjectCreateRule(className, attributeName)); 
}
public void addObjectCreate(String pattern,  String attributeName, Class clazz) { addRule(pattern,  new ObjectCreateRule(attributeName, clazz)); 
}
对以上代码的分析(Analysis):
A1)这4个重载方法都调用了addRule()方法,ObjectCreateRule类 是 Rule 类的子类,该类的实例都作为 addRule()方法的参数;
A2)ObjectCreateRule.start()方法 和 ObjectCreateRule.end()方法的实现如下:
 public void begin(Attributes attributes) throws Exception { //org.apache.commons.digester.ObjectCreateRule.begin().// Identify the name of the class to instantiateString realClassName = className;if (attributeName != null) {String value = attributes.getValue(attributeName);if (value != null) {realClassName = value;}}if (digester.log.isDebugEnabled()) {digester.log.debug("[ObjectCreateRule]{" + digester.match +"}New " + realClassName);}// Instantiate the new object and push it on the context stackClass clazz = digester.getClassLoader().loadClass(realClassName);Object instance = clazz.newInstance();digester.push(instance); //highlight line.}public void end() throws Exception {Object top = digester.pop(); //highlight line.if (digester.log.isDebugEnabled()) {digester.log.debug("[ObjectCreateRule]{" + digester.match +"} Pop " + top.getClass().getName());}}
对以上代码的分析(Analysis):begin()方法的最后三行会创建Digester对象的一个实例,并将其压入到 Digester对象的内部栈中。end()方法 会将内部站的栈顶元素弹出;
【1.5】Digester库荔枝3:使用RuleSet(org.apache.commons.digester.RuleSet)
1)要向Digester实例添加 Rule对象,还可以调用其 addRuleSet()方法;
2)Rule对象集合是 org.apache.commons.digester.RuleSet接口的实例,该接口定义了两个方法,分别是 addRuleInstance()方法 和 getNamespaceURI()方法;
2.1)addRuleInstance方法:将在当前RuleSet 中的Rule对象的集合作为该方法的参数添加到 Digester实例中;
2.2)getNamespaceURI方法:返回将要应用在 RuleSet中所有Rule 对象的命名空间的URI;
3)RuleSetBase implements RuleSet。RuleSetBase 是一个抽象类,提供了getNamespaceURI的实现,你只需要提供addRuleInstances()方法的实现就可以了;
public abstract class RuleSetBase implements RuleSet {   protected String namespaceURI = null;    public String getNamespaceURI() {return (this.namespaceURI);}    public abstract void addRuleInstances(Digester digester);
}
4)测试用例
public class Test03 {public static void main(String[] args) {String path = System.getProperty("user.dir") + File.separator + "src";File file = new File(path, "employee2.xml");Digester digester = new Digester();digester.addRuleSet(new EmployeeRuleSet());try {Employee employee = (Employee) digester.parse(file);ArrayList offices = employee.getOffices();Iterator iterator = offices.iterator();System.out.println("-------------------------------------------------");while (iterator.hasNext()) {Office office = (Office) iterator.next();Address address = office.getAddress();System.out.println(office.getDescription());System.out.println("Address : " + address.getStreetNumber()+ " " + address.getStreetName());System.out.println("--------------------------------");}} catch (Exception e) {e.printStackTrace();}}
}
public class EmployeeRuleSet extends RuleSetBase {public void addRuleInstances(Digester digester) {// add rulesdigester.addObjectCreate("employee","com.tomcat.chapter15.digestertest.Employee");digester.addSetProperties("employee");digester.addObjectCreate("employee/office","com.tomcat.chapter15.digestertest.Office");digester.addSetProperties("employee/office");digester.addSetNext("employee/office", "addOffice");digester.addObjectCreate("employee/office/address","com.tomcat.chapter15.digestertest.Address");digester.addSetProperties("employee/office/address");digester.addSetNext("employee/office/address", "setAddress");}
}
Attention)参考前面做的分析,应该不难;

【2】ContextConfig类
1)在前面章节中,我们使用了 SimpleContextConfig 作为 StandardContext的监听器:其唯一用途是设置configure变量,这样StandardContext.start()方法才能继续执行;
public class SimpleContextConfig implements LifecycleListener {public void lifecycleEvent(LifecycleEvent event) {if (Lifecycle.START_EVENT.equals(event.getType())) {Context context = (Context) event.getLifecycle();context.setConfigured(true);}}
}
2)而tomcat 的标准监听器:是 org.apache.catalina.startup.ContextConfig类的实例;(干货——Tomcat标准监听器)
3)ContextConfig会执行很多对 StandardContext实例来说必不可少的任务。如,与某个 StandardContext实例关联的 ContextConfig 实例会安装一个验证器阀到 StandardContext的管道中。它还会添加一个许可阀(org.apache.catalina.valves.CertificateValve)到管道对象中;
4)更重要的是:ContextConfig类的实例还要读取和解析默认的 web.xml 文件和应用程序自定义的web.xml文件,并将xml 元素转换为 java 对象;(干货——引入了默认的和自定义的web.xml文件)
4.1)默认的web.xml:位于 CATALINA_HOME/conf 目录中,其中定义并映射了很多默认的 servlet,配置了很多 MIME类型文件的映射,定义了默认的session超时时间,以及定义了欢迎文件的列表;
4.2)应用程序的web.xml文件:位于 WEB-INF 目录中;
5)以上两个文件都不是必须的,即使这两个文件没有找到, ContextConfig 实例仍然会继续执行;
6)ContextConfig实例:会为每个 servlet元素创建一个 StandardWrapper类;(干货——ContextConfig的作用)
7)在BootStrap程序中,需要实例化一个 ContextConfig类,并调用 addLifecycleListener方法;
LifecycleListener listener = new ContextConfig();((Lifecycle) context).addLifecycleListener(listener);
7.1)在启动 StandardContext实例时,会触发以下事件(events):
event1)BEFORE_START_EVENT;
event2)START_EVENT;
event3)AFTER_START_EVENT;
7.2)当程序停止时,会触发以下事件:
event1)BEFORE_STOP_EVENT;
event2)STOP_EVENT;
event3)AFTER_STOP_EVENT;
8)ContextConfig 实例会对两种事情做出相应:分别是START_EVENT and STOP_EVENT。每次 StandardContext实例触发事件时,会调用 ContextConfig.lifecycleEvent()方法;
public void lifecycleEvent(LifecycleEvent event) { //org.apache.catalina.startup.ContextConfig.lifecycleEvent().// Identify the context we are associated withtry {context = (Context) event.getLifecycle();if (context instanceof StandardContext) {int contextDebug = ((StandardContext) context).getDebug();if (contextDebug > this.debug)this.debug = contextDebug;}} catch (ClassCastException e) {log(sm.getString("contextConfig.cce", event.getLifecycle()), e);return;}// Process the event that has occurredif (event.getType().equals(Lifecycle.START_EVENT))start(); //highlight line.else if (event.getType().equals(Lifecycle.STOP_EVENT))stop(); //highlight line.}
8.1)start()方法
(干货——start方法会调用 defaultConfig() and applicationConfig()方法,两者分别用于读取和解析默认的web.xml 和 应用程序自定义的 web.xml
private synchronized void start() {  //org.apache.catalina.startup.ContextConfig.start().if (debug > 0)log(sm.getString("contextConfig.start"));context.setConfigured(false);ok = true;// Set properties based on DefaultContextContainer container = context.getParent();if( !context.getOverride() ) {if( container instanceof Host ) {((Host)container).importDefaultContext(context);container = container.getParent();}if( container instanceof Engine ) {((Engine)container).importDefaultContext(context);}}// Process the default and application web.xml filesdefaultConfig(); // highlight line.applicationConfig(); // highlight line.if (ok) {validateSecurityRoles();}// Scan tag library descriptor files for additional listener classesif (ok) {try {tldScan();} catch (Exception e) {log(e.getMessage(), e);ok = false;}}// Configure a certificates exposer valve, if requiredif (ok)certificatesConfig();// Configure an authenticator if we need oneif (ok)authenticatorConfig();// Dump the contents of this pipeline if requestedif ((debug >= 1) && (context instanceof ContainerBase)) {log("Pipline Configuration:");Pipeline pipeline = ((ContainerBase) context).getPipeline();Valve valves[] = null;if (pipeline != null)valves = pipeline.getValves();if (valves != null) {for (int i = 0; i < valves.length; i++) {log("  " + valves[i].getInfo());}}log("======================");}// Make our application available if no problems were encounteredif (ok)context.setConfigured(true);else {log(sm.getString("contextConfig.unavailable"));context.setConfigured(false);}}
【2.1】 defaultConfig()方法
1)intro: 该方法负责读取并解析位于 CATALINA_HOME/conf目录下的默认web.xml 文件;
 private void defaultConfig() {  //org.apache.catalina.startup.ContextConfig.defaultConfig().// Open the default web.xml file, if it existsFile file = new File(Constants.DefaultWebXml);// public static final String DefaultWebXml = "conf/web.xml";if (!file.isAbsolute())file = new File(System.getProperty("catalina.base"),Constants.DefaultWebXml);FileInputStream stream = null;try {stream = new FileInputStream(file.getCanonicalPath());stream.close();stream = null;} catch (FileNotFoundException e) {log(sm.getString("contextConfig.defaultMissing"));return;} catch (IOException e) {log(sm.getString("contextConfig.defaultMissing"), e);return;}// Process the default web.xml file (锁定webDigester变量,并解析默认的 web.xml 文件)synchronized (webDigester) {try {InputSource is =new InputSource("file://" + file.getAbsolutePath());stream = new FileInputStream(file);is.setByteStream(stream);webDigester.setDebug(getDebug());if (context instanceof StandardContext)((StandardContext) context).setReplaceWelcomeFiles(true);webDigester.clear();webDigester.push(context);webDigester.parse(is);webDigester.push(null); // 解析结束.} catch (SAXParseException e) {log(sm.getString("contextConfig.defaultParse"), e);log(sm.getString("contextConfig.defaultPosition","" + e.getLineNumber(),"" + e.getColumnNumber()));ok = false;} catch (Exception e) {log(sm.getString("contextConfig.defaultParse"), e);ok = false;} finally {try {if (stream != null) {stream.close();}} catch (IOException e) {log(sm.getString("contextConfig.defaultClose"), e);}}}}
【2.2】applicationConfig()方法
1)intro:该方法处理的是 应用程序自定义的web.xml,位于 WEB-INF 目录中;
private void applicationConfig() {  //org.apache.catalina.startup.ContextConfig.applicationConfig().// Open the application web.xml file, if it existsInputStream stream = null;ServletContext servletContext = context.getServletContext();if (servletContext != null)stream = servletContext.getResourceAsStream(Constants.ApplicationWebXml); //  public static final String ApplicationWebXml = "/WEB-INF/web.xml";if (stream == null) {log(sm.getString("contextConfig.applicationMissing"));return;}// Process the application web.xml filesynchronized (webDigester) {try {URL url =servletContext.getResource(Constants.ApplicationWebXml);InputSource is = new InputSource(url.toExternalForm());is.setByteStream(stream);webDigester.setDebug(getDebug());if (context instanceof StandardContext) {((StandardContext) context).setReplaceWelcomeFiles(true);}webDigester.clear();webDigester.push(context);webDigester.parse(is);webDigester.push(null);} catch (SAXParseException e) {log(sm.getString("contextConfig.applicationParse"), e);log(sm.getString("contextConfig.applicationPosition","" + e.getLineNumber(),"" + e.getColumnNumber()));ok = false;} catch (Exception e) {log(sm.getString("contextConfig.applicationParse"), e);ok = false;} finally {try {if (stream != null) {stream.close();}} catch (IOException e) {log(sm.getString("contextConfig.applicationClose"), e);}}}}

【2.3】创建 Web Digester
1)在ContextConfig 类中,使用变量 webDigester来引用一个 Digester类型的对象;
private static Digester webDigester = createWebDigester();private static Digester createWebDigester() {  //org.apache.catalina.startup.ContextConfig.createWebDigester().URL url = null;Digester webDigester = new Digester();webDigester.setValidating(true);url = ContextConfig.class.getResource(Constants.WebDtdResourcePath_22);webDigester.register(Constants.WebDtdPublicId_22,url.toString());url = ContextConfig.class.getResource(Constants.WebDtdResourcePath_23);webDigester.register(Constants.WebDtdPublicId_23,url.toString());webDigester.addRuleSet(new WebRuleSet()); // highlight line.return (webDigester);}
2)这个Digester对象用来解析默认的 web.xml 文件和应用程序自定义的 web.xml 文件。在调用了 createWebDigester() 方法时会添加用来处理 web.xml 文件的规则;(干货——在调用了 createWebDigester() 方法时会添加用来处理 web.xml 文件的规则,什么是规则,你懂的,前面已经详细介绍了Rule)
Attention)
A1)createWebDigester()方法调用了变量webDigester的 addRuleSet()方法,传入了一个 org.apache.catalina.startup.WebRuleSet 类型的对象作为参数;
A2)WebRuleSet 类是 org.apache.commons.digester.RuleSetBase的子类;
public class WebRuleSet extends RuleSetBase { //org.apache.catalina.startup.WebRuleSet
A3)org.apache.catalina.startup.WebRuleSet的定义代码见 文末,特别要注意其addRuleInstances()方法,其添加了很多规则集合;(干货——addRuleInstances()方法添加了很多规则集合)

【3】应用程序(本测试用例重在说明如何使用ContextConfig实例作为一个监听器来配置StandardContext对象) 
Attention)通过以下实例,你会发现,这与之前的Bootstrap 测试用例大有不同,以前是显式地创建StandardWrapper(创建具体的servlet实例),而下面的测试用例采用Digester从 xml 中读取 servlet的配置信息创建servlet实例,这就是为什么本文之前讲那么多 Digester库的原因;
1)测试用例
public final class Bootstrap {// invoke: http://localhost:8080/app1/Modern or // http://localhost:8080/app2/Primitive// note that we don't instantiate a Wrapper here,// ContextConfig reads the WEB-INF/classes dir and loads all servlets.public static void main(String[] args) {System.setProperty("catalina.base", System.getProperty("user.dir"));Connector connector = new HttpConnector();Context context = new StandardContext();// StandardContext's start method adds a default mappercontext.setPath("/app1");context.setDocBase("app1");LifecycleListener listener = new ContextConfig();((Lifecycle) context).addLifecycleListener(listener);Host host = new StandardHost();host.addChild(context);host.setName("localhost");host.setAppBase("webapps");Loader loader = new WebappLoader();context.setLoader(loader);connector.setContainer(host);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) host).start();Container[] c = context.findChildren();int length = c.length;for (int i=0; i<length; i++) {Container child = c[i];System.out.println(child.getName());}// make the application wait until we press a key.System.in.read();((Lifecycle) host).stop();}catch (Exception e) {e.printStackTrace();}}
}
Supplement)本文习惯性地总结了上述测试用例的调用过程,如下:


S0)上述调用过程涉及到的变量ApplicationWebXml 和 DefaultWebXml,其值为:
 public static final String ApplicationWebXml = "/WEB-INF/web.xml";public static final String DefaultWebXml = "conf/web.xml"; // both of them are defined in org.apache.catalina.startup.Constant;
S1)自定义的web.xml如下所示:该文件的文件路径为  System.getProperty("user.dir")\webapps\app1\WEB-INF;
S2)tomcat使用了开源库Digester来将XML 文档中的元素转换成 java 对象,触发相应规则如调用设置器来配置StandardContext的子容器(StandardWrapper包装了servlet)(干货——具体的规则包含在 WebRuleSet类中,见文末)
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE web-appPUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><servlet><servlet-name>Modern</servlet-name><servlet-class>ModernServlet</servlet-class></servlet><servlet><servlet-name>Primitive</servlet-name><servlet-class>PrimitiveServlet</servlet-class></servlet><servlet-mapping><servlet-name>Modern</servlet-name><url-pattern>/Modern</url-pattern></servlet-mapping><servlet-mapping><servlet-name>Primitive</servlet-name><url-pattern>/Primitive</url-pattern></servlet-mapping>
</web-app>
2)console info
E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common.
jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/commons-digester.jar;lib/catalina.jar;lib/commons-logging.jar;lib/commons-beanutils.jar;E
:\bench-cluster\cloud-data-preprocess\HowTomcatWoks\webroot com.tomcat.chapter15.startup.Bootstrap
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
WebappLoader[/app1]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\localhost\app1
WebappLoader[/app1]: Deploy class files /WEB-INF/classes to E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\webapps\app1\WEB-INF\classes
ContextConfig[/app1]: Missing default web.xml, using application web.xml only
StandardManager[/app1]: Seeding random number generator class java.security.SecureRandom
StandardManager[/app1]: Seeding of random number generator has been completed
Primitive
Modern
StandardHost[localhost]: MAPPING configuration error for request URI /Modern/app1/Modern
StandardHost[localhost]: MAPPING configuration error for request URI /favicon.ico
ModernServlet -- init
StandardHost[localhost]: MAPPING configuration error for request URI /favicon.ico
3)访问结果




public class WebRuleSet extends RuleSetBase { //org.apache.catalina.startup.WebRuleSetprotected String prefix = null;  public WebRuleSet() {  this("");}  public WebRuleSet(String prefix) {super();this.namespaceURI = null;this.prefix = prefix;}  public void addRuleInstances(Digester digester) { // highlight.digester.addRule(prefix + "web-app",new SetPublicIdRule(digester, "setPublicId"));digester.addCallMethod(prefix + "web-app/context-param","addParameter", 2);digester.addCallParam(prefix + "web-app/context-param/param-name", 0);digester.addCallParam(prefix + "web-app/context-param/param-value", 1);digester.addCallMethod(prefix + "web-app/display-name","setDisplayName", 0);digester.addRule(prefix + "web-app/distributable",new SetDistributableRule(digester));digester.addObjectCreate(prefix + "web-app/ejb-local-ref","org.apache.catalina.deploy.ContextLocalEjb");digester.addSetNext(prefix + "web-app/ejb-local-ref","addLocalEjb","org.apache.catalina.deploy.ContextLocalEjb");digester.addCallMethod(prefix + "web-app/ejb-local-ref/description","setDescription", 0);digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link","setLink", 0);digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name","setName", 0);digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type","setType", 0);digester.addCallMethod(prefix + "web-app/ejb-local-ref/local","setLocal", 0);digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home","setHome", 0);digester.addObjectCreate(prefix + "web-app/ejb-ref","org.apache.catalina.deploy.ContextEjb");digester.addSetNext(prefix + "web-app/ejb-ref","addEjb","org.apache.catalina.deploy.ContextEjb");digester.addCallMethod(prefix + "web-app/ejb-ref/description","setDescription", 0);digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link","setLink", 0);digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name","setName", 0);digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type","setType", 0);digester.addCallMethod(prefix + "web-app/ejb-ref/home","setHome", 0);digester.addCallMethod(prefix + "web-app/ejb-ref/remote","setRemote", 0);digester.addObjectCreate(prefix + "web-app/env-entry","org.apache.catalina.deploy.ContextEnvironment");digester.addSetNext(prefix + "web-app/env-entry","addEnvironment","org.apache.catalina.deploy.ContextEnvironment");digester.addCallMethod(prefix + "web-app/env-entry/description","setDescription", 0);digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name","setName", 0);digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type","setType", 0);digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value","setValue", 0);digester.addObjectCreate(prefix + "web-app/error-page","org.apache.catalina.deploy.ErrorPage");digester.addSetNext(prefix + "web-app/error-page","addErrorPage","org.apache.catalina.deploy.ErrorPage");digester.addCallMethod(prefix + "web-app/error-page/error-code","setErrorCode", 0);digester.addCallMethod(prefix + "web-app/error-page/exception-type","setExceptionType", 0);digester.addCallMethod(prefix + "web-app/error-page/location","setLocation", 0);digester.addObjectCreate(prefix + "web-app/filter","org.apache.catalina.deploy.FilterDef");digester.addSetNext(prefix + "web-app/filter","addFilterDef","org.apache.catalina.deploy.FilterDef");digester.addCallMethod(prefix + "web-app/filter/description","setDescription", 0);digester.addCallMethod(prefix + "web-app/filter/display-name","setDisplayName", 0);digester.addCallMethod(prefix + "web-app/filter/filter-class","setFilterClass", 0);digester.addCallMethod(prefix + "web-app/filter/filter-name","setFilterName", 0);digester.addCallMethod(prefix + "web-app/filter/large-icon","setLargeIcon", 0);digester.addCallMethod(prefix + "web-app/filter/small-icon","setSmallIcon", 0);digester.addCallMethod(prefix + "web-app/filter/init-param","addInitParameter", 2);digester.addCallParam(prefix + "web-app/filter/init-param/param-name",0);digester.addCallParam(prefix + "web-app/filter/init-param/param-value",1);digester.addObjectCreate(prefix + "web-app/filter-mapping","org.apache.catalina.deploy.FilterMap");digester.addSetNext(prefix + "web-app/filter-mapping","addFilterMap","org.apache.catalina.deploy.FilterMap");digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name","setFilterName", 0);digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name","setServletName", 0);digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern","setURLPattern", 0);digester.addCallMethod(prefix + "web-app/listener/listener-class","addApplicationListener", 0);digester.addObjectCreate(prefix + "web-app/login-config","org.apache.catalina.deploy.LoginConfig");digester.addSetNext(prefix + "web-app/login-config","setLoginConfig","org.apache.catalina.deploy.LoginConfig");digester.addCallMethod(prefix + "web-app/login-config/auth-method","setAuthMethod", 0);digester.addCallMethod(prefix + "web-app/login-config/realm-name","setRealmName", 0);digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-error-page","setErrorPage", 0);digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-login-page","setLoginPage", 0);digester.addCallMethod(prefix + "web-app/mime-mapping","addMimeMapping", 2);digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0);digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1);digester.addCallMethod(prefix + "web-app/resource-env-ref","addResourceEnvRef", 2);digester.addCallParam(prefix + "web-app/resource-env-ref/resource-env-ref-name", 0);digester.addCallParam(prefix + "web-app/resource-env-ref/resource-env-ref-type", 1);digester.addObjectCreate(prefix + "web-app/resource-ref","org.apache.catalina.deploy.ContextResource");digester.addSetNext(prefix + "web-app/resource-ref","addResource","org.apache.catalina.deploy.ContextResource");digester.addCallMethod(prefix + "web-app/resource-ref/description","setDescription", 0);digester.addCallMethod(prefix + "web-app/resource-ref/res-auth","setAuth", 0);digester.addCallMethod(prefix + "web-app/resource-ref/res-ref-name","setName", 0);digester.addCallMethod(prefix + "web-app/resource-ref/res-sharing-scope","setScope", 0);digester.addCallMethod(prefix + "web-app/resource-ref/res-type","setType", 0);digester.addObjectCreate(prefix + "web-app/security-constraint","org.apache.catalina.deploy.SecurityConstraint");digester.addSetNext(prefix + "web-app/security-constraint","addConstraint","org.apache.catalina.deploy.SecurityConstraint");digester.addRule(prefix + "web-app/security-constraint/auth-constraint",new SetAuthConstraintRule(digester));digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name","addAuthRole", 0);digester.addCallMethod(prefix + "web-app/security-constraint/display-name","setDisplayName", 0);digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee","setUserConstraint", 0);digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection","org.apache.catalina.deploy.SecurityCollection");digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection","addCollection","org.apache.catalina.deploy.SecurityCollection");digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method","addMethod", 0);digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern","addPattern", 0);digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name","setName", 0);digester.addCallMethod(prefix + "web-app/security-role/role-name","addSecurityRole", 0);digester.addRule(prefix + "web-app/servlet",new WrapperCreateRule(digester));digester.addSetNext(prefix + "web-app/servlet","addChild","org.apache.catalina.Container");digester.addCallMethod(prefix + "web-app/servlet/init-param","addInitParameter", 2);digester.addCallParam(prefix + "web-app/servlet/init-param/param-name",0);digester.addCallParam(prefix + "web-app/servlet/init-param/param-value",1);digester.addCallMethod(prefix + "web-app/servlet/jsp-file","setJspFile", 0);digester.addCallMethod(prefix + "web-app/servlet/load-on-startup","setLoadOnStartupString", 0);digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name","setRunAs", 0);digester.addCallMethod(prefix + "web-app/servlet/security-role-ref","addSecurityReference", 2);digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1);digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0);digester.addCallMethod(prefix + "web-app/servlet/servlet-class","setServletClass", 0);digester.addCallMethod(prefix + "web-app/servlet/servlet-name","setName", 0);digester.addCallMethod(prefix + "web-app/servlet-mapping","addServletMapping", 2);digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1);digester.addCallParam(prefix + "web-app/servlet-mapping/url-pattern", 0);digester.addCallMethod(prefix + "web-app/session-config/session-timeout","setSessionTimeout", 1,new Class[] { Integer.TYPE });digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0);digester.addCallMethod(prefix + "web-app/taglib","addTaglib", 2);digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1);digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0);digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file","addWelcomeFile", 0);}}// ----------------------------------------------------------- Private Classes/*** A Rule that calls the <code>setAuthConstraint(true)</code> method of* the top item on the stack, which must be of type* <code>org.apache.catalina.deploy.SecurityConstraint</code>.*/final class SetAuthConstraintRule extends Rule {public SetAuthConstraintRule(Digester digester) {super(digester);}public void begin(Attributes attributes) throws Exception {SecurityConstraint securityConstraint =(SecurityConstraint) digester.peek();securityConstraint.setAuthConstraint(true);if (digester.getDebug() > 0)digester.log("Calling SecurityConstraint.setAuthConstraint(true)");}}/*** Class that calls <code>setDistributable(true)</code> for the top object* on the stack, which must be a <code>org.apache.catalina.Context</code>.*/final class SetDistributableRule extends Rule {public SetDistributableRule(Digester digester) {super(digester);}public void begin(Attributes attributes) throws Exception {Context context = (Context) digester.peek();context.setDistributable(true);if (digester.getDebug() > 0)digester.log(context.getClass().getName() +".setDistributable( true)");}}/*** Class that calls a property setter for the top object on the stack,* passing the public ID of the entity we are currently processing.*/final class SetPublicIdRule extends Rule {public SetPublicIdRule(Digester digester, String method) {super(digester);this.method = method;}private String method = null;public void begin(Attributes attributes) throws Exception {Context context = (Context) digester.peek(digester.getCount() - 1);Object top = digester.peek();Class paramClasses[] = new Class[1];paramClasses[0] = "String".getClass();String paramValues[] = new String[1];paramValues[0] = digester.getPublicId();Method m = null;try {m = top.getClass().getMethod(method, paramClasses);} catch (NoSuchMethodException e) {digester.log("Can't find method " + method + " in " + top +" CLASS " + top.getClass());return;}m.invoke(top, paramValues);if (digester.getDebug() >= 1)digester.log("" + top.getClass().getName() + "." + method +"(" + paramValues[0] + ")");}}/*** A Rule that calls the factory method on the specified Context to* create the object that is to be added to the stack.*/final class WrapperCreateRule extends Rule {public WrapperCreateRule(Digester digester) {super(digester);}public void begin(Attributes attributes) throws Exception {Context context =(Context) digester.peek(digester.getCount() - 1);Wrapper wrapper = context.createWrapper();digester.push(wrapper);if (digester.getDebug() > 0)digester.log("new " + wrapper.getClass().getName());}public void end() throws Exception {Wrapper wrapper = (Wrapper) digester.pop();if (digester.getDebug() > 0)digester.log("pop " + wrapper.getClass().getName());}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

api restful_HATEOAS的RESTful服务。 记录超媒体API

api restful1.简介 希望本教程的前一部分不仅揭示了超媒体和HATEOAS的深远意义&#xff0c;而且使我们确信这些都是RESTful Web服务和API的基本构建模块。 在这一部分中&#xff0c;我们将继续侧重于文档方面&#xff0c;以解决如何预先传递Web服务或API功能的问题。 目录 1.…

模版方法模式

转载自 23种设计模式&#xff08;6&#xff09;&#xff1a;模版方法模式定义&#xff1a;定义一个操作中算法的框架&#xff0c;而将一些步骤延迟到子类中&#xff0c;使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。 类型&#xff1a;行为类模式 类图&#…

java并发编程实践(1)intro

【0】README0.1&#xff09;本文部分文字描述转自“java并发编程实践”&#xff0c;旨在学习“java并发编程实践(1)intro”的相关知识&#xff1b;【3】线程带来的风险【3.1】安全性问题1&#xff09;intro&#xff1a;在没有充足同步的case下&#xff0c;多个线程的操作执行顺…

读入的字节都写入字节数组中_使用Java将文件读入字节数组的7个示例

读入的字节都写入字节数组中嗨&#xff0c;大家好&#xff0c;Java程序员经常在现实世界中遇到编程问题&#xff0c;他们需要将文件中的数据加载到字节数组中&#xff0c;该文件可以是文本文件或二进制文件。 一个示例是将文件的内容转换为String以显示。 不幸的是&#xff0c;…

迭代子模式

转载自 《JAVA与模式》之迭代子模式 在阎宏博士的《JAVA与模式》一书中开头是这样描述迭代子&#xff08;Iterator&#xff09;模式的&#xff1a; 迭代子模式又叫游标(Cursor)模式&#xff0c;是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部…

java并发编程实践(2)线程安全性

【0】README 0.0&#xff09;本文部分文字描述转自&#xff1a;“java并发编程实战”&#xff0c; 旨在学习“java并发编程实践(2)线程安全性” 的相关知识&#xff1b;0.1&#xff09;几个术语&#xff08;terms&#xff09;t1&#xff09;对象的状态&#xff1a;是指存储在状…

自动配置jdk_JDK 15中自动自动发送更好的NullPointerException消息

自动配置jdk我讨论了期待已久的和高度赞赏改进的NullPointerException &#xff08; NPE在帖&#xff09;消息“ 更好的默认NullPointerException异常消息即将到Java&#xff1f; ”和“ JDK 14中更好的NPE消息 ”。 当此JEP 358驱动的功能添加到JDK 14中时 &#xff0c;想要从…

tomat(16)关闭钩子

【0】REAMDE0&#xff09;本文部分文字描述转自&#xff1a;“how tomcat works”&#xff0c;旨在学习“tomat(16)关闭钩子”的相关知识&#xff1b;1&#xff09;problemsolution&#xff1a;1.1&#xff09;problem&#xff1a;在很多实际环境中&#xff0c;当用户关闭应用程…

apache.camel_Apache Camel 3.1 – XML路由的快速加载

apache.camelCamel 3.1中添加的一项功能是能够更快地加载XML路由。 这是我们为使Camel变得更小&#xff0c;更快而进行的总体工作的一部分。 您可能会说ewww XML。 但坦率地说&#xff0c;有很多Camel用户使用XML定义路由来构建应用程序。 在Camel 2.x中&#xff0c;您将不得不…

程序中 设置jvm 参数_高效应用程序的7个JVM参数

程序中 设置jvm 参数在撰写本文时&#xff08;2020年3月&#xff09;&#xff0c;围绕垃圾收集和内存&#xff0c;您可以将600多个参数传递给JVM。 如果您包括其他方面&#xff0c;则JVM参数总数将很容易超过1000个。 &#x1f60a;。 任何人都无法消化和理解太多的论据。 在本…

tomcat(17)启动tomcat

【0】README 1&#xff09;本文部分文字描述转自“how tomcat works”&#xff0c;旨在学习“tomcat(17)启动tomcat”的相关知识&#xff1b;2&#xff09;本文重点关注启动Tomcat时会用到的两个类&#xff0c;分别是Catalina类和 Bootstrap类&#xff1b;&#xff08;干货——…

八爪鱼 是java做的吗_章鱼扫描仪:Java构建工具和恶意软件

八爪鱼 是java做的吗Alvaro Munoz最近在GitHub Security Lab网站上发布了“ Octopus扫描程序恶意软件&#xff1a;攻击开源供应链 ”。 我发现这篇文章很有趣&#xff0c;原因有很多&#xff0c;其中包括对Octopus Scanner恶意软件的工作原理和发现方式的详细介绍&#xff0c; …

spring(1)Spring之旅

【0】README0.1&#xff09;本文部分文字描述转自&#xff1a;“Spring In Action&#xff08;中/英文版&#xff09;”&#xff0c;旨在reviewSpring(1)Spring之旅 的相关知识&#xff1b;【1】简化java 开发1&#xff09;为了降低java开发的复杂性&#xff0c;Spring采取了以…

apache.camel_Apache Camel K 1.0在这里–您为什么要关心

apache.camel昨天我们发布了Apache Camel K 1.0&#xff0c;并在社交媒体和Camel网站上宣布了该版本。 那么&#xff0c;骆驼K是什么&#xff0c;为什么你要在乎呢&#xff1f; 这是一个很好的问题&#xff0c;我想通过提及伟大的思想来帮助回答这个问题。 Hugo Guerrero发表…

DRF之初识

目录 一、序列化和反序列化 【1】序列化 【2】反序列化 【3】小结 二、DRF的安装和快速使用 (1) 安装DRF&#xff1a; (2) 配置DRF&#xff1a; (3) 创建序列化器(Serializer)&#xff1a; (4) 创建视图(View)&#xff1a; (5) 配置URL路由&#xff1a; 【补充】下载…

spring(2)装配Bean

【0】README0&#xff09;本文部分文字描述转自&#xff1a;“Spring In Action&#xff08;中/英文版&#xff09;”&#xff0c;旨在review spring(2)装配Bean 的相关知识&#xff1b;1&#xff09;在spring中&#xff0c;对象无需自己查找或创建与其所关联的其他对象。相反…

restful和rest_HATEOAS的RESTful服务:JVM上的REST API和超媒体

restful和rest1.简介 到目前为止&#xff0c;我们已经花了很多时间谈论了相当数量的关于角色的的超媒体和HATEOAS在REST风格的 Web服务和API&#xff0c;扫视不同规格和可用性方面。 听起来好像支持超媒体和HATEOAS并不难&#xff0c;只需选择您的收藏夹就可以了&#xff01; …

Spring中配置数据源的4种形式

【0】README 0.1&#xff09;以下内容转自&#xff1a;http://blog.csdn.net/orclight/article/details/8616103 不管采用何种持久化技术&#xff0c;都需要定义数据源。Spring中提供了4种不同形式的数据源配置方式&#xff1a; spring自带的数据源(DriverManagerDataSource)&…

MavenSelenium测试自动化教程

在进行自动化测试项目时&#xff0c;您需要与之关联的所有Selenium依赖项。 通常&#xff0c;这些依赖项是在项目生命周期中手动下载和升级的&#xff0c;但是随着项目规模的扩大&#xff0c;管理依赖项可能会非常困难。 这就是为什么需要构建自动化工具&#xff08;例如Maven&…

命令行执行Junit测试

【0】README 0.1&#xff09;本文旨在给出如何在命令行中执行 Junit测试的steps&#xff1a; 【1】在命令行中执行Junit测试 1&#xff09;problemsolution&#xff1a; 1.1&#xff09;problem&#xff1a; 1.2&#xff09;solution&#xff1a;导出 JUnitCore 类并且使用 …