- 浏览: 997717 次
-
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
Tomcat的Server初始化及启动过程:http://donald-draper.iteye.com/blog/2327060
Realm域管理:http://www.cnblogs.com/xing901022/p/4552843.html
通过分析Server初始化及启动过程,我们可以看到关键只在Engine的init和start方法
Server中Engine的配置:
下面来看StandardEngine的initInternal和startInternal方法
从上可以看出StandardEngine的initInternal和startInternal方法,实际调用的,
为其父类的initInternal和startInternal,我们来看ContainerBase
从分析ContainerBase,可以得出ContainerBase主要做的工作是,创建后台子容器线程
执行器,执行子容器的启动任务,启动context更新守候线程。
在ContainerBase的startInternal中有这么一句
查看StandardPipeline
在StandardEngine中有构造方法种,初始化
而pipeline是在ContainerBase定义
查看StandardPipeline,处理HTTP请求的Pipeline
//StandardEngineValve,处理请求Valve
//Valve,实际上一个链表,只有后继,没有前驱
总结:
以上分析可以得出,Engine的初始化与启动实际上是委托给ContainerBase,而ContainerBase初始化与启动,主要做的工作是,创建后台子容器线程执行器,执行子容器的启动任务,启动context更新守候线程。ContainerBase拥有一个StandardPipeline,StandardPipeline是处理HTTP请求的管道,在管道内部有很多Valve( Valve, Filter, or Servlet),这些Value是一个只有后继的链,当请求进来的时候,调用invoke(Request request, Response response)处理请求。
Realm域管理:http://www.cnblogs.com/xing901022/p/4552843.html
通过分析Server初始化及启动过程,我们可以看到关键只在Engine的init和start方法
public class StandardService extends LifecycleMBeanBase implements Service { private static final String info = "org.apache.catalina.core.StandardService/1.0"; private String name = null; private static final StringManager sm = StringManager.getManager(Constants.Package); private Server server = null; protected Connector connectors[] = new Connector[0]; private final Object connectorsLock = new Object(); protected ArrayList<Executor> executors = new ArrayList<Executor>(); protected Container container = null; private ClassLoader parentClassLoader = null; @Override protected void initInternal() throws LifecycleException { //注册Service到JMX super.initInternal(); //初始化Container if (container != null) { container.init(); } } @Override protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); //设置Service状态 setState(LifecycleState.STARTING); if (container != null) { synchronized (container) { //启动container container.start(); } } } //Container处理所有请求 public void setContainer(Container container) { Container oldContainer = this.container; if ((oldContainer != null) && (oldContainer instanceof Engine)) ((Engine) oldContainer).setService(null); this.container = container; if ((this.container != null) && (this.container instanceof Engine)) ((Engine) this.container).setService(this); if (getState().isAvailable() && (this.container != null)) { try { //启动Engine this.container.start(); } } } }
Server中Engine的配置:
<Engine name="Catalina" defaultHost="localhost"> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine>
下面来看StandardEngine的initInternal和startInternal方法
public class StandardEngine extends ContainerBase implements Engine { public StandardEngine() { super(); //设置Http请求Valve pipeline.setBasic(new StandardEngineValve()); /* Set the jmvRoute using the system property jvmRoute */ try { setJvmRoute(System.getProperty("jvmRoute")); } catch(Exception ex) { log.warn(sm.getString("standardEngine.jvmRouteFail")); } // By default, the engine will hold the reloading thread backgroundProcessorDelay = 10; } //默认主机名 private String defaultHost = null; /** * The descriptive information string for this implementation. */ private static final String info = "org.apache.catalina.core.StandardEngine/1.0"; //Engine关联的Service private Service service = null; /** Allow the base dir to be specified explicitly for * each engine. In time we should stop using catalina.base property - * otherwise we loose some flexibility. */ private String baseDir = null; /** * The JVM Route ID for this Tomcat instance. All Route ID's must be unique across the cluster. */ private String jvmRouteId; /** * Default access log to use for request/response pairs where we can't ID the intended host and context. */ private final AtomicReference<AccessLog> defaultAccessLog = new AtomicReference<AccessLog>(); //初始化 protected void initInternal() throws LifecycleException { //获取角色权限 getRealm(); super.initInternal(); } //获取角色权限 public Realm getRealm() { Realm configured = super.getRealm(); // If no set realm has been called - default to NullRealm // This can be overridden at engine, context and host level if (configured == null) { configured = new NullRealm(); this.setRealm(configured); } return configured; } //启动 protected synchronized void startInternal() throws LifecycleException { // Log our server identification information if(log.isInfoEnabled()) log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo()); // 启动Standard container super.startInternal(); } //添加子容器<Host> public void addChild(Container child) { if (!(child instanceof Host)) throw new IllegalArgumentException (sm.getString("standardEngine.notHost")); super.addChild(child); } }
从上可以看出StandardEngine的initInternal和startInternal方法,实际调用的,
为其父类的initInternal和startInternal,我们来看ContainerBase
public abstract class ContainerBase extends LifecycleMBeanBase implements Container { //子容器Map protected HashMap<String, Container> children = new HashMap<String, Container>(); protected int backgroundProcessorDelay = -1; /** * The container event listeners for this Container. Implemented as a * CopyOnWriteArrayList since listeners may invoke methods to add/remove * themselves or other listeners and with a ReadWriteLock that would trigger * a deadlock. */ //线程安全的容器监听器List protected List<ContainerListener> listeners = new CopyOnWriteArrayList<ContainerListener>(); /** The Loader implementation with which this Container is associated.*/ protected Loader loader = null; /** The Logger implementation with which this Container is associated.*/ protected Log logger = null; /** Associated logger name.*/ protected String logName = null; /** The Manager implementation with which this Container is associated.*/ protected Manager manager = null; /** The cluster with which this Container is associated.*/ protected Cluster cluster = null; //容器名 protected String name = null; /** The parent Container to which this Container is a child.*/ protected Container parent = null; /** The parent class loader to be configured when we install a Loader.*/ protected ClassLoader parentClassLoader = null; /** The Pipeline object with which this Container is associated.*/ protected Pipeline pipeline = new StandardPipeline(this); /** The Realm with which this Container is associated.*/ private volatile Realm realm = null; /** Lock used to control access to the Realm. */ private final ReadWriteLock realmLock = new ReentrantReadWriteLock(); // javax.naming.Context /** The resources DirContext object with which this Container is associated.*/ protected DirContext resources = null; /** The string manager for this package.*/ protected static final StringManager sm = StringManager.getManager(Constants.Package); //当添加子容器时,是否自动启动 protected boolean startChildren = true; /**The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); //后台线程 private Thread thread = null; //后台线程完成信号量 private volatile boolean threadDone = false; /** * The access log to use for requests normally handled by this container * that have been handled earlier in the processing chain. */ protected volatile AccessLog accessLog = null; private volatile boolean accessLogScanComplete = false; //处理Container事件线程数 private int startStopThreads = 1; protected ThreadPoolExecutor startStopExecutor; //初始化 protected void initInternal() throws LifecycleException { //LinkedBlockingQueue,线程安全的阻塞队列 BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<Runnable>(); //新建容器事件,线程池执行器 startStopExecutor = new ThreadPoolExecutor( getStartStopThreadsInternal(), getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, startStopQueue, new StartStopThreadFactory(getName() + "-startStop-")); startStopExecutor.allowCoreThreadTimeOut(true); //注册Engine到JMX super.initInternal(); } //启动 protected synchronized void startInternal() throws LifecycleException { //启动loader if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); logger = null; getLogger(); //启动manager if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); //启动cluster if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); //配置Realm Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); //加载resources if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); //获取子容器 Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<Future<Void>>(); for (int i = 0; i < children.length; i++) { //后台线程执行器,执行子容器 results.add(startStopExecutor.submit(new StartChild(children[i]))); } boolean fail = false; for (Future<Void> result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); fail = true; } } if (fail) { throw new LifecycleException( sm.getString("containerBase.threadedStartFailed")); } // Start the Valves in our pipeline (including the basic), if any //启动请求处理Valves包括basic(StandardEngineValve),这个在Engine构造方法中 if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); setState(LifecycleState.STARTING); // Start our thread threadStart(); } protected void threadStart() { if (thread != null) return; if (backgroundProcessorDelay <= 0) return; threadDone = false; String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; //新建后台更新上线问线程 thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start(); } //子容器启动Callable private static class StartChild implements Callable<Void> { private Container child; public StartChild(Container child) { this.child = child; } @Override public Void call() throws LifecycleException { //启动子容器 child.start(); return null; } } /** * Private thread class to invoke the backgroundProcess method * of this container and its children after a fixed delay. */ //后台更新上下文线程 protected class ContainerBackgroundProcessor implements Runnable { @Override public void run() { Throwable t = null; String unexpectedDeathMessage = sm.getString( "containerBase.backgroundProcess.unexpectedThreadDeath", Thread.currentThread().getName()); try { while (!threadDone) { try { Thread.sleep(backgroundProcessorDelay * 1000L); } if (!threadDone) { //获取父容器 Container parent = (Container) getMappingObject(); //获取当前线程ClassLoader ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (parent.getLoader() != null) { cl = parent.getLoader().getClassLoader(); } processChildren(parent, cl); } } } } protected void processChildren(Container container, ClassLoader cl) { try { if (container.getLoader() != null) { Thread.currentThread().setContextClassLoader (container.getLoader().getClassLoader()); } container.backgroundProcess(); } finally { Thread.currentThread().setContextClassLoader(cl); } Container[] children = container.findChildren(); for (int i = 0; i < children.length; i++) { if (children[i].getBackgroundProcessorDelay() <= 0) { processChildren(children[i], cl); } } } } /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ //当上下文改变时,重新加载时,上下文,更新到Container @Override public void backgroundProcess() { if (!getState().isAvailable()) return; if (cluster != null) { try { cluster.backgroundProcess(); } } if (loader != null) { try { loader.backgroundProcess(); } } if (manager != null) { try { manager.backgroundProcess(); } } Realm realm = getRealmInternal(); if (realm != null) { try { realm.backgroundProcess(); } } Valve current = pipeline.getFirst(); while (current != null) { try { current.backgroundProcess(); } } current = current.getNext(); } fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); } //启动停止,子容器线程工厂类 private static class StartStopThreadFactory implements ThreadFactory { private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; public StartStopThreadFactory(String namePrefix) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = namePrefix; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement()); thread.setDaemon(true); return thread; } } /** * Process the specified Request, to produce the corresponding Response, * by invoking the first Valve in our pipeline (if any), or the basic * Valve otherwise. */ //处理HTTP请求 @Override public void invoke(Request request, Response response) throws IOException, ServletException { pipeline.getFirst().invoke(request, response); } //添加子容器权限 @Override public void addChild(Container child) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> dp = new PrivilegedAddChild(child); AccessController.doPrivileged(dp); } else { addChildInternal(child); } } //添加子容器 private void addChildInternal(Container child) { synchronized(children) { if (children.get(child.getName()) != null) throw new IllegalArgumentException("addChild: Child name '" + child.getName() + "' is not unique"); child.setParent(this); // May throw IAE children.put(child.getName(), child); } // Start child // Don't do this inside sync block - start can be a slow process and // locking the children object can cause problems elsewhere try { if ((getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) && startChildren) { //启动自容器 child.start(); } } //产生ADD_CHILD_EVENT事件 fireContainerEvent(ADD_CHILD_EVENT, child); } } /** * Perform addChild with the permissions of this class. * addChild can be called with the XML parser on the stack, * this allows the XML parser to have fewer privileges than * Tomcat. */ protected class PrivilegedAddChild implements PrivilegedAction<Void> { private Container child; PrivilegedAddChild(Container child) { this.child = child; } @Override public Void run() { addChildInternal(child); return null; } } //添加addValve public synchronized void addValve(Valve valve) { pipeline.addValve(valve); } }
从分析ContainerBase,可以得出ContainerBase主要做的工作是,创建后台子容器线程
执行器,执行子容器的启动任务,启动context更新守候线程。
在ContainerBase的startInternal中有这么一句
if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();
查看StandardPipeline
public class StandardPipeline extends LifecycleBase implements Pipeline, Contained { //待子类扩展 protected void initInternal() { // NOOP } //如果Valve实现了LifecycleBase,则启动Valve的startInternal方法 protected synchronized void startInternal() throws LifecycleException { // Start the Valves in our pipeline (including the basic), if any Valve current = first; if (current == null) { current = basic; } while (current != null) { if (current instanceof Lifecycle) ((Lifecycle) current).start(); current = current.getNext(); } setState(LifecycleState.STARTING); } }
在StandardEngine中有构造方法种,初始化
public StandardEngine() { super(); pipeline.setBasic(new StandardEngineValve()); /* Set the jmvRoute using the system property jvmRoute */ try { setJvmRoute(System.getProperty("jvmRoute")); } backgroundProcessorDelay = 10; }
而pipeline是在ContainerBase定义
/** * The Pipeline object with which this Container is associated. */ protected Pipeline pipeline = new StandardPipeline(this);
查看StandardPipeline,处理HTTP请求的Pipeline
public class StandardPipeline extends LifecycleBase implements Pipeline, Contained { /** The basic Valve (if any) associated with this Pipeline.*/ //处理HTTP请求的Basic Valve protected Valve basic = null; /** The Container with which this Pipeline is associated.*/ //关联容器 protected Container container = null; /** Descriptive information about this implementation.*/ protected static final String info = "org.apache.catalina.core.StandardPipeline/1.0"; /** The first valve associated with this Pipeline.*/ //第一个Valve protected Valve first = null; //设置basic-Valve public void setBasic(Valve valve) { // Change components if necessary Valve oldBasic = this.basic; if (oldBasic == valve) return; // Stop the old component if necessary if (oldBasic != null) { if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) { try { ((Lifecycle) oldBasic).stop(); } } if (oldBasic instanceof Contained) { try { ((Contained) oldBasic).setContainer(null); } } } // Start the new component if necessary if (valve == null) return; if (valve instanceof Contained) { ((Contained) valve).setContainer(this.container); } if (getState().isAvailable() && valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); } } //更新pipeline Valve current = first; while (current != null) { if (current.getNext() == oldBasic) { current.setNext(valve); break; } current = current.getNext(); } this.basic = valve; } //添加Valve @Override public void addValve(Valve valve) { // Validate that we can add this Valve if (valve instanceof Contained) //如果valve是Contained,则设置valve的关联容器 ((Contained) valve).setContainer(this.container); // Start the new component if necessary if (getState().isAvailable()) { if (valve instanceof Lifecycle) { try { //启动valve ((Lifecycle) valve).start(); } } } // Add this Valve to the set associated with this Pipeline //将Valve与PipeLine关联,如果first为null,则Valve关联到first if (first == null) { first = valve; valve.setNext(basic); } else { Valve current = first; while (current != null) { if (current.getNext() == basic) { current.setNext(valve); valve.setNext(basic); break; } current = current.getNext(); } } container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve); } //返回first Valve public Valve getFirst() { if (first != null) { return first; } return basic; } }
//StandardEngineValve,处理请求Valve
final class StandardEngineValve extends ValveBase { public StandardEngineValve() { super(true); } //类信息 private static final String info = "org.apache.catalina.core.StandardEngineValve/1.0"; private static final StringManager sm = StringManager.getManager(Constants.Package); //获取类信息 public String getInfo() { return (info); } //处理HTTP请求 public final void invoke(Request request, Response response) throws IOException, ServletException { //获取Host信息,处理请求 Host host = request.getHost(); if (host == null) { response.sendError (HttpServletResponse.SC_BAD_REQUEST, sm.getString("standardEngine.noHost", request.getServerName())); return; } if (request.isAsyncSupported()) { request.setAsyncSupported(host.getPipeline().isAsyncSupported()); } host.getPipeline().getFirst().invoke(request, response); } //事件推送 public final void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Ask this Host to process this request request.getHost().getPipeline().getFirst().event(request, response, event); } }
//Valve,实际上一个链表,只有后继,没有前驱
public interface Valve { //-------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ public String getInfo(); /** * Return the next Valve in the pipeline containing this Valve, if any. */ public Valve getNext(); /** * Set the next Valve in the pipeline containing this Valve. * * @param valve The new next valve, or <code>null</code> if none */ public void setNext(Valve valve); //---------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ public void backgroundProcess(); /** * Perform request processing as required by this Valve. * * An individual Valve <b>MAY</b> perform the following actions, in * the specified order: * [list] * <li>Examine and/or modify the properties of the specified Request and * Response. * <li>Examine the properties of the specified Request, completely generate * the corresponding Response, and return control to the caller. * <li>Examine the properties of the specified Request and Response, wrap * either or both of these objects to supplement their functionality, * and pass them on. * <li>If the corresponding Response was not generated (and control was not * returned, call the next Valve in the pipeline (if there is one) by * executing <code>getNext().invoke()</code>. * <li>Examine, but not modify, the properties of the resulting Response * (which was created by a subsequently invoked Valve or Container). * [/list] * * A Valve <b>MUST NOT</b> do any of the following things: * [list] * <li>Change request properties that have already been used to direct * the flow of processing control for this request (for instance, * trying to change the virtual host to which a Request should be * sent from a pipeline attached to a Host or Context in the * standard implementation). * <li>Create a completed Response [b]AND[/b] pass this * Request and Response on to the next Valve in the pipeline. * <li>Consume bytes from the input stream associated with the Request, * unless it is completely generating the response, or wrapping the * request before passing it on. * <li>Modify the HTTP headers included with the Response after the * <code>getNext().invoke()</code> method has returned. * <li>Perform any actions on the output stream associated with the * specified Response after the <code>getNext().invoke()</code> method has * returned. * [/list] * @exception IOException if an input/output error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet * @exception ServletException if a servlet error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet */ public void invoke(Request request, Response response) throws IOException, ServletException; //推送事件 public void event(Request request, Response response, CometEvent event) throws IOException, ServletException; public boolean isAsyncSupported(); }
总结:
以上分析可以得出,Engine的初始化与启动实际上是委托给ContainerBase,而ContainerBase初始化与启动,主要做的工作是,创建后台子容器线程执行器,执行子容器的启动任务,启动context更新守候线程。ContainerBase拥有一个StandardPipeline,StandardPipeline是处理HTTP请求的管道,在管道内部有很多Valve( Valve, Filter, or Servlet),这些Value是一个只有后继的链,当请求进来的时候,调用invoke(Request request, Response response)处理请求。
发表评论
-
tomcat日志及log4j日志乱码
2017-04-26 15:00 5545Linux系统字符编码:http://www.cnblogs. ... -
SQL盲注的解决方案
2016-10-27 18:35 2570引起SQL盲注的原因:http://www-01.ibm.co ... -
Tomcat的HTTPS配置详解
2016-10-27 16:59 1004HTTPS原理详解:http://blog.csdn.net/ ... -
Tomcat的StandardService,Executor初始化与启动
2016-10-13 09:15 1635Tomcat的Server初始化及启动过程:http://do ... -
Tomcat的JioEndPoint,处理HTTP请求
2016-10-12 19:02 1301Tomcat的Connector(Protocol,Coyot ... -
Tomcat的Connector(Protocol,CoyoteAdapterAdapter,AprEndPoint)初始化及请求处理过程
2016-10-12 16:46 1681Tomcat的Server初始化及启动过程:http://do ... -
Tomcat问题集
2016-10-09 17:50 861tcnative-1.dll: Can't load AMD ... -
Tomcat-ConfigContext监听器(Context.xml,web.xml)
2016-09-27 12:59 2014Tomcat的Host初始化(Context,Listener ... -
Tomcat的Host初始化(Context,Listener,Filter,Servlet)
2016-09-27 08:42 1521Tomcat的Engine初始化,启动过程:http://do ... -
Tomcat的Server初始化及启动过程
2016-09-26 11:02 2957Tomcat7,启动过程(BootStrap、Catalina ... -
Tomcat7,启动过程(BootStrap、Catalina)
2016-09-23 19:08 1902Tomcat 系统架构与设计模式,工作原理:http://ww ... -
405 request method post not supported
2016-08-18 18:09 32591.检查链接地址有没有错误 2.看RequestMethod, ... -
apache-tomcat-7.0.67\bin\tcnative-1.dll: Can't load AMD 64-bit .dll on a IA 3
2016-08-12 13:02 1165F:\apache-tomcat-7.0.67\bin\tcn ...
相关推荐
内容概要:本文介绍了如何使用Python识别图片和扫描PDF中的文字。首先,文章讲解了使用Spire.OCR for Python库来识别图片中的文字,包括安装库、配置OCR模型路径和语言设置、扫描图片以及保存识别后的文本。其次,详细描述了从图片中提取文字及其坐标位置的方法,使用户不仅能够获取文本内容,还能知道文本在图片中的具体位置。最后,文章还介绍了如何结合Spire.PDF for Python将PDF文件转换为图片格式,再通过OCR技术从中提取文字,适用于处理扫描版PDF文件。文中提供了完整的代码示例,帮助读者理解和实践。 适合人群:对Python编程有一定基础,希望学习或提高光学字符识别(OCR)技术的应用开发者,尤其是需要处理大量图片或PDF文档中文字信息的工作人员。 使用场景及目标:① 开发者可以利用这些方法自动化处理图片或PDF文档中的文字信息,提高工作效率;② 实现从非结构化数据(如图片、扫描件)到结构化数据(如文本文件)的转换,便于后续的数据分析和处理;③ 提供了一种解决纸质文档数字化的有效途径,特别是对于历史档案、书籍等资料的电子化保存。 其他说明:需要注意的是,OCR的准确性很大程度上取决于图片的质量,清晰度高、对比度好的图片可以获得更好的识别效果。此外,不同OCR库可能对特定语言或字体的支持程度不同,选择合适的库和配置参数能显著提升识别精度。在实际应用中,建议先进行小规模测试,优化参数后再大规模应用。
2025中小企业数字化转型指南
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
2025-04-10 兜兜\(^o^)/~
内容概要:本文详细介绍了永磁同步电机(PMSM)无位置传感器控制中滑模观测器(SMO)的设计与仿真实现。首先阐述了系统的整体架构,包括速度环和电流环的工作机制。接着深入探讨了滑模观测器的关键实现步骤,如滑模增益选择、符号函数的应用以及低通滤波器的作用。文中还涉及了坐标变换(Clarke变换和Park变换)、PI参数整定、SVPWM调制等重要环节的具体实现方法和技术难点。此外,作者分享了多个调试过程中遇到的问题及解决方案,如波形抖振、电流采样延时、扇区判断错误等。最后展示了仿真结果,证明了所提方案的有效性和可行性。 适合人群:从事电机控制系统研究与开发的技术人员,尤其是对无位置传感器控制感兴趣的工程师。 使用场景及目标:适用于希望深入了解并掌握永磁同步电机无位置传感器控制技术的研究人员和工程师。目标是帮助读者理解滑模观测器的工作原理,掌握其设计与调试技巧,从而应用于实际项目中。 其他说明:文中提供了丰富的代码片段和实践经验,有助于读者更好地理解和应用理论知识。同时提醒读者注意离散化步长的选择和滑模增益的调整,这些都是确保系统稳定运行的重要因素。
内容概要:本文详细介绍了航天器姿态控制中的关键技术,包括时变滑模控制、自适应控制、执行器饱和处理及推力器安装偏差补偿。针对航天器在复杂环境中面临的不确定性,提出了时变滑模面设计、自适应参数更新、饱和控制和安装偏差补偿的具体实现方法,并提供了相应的MATLAB代码。通过合理的控制策略设计,确保航天器在面对多种干扰因素时仍能保持高精度的姿态控制。 适合人群:航空航天领域的研究人员、控制系统工程师、高校相关专业师生。 使用场景及目标:适用于航天器姿态控制系统的开发与优化,旨在提升系统的鲁棒性、稳定性和控制精度。具体应用场景包括卫星姿态调整、深空探测器姿态控制等。 其他说明:文中提供的MATLAB代码可以直接用于实验验证和教学演示,帮助读者深入理解各控制环节的工作原理和技术细节。此外,文中还分享了许多实用的工程经验,如参数整定技巧、常见问题处理等,有助于指导实际项目开发。
内容概要:本文详细介绍了基于Simulink-Simscape平台构建的四轮转向汽车模型预测控制(MPC)路径跟踪系统。首先,文章阐述了车辆动力学模型的核心结构,包括前轮和后轮转向角的计算方法以及魔术轮胎模型的配置。接着,深入探讨了MPC控制器的设计,特别是代价函数的配置和QP优化的具体实现。此外,还讨论了路面切换模块的设计,确保不同路况下的稳定性和响应性。最后,文章分享了一些调参经验和仿真参数设置的技巧,如积分限幅、随机质量块的应用以及解算器的选择。 适合人群:从事自动驾驶、车辆控制系统研究的工程师和技术人员,尤其是对路径跟踪算法和MPC有浓厚兴趣的研究者。 使用场景及目标:适用于开发和优化四轮转向汽车的路径跟踪系统,旨在提高车辆在各种复杂路况下的行驶稳定性和精确度。具体目标包括减小方向盘转角误差、控制横向位移偏差、优化轮胎力计算等。 其他说明:文中提供了大量MATLAB代码片段和具体的参数配置,帮助读者更好地理解和复现实验结果。同时,作者分享了许多实际调试过程中遇到的问题及其解决方案,使读者能够避开常见陷阱并高效完成模型搭建。
全国银行代码和支行代城市地区mysql
内容概要:本文详细介绍了如何利用动态规划(Dynamic Programming, DP)在MATLAB/SIMULINK环境中实现自动驾驶车辆的动态避障功能。首先,文章解释了动态规划的核心思想及其在路径规划中的应用,特别是通过状态转移方程来解决避障问题。接着,讨论了运动学模型(如自行车模型)的建立方法,以及如何通过PID和MPC控制算法进行路径跟踪和避障。此外,文章还探讨了联合仿真平台(MATLAB + Carsim + Prescan)的搭建和配置,展示了如何将理论转化为实际的仿真效果。最后,提供了完整的代码实现和调试技巧,帮助读者快速上手并优化性能。 适合人群:对自动驾驶技术和路径规划感兴趣的科研人员、工程师和技术爱好者。 使用场景及目标:适用于研究和开发自动驾驶系统,特别是在复杂环境下实现高效的动态避障功能。目标是提高车辆的安全性和智能化水平,减少人为干预。 其他说明:文中提供的代码已在GitHub上开源,读者可以直接下载并运行。需要注意的是,某些高级功能(如深度强化学习)将在后续版本中继续探索。
内容概要:本文档是《拼多多Python面试题目.pdf》,涵盖了Python编程语言的面试题目及其参考答案。文档分为四个主要部分:选择题、填空题、代码编程题和综合题。选择题涉及Python基础知识、多线程、Redis使用场景、字符编码转换、协程特性、深拷贝操作等;填空题考察了列表推导式、对象序列化、文件操作、字符串处理等知识点;代码编程题包括统计热门商品、订单时间窗口校验、字符串压缩、异步批量请求、最长递增子序列等实际编程任务;综合题则要求设计一个高并发秒杀系统,涵盖缓存、数据库、消息队列的选择,库存扣减、分布式锁、限流策略等关键模块的实现思路,以及解决缓存相关问题的方法。 适合人群:有一定Python编程基础,准备求职或希望提升技术能力的开发者,尤其是对Python高级特性和实际应用感兴趣的工程师。 使用场景及目标:①帮助面试者熟悉Python常见知识点和技巧,提高面试成功率;②通过实际编程题目的练习,加深对Python语法和标准库的理解;③掌握高并发系统的架构设计思路,培养解决复杂业务问题的能力。 阅读建议:此文档不仅包含理论知识的选择题和填空题,还有实际编程题目的训练,建议读者在学习过程中不仅要关注正确答案,更要理解每个选项背后的原理,同时动手实践编程题目,结合实际案例进行思考和总结。
内容概要:本文档《Java 算法面试题目.pdf》涵盖了 Java 编程语言的核心知识点和常见面试题,分为选择题、填空题、代码编程题和综合题四个部分。选择题涉及 Java 内存模型、字符串处理、集合类、垃圾回收、线程池、设计模式、Spring 事务、流操作、类加载机制、锁机制、Netty 和 Redis 持久化等主题。填空题考察了线程同步、HashMap 负载因子、序列化、数学运算、Spring 注入、字符串对象创建、位移运算、字符串方法、动态代理和 JVM 参数配置等细节。代码编程题要求实现链表反转、线程安全单例模式、快速排序、二叉树层序遍历和 LRU 缓存等功能。综合题则要求设计一个无人机实时控制系统,涵盖并发控制、可靠传输、路径规划、高可用性和低延迟等方面。; 适合人群:具有 Java 编程基础,尤其是准备面试的中高级开发人员,以及对 Java 核心技术和框架有深入理解需求的技术人员。; 使用场景及目标:①帮助开发者复习和巩固 Java 基础知识和常见面试考点;②通过编程题提升实际编码能力;③通过综合题锻炼系统设计和架构思维,掌握分布式系统的设计要点。; 阅读建议:建议读者先复习相关知识点,再尝试解答题目,最后对照参考答案进行查漏补缺。对于综合题,应结合实际项目经验思考解决方案,重点理解系统设计的关键点和技术选型的理由。
内容概要:该专利提出了一种节能高效的双螺杆压缩机转子型线设计方案,属于动力传动与控制技术领域。核心创新点在于阴阳转子的齿曲线采用抛物线、圆弧、椭圆及其共轭包络线组合而成,形成二次曲线与二次曲线包络线的组合型线。设计特点包括非对称齿面(前齿面更宽,b/a>1.8)、各段曲线光滑连接无尖点、七段曲线组合结构。该设计旨在提高密封性、改善动力特性、降低损耗、提升效率,从而提高双螺杆压缩机的整体性能。文中提供了详细的Python代码实现,包括转子型线的计算和可视化,以及改进后的代码,以更好地反映专利的具体参数和技术细节。 适合人群:机械工程专业人员、从事压缩机设计与制造的技术人员、对双螺杆压缩机转子型线设计感兴趣的科研人员。 使用场景及目标:①用于研究和开发新型双螺杆压缩机,特别是在提高压缩机效率和性能方面;②作为教学案例,帮助学生和工程师理解双螺杆压缩机转子型线的设计原理和技术实现;③为企业提供参考,优化现有产品的设计和制造工艺。 其他说明:文中提供的代码基于专利描述进行了合理的假设和简化,实际应用中可能需要根据具体性能要求进行优化调整。专利技术通过非对称设计、多段曲线组合等方式,实现了高效的密封性和优良的动力特性,显著提升了双螺杆压缩机的性能。
内容概要:本文详细介绍了利用PFC3D5.0进行滑坡冲击建筑物仿真的全流程,涵盖滑坡体和建筑物的建模、参数设定、监测系统的构建以及灾后损伤评估。文中不仅提供了完整的Python代码示例,还解释了各个关键参数的选择依据及其对仿真结果的影响。通过实例展示了如何设置滑坡体的尺寸、密度、阻尼系数等属性,以及建筑物的材料属性、粘结强度等参数。同时,文章强调了实时监测系统的重要性,包括冲击力传感器的布置和预警机制的设计。此外,还探讨了不同条件下建筑物的易损性曲线生成方法及其应用价值。 适合人群:从事地质灾害研究、结构工程分析的专业人士,尤其是那些希望深入了解滑坡冲击建筑物过程并掌握相关数值模拟技术的研究人员和技术人员。 使用场景及目标:适用于需要进行滑坡灾害风险评估、建筑设计优化以及应急响应规划的项目。主要目标是帮助用户理解和预测滑坡对建筑物造成的潜在损害,从而提高建筑物的安全性和耐久性。 其他说明:文中提供的代码和参数设置均经过多次实验验证,确保了较高的准确性。对于想要进一步探索这一领域的读者来说,本文提供了一条从理论到实践的学习路径。
修复版本,改了短信接口到阿里云,现在好像国内短信接口管的最松的反而是阿里了,支付也已经接好了派特了。可以直接开户直接用了,带非常非常非常完整的搭建教程,萌新都可以随便装起来了。
内容概要:本文探讨了在自动驾驶领域中,利用Matlab/Simulink 2018b和Carsim 2020构建ACC(自适应巡航控制)系统的分层PID控制模型的方法和技术要点。首先介绍了软件选择的原因及其版本要求,强调了版本兼容性的重要性。接着详细讲解了模块化建模方法的应用,包括单独的Carsim配置文件、电机驱动模块、车辆巡航模块、车辆跟踪模块、切换逻辑、速度跟踪模块以及联合仿真模块等七个关键组成部分的作用和实现方式。文中提供了具体的MATLAB代码片段展示上层和下层PID控制器的工作机制,并分享了一些实用的小技巧,如安全距离动态补偿、积分限幅处理、死区设置等。此外,还讨论了联合仿真的注意事项,如接口版本匹配、远程调试设置等问题。最后提到模型验证的有效测试案例,并指出整套源码中最值得关注的部分是状态机实现。 适合人群:对自动驾驶技术感兴趣的科研人员、工程师以及相关专业的学生,尤其是那些希望深入了解ACC系统内部工作机制的人群。 使用场景及目标:①帮助读者掌握如何使用Matlab/Simulink和Carsim建立并优化ACC巡航控制系统;②提高读者对PID控制理论的理解及其在实际工程项目中的应用能力;③为从事智能交通系统研究的专业人士提供有价值的参考资料。 其他说明:本文不仅涵盖了理论知识,还包括大量实践经验分享,有助于初学者快速入门的同时也为资深从业者带来新的思考角度。
内容概要:本文详细介绍了基于西门子S7-1200 PLC和TIA Portal V16平台的五层电梯仿真系统。该系统利用博图V16的仿真环境,无需实体PLC即可实现电梯的动态动画运行。核心内容涵盖PLC程序的状态机设计、呼叫处理模块、HMI组态画面的设计以及安全回路处理等方面。文中展示了具体的代码片段,如电梯状态机的嵌套状态切换逻辑、呼叫信号的位操作处理、HMI动画的位置计算等。此外,还提到了一些实用技巧,如优化响应速度的方法、动画效果的实现细节以及仿真过程中可能遇到的问题及其解决方案。 适合人群:工控领域的工程师、培训讲师、学生及其他对电梯控制系统感兴趣的人员。 使用场景及目标:①作为教学工具,帮助学员理解和掌握电梯控制系统的逻辑设计;②作为验证工具,用于测试和优化电梯控制系统的性能;③为实际工程项目提供参考,减少硬件调试的时间和成本。 其他说明:该仿真系统不仅提供了完整的PLC程序和HMI项目文件,还包括详细的仿真参数配置指南和故障模拟功能,使得教学和实验更加生动有趣。
内容概要:本文详细介绍了Bandgap带隙基准电路的设计、仿真及其优化技巧。首先解释了启动电路的重要性和具体实现方式,确保电路能够稳定启动。接着深入探讨了如何通过仿真工具(如Cadence、Spectre等)进行抛物线曲线、电源抑制比(PSR)、稳定性等方面的仿真测试。提供了具体的Verilog、TCL和Spectre代码片段,帮助读者理解和实践这些复杂的电路特性。此外,还分享了一些实用的经验和技巧,如如何调整电阻比例、设置合适的仿真参数、处理潜在的振荡问题等。 适合人群:具有一定模拟电路基础知识的工程师和技术爱好者,尤其是对Bandgap带隙基准电路感兴趣的读者。 使用场景及目标:适用于希望深入了解Bandgap带隙基准电路的工作原理并掌握其仿真方法的人群。目标是在实践中提高电路设计能力,解决实际工程中的问题。 其他说明:文中不仅提供了理论知识,还包括大量实际操作步骤和代码示例,使读者能够在动手实践中加深理解。同时,强调了在GPDK45nm工艺下的特殊注意事项,为从事先进工艺电路设计的研究人员提供宝贵参考资料。
人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTo
路宁-驾驭大模型开发真实项目代码.pdf
包装类型.md