精华内容
下载资源
问答
  • 这个就是组件化,回归初心,从容器化到组件化,精华PPT,可以打开新世纪大门,彻底理解清楚这个容器化,插件化,组件化本质的关系与演进过程核心
  • 建议先看最后的总结再细读全文 目录1. ClassPathResource2. DefaultListableBeanFactory3....由上一篇文章得知,从 bean 的装配到获取,分别用到了三大组件: 资源抽象 Resource 工厂 DefaultListableBeanFactory.

    建议先看最后的总结再细读全文


    由上一篇文章得知,从 bean 的装配到获取,分别用到了三大组件:

    • 资源抽象 Resource
    • 工厂 DefaultListableBeanFactory
    • 配置信息读取器 BeanDefinitionReader
    public class SpringDemo {
    	public static void main(String[] args) {
    		// 1.指定加载的资源文件
    		Resource resource = new ClassPathResource("spring.xml");
    		// 2.创建管理bean的工厂
    		DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    		// 3.资源读取器,把读取的到信息装配到 defaultListableBeanFactory 里面,工厂再对 bean 进行管理
    		BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    		// 4.读取装配文件 xml 里面的信息
    		beanDefinitionReader.loadBeanDefinitions(resource);
    		// 5.获取 bean
    		Student student = defaultListableBeanFactory.getBean("student", Student.class);
    		System.out.println(student.getName());
    		System.out.println(student.getAge());
    	}
    }
    

    1. ClassPathResource

    接下来谈谈spring是如何通过 ClassPathResource 把资源加载进来。

    首先来看看源码:

    	private final String path;
    
    	@Nullable
    	private ClassLoader classLoader;
    
    	@Nullable
    	private Class<?> clazz;
    
    	public ClassPathResource(String path) {
    	    // 继续调用来下面的方法
    		this(path, (ClassLoader) null);
    	}
    	
    	public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
    	    // 断言
    		Assert.notNull(path, "Path must not be null");
    		// 判断这个路径是否为一个合法的路径,并解析成spring能识别的标准路径
    		String pathToUse = StringUtils.cleanPath(path);
    		if (pathToUse.startsWith("/")) {
    			pathToUse = pathToUse.substring(1);
    		}
    		// 已经是一个带解析并且能识别的path
    		this.path = pathToUse;
    		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    	}
    	
    	public ClassPathResource(String path, @Nullable Class<?> clazz) {
    		Assert.notNull(path, "Path must not be null");
    		this.path = StringUtils.cleanPath(path);
    		this.clazz = clazz;
    	}
    	
    

    从源码可以看出,ClassPathResource 可以通过给定 class 或者给定的 classloader来进行资源的加载。ClassPathResource 的 构造方法主要是判断加载资源的路径是否有误,然后由默认的线程上下文类加载器(在运行期间,可以动态地去改变类加载器加载地方式)加载资源。如果传过来的classloader是空的,则:

    	public static ClassLoader getDefaultClassLoader() {
    		ClassLoader cl = null;
    		try {
    			cl = Thread.currentThread().getContextClassLoader();
    		}
    		catch (Throwable ex) {
    			// Cannot access thread context ClassLoader - falling back...
    		}
    		if (cl == null) {
    			// No thread context class loader -> use class loader of this class.
    			cl = ClassUtils.class.getClassLoader();
    			if (cl == null) {
    				// getClassLoader() returning null indicates the bootstrap ClassLoader
    				try {
    					cl = ClassLoader.getSystemClassLoader();
    				}
    				catch (Throwable ex) {
    					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
    				}
    			}
    		}
    		return cl;
    	}
    

    从作者的源码和注释中可以看出,首先判断当前线程的上下文类加载器是否存在,若不存在,则使用当前 ClassUtils 的 classloader,cl还是为空则说明当前的 cl 是用到了 bootstrap classloader,如果一个类是通过bootstrap classloader 载入的,那我们通过这个类去获得classloader的话,有些jdk的实现是会返回一个null的。所以,如果以上都获取不到 classloader,最终会由 SystemClassLoader 系统类加载器 来进行加载。

    2. DefaultListableBeanFactory

    DefaultListableBeanFactory 是 BeanFactory 的一个默认实现类,它继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory, BeanDefinitionRegistry。

    defaultlistablebeanfactory.png

    DefaultListableBeanFactory构造函数源码分析

    public DefaultListableBeanFactory() {
    		super();
    	}
    

    这里的无参构造函数调用了父类的方法,继续分析:

    	public AbstractAutowireCapableBeanFactory() {
    		super();
    		ignoreDependencyInterface(BeanNameAware.class);
    		ignoreDependencyInterface(BeanFactoryAware.class);
    		ignoreDependencyInterface(BeanClassLoaderAware.class);
    	}
    

    可以看到创建了一个 AbstractAutowireCapableBeanFactory ,它 的无参构造方法除了继续调用了父类的方法之外,忽略掉了3个class文件,为了在依赖注入的时候不应该用这三种类型来进行依赖的注入。继续往上跟:

    	public AbstractBeanFactory() {
    	}
    

    只是创建了一个 AbstractBeanFactory 实例。

    3. BeanDefinitionReader 实现类 XmlBeanDefinitionReader

    实现类XmlBeanDefinitionReader构造方法源码分析:

    	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    		super(registry);
    	}
    

    把工厂一起传给了父类,继续往上跟:

    	protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    		this.registry = registry;
    
    		// Determine ResourceLoader to use.
    		if (this.registry instanceof ResourceLoader) {
    			this.resourceLoader = (ResourceLoader) this.registry;
    		}
    		else {
    			this.resourceLoader = new PathMatchingResourcePatternResolver();
    		}
    
    		// Inherit Environment if possible
    		if (this.registry instanceof EnvironmentCapable) {
    			this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    		}
    		else {
    			this.environment = new StandardEnvironment();
    		}
    	}
    

    这里可以看到通过 ResourceLoader 去加载资源文件并继承它的环境,判断是否实现了ResourceLoader,若没有,则:

    	public PathMatchingResourcePatternResolver() {
    		this.resourceLoader = new DefaultResourceLoader();
    	}
    
    	@Override
    	@Nullable
    	public ClassLoader getClassLoader() {
    		return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
    	}
    

    又回到了上面所说获取类加载器的方法,是一种典型的回退思想。这算是为工厂装配bean准备环境的一步。

    • EnvironmentCapable:如果可以的话 registry 把环境也继承了,如果没有则创建一个StandardEnvironment。

    4. XmlBeanDefinitionReader.loadBeanDefinitions()

    对 xml 文件信息整体的解析,将解析出来的xml信息装配成一个bean,并且把bean存放到工厂当中。看看 loadBeanDefinitions 做了哪些操作:

    	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    		return loadBeanDefinitions(new EncodedResource(resource));
    	}
    

    首先把 resource 传给 EncodedResource,让 EncodedResource 封装成一个真正带编码或者字符集的资源。且encoding 和 charset 是互斥关系:

    	public EncodedResource(Resource resource) {
    		this(resource, null, null);
    	}
    
    	public EncodedResource(Resource resource, @Nullable String encoding) {
    		this(resource, encoding, null);
    	}
    
    	public EncodedResource(Resource resource, @Nullable Charset charset) {
    		this(resource, null, charset);
    	}
    
    	private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
    		super();
    		Assert.notNull(resource, "Resource must not be null");
    		this.resource = resource;
    		this.encoding = encoding;
    		this.charset = charset;
    	}
    

    然后再调用重载的 loadBeanDefinitions

    	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    		Assert.notNull(encodedResource, "EncodedResource must not be null");
    		if (logger.isTraceEnabled()) {
    			logger.trace("Loading XML bean definitions from " + encodedResource);
    		}
    
    		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    
            // 防止循环依赖,因为set集合不可重复的原因,若集合中存在 encodedResource A,再次add A 的时候则会抛出异常
    		if (!currentResources.add(encodedResource)) {
    			throw new BeanDefinitionStoreException(
    					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    		}
    
            // 获取 encodedResource 里面 resource 的输入流
    		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
    		    // InputSource 用字节流创建一个新的输入源,是 org.xml.sax 提供的一个对象,并不是 spring 内部的
    			InputSource inputSource = new InputSource(inputStream);
    			// 这里我们传入的是 null
    			if (encodedResource.getEncoding() != null) {
    				inputSource.setEncoding(encodedResource.getEncoding());
    			}
    			// doLoadBeanDefinitions 方法在下文做出分析,实际是从指定的XML文件加载bean定义的方法
    			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    		}
    		catch (IOException ex) {
    			throw new BeanDefinitionStoreException(
    					"IOException parsing XML document from " + encodedResource.getResource(), ex);
    		}
    		finally {
    			currentResources.remove(encodedResource);
    			if (currentResources.isEmpty()) {
    			    // resourcesCurrentlyBeingLoaded 是 threadlocal 变量,remove 防止内存泄漏
    				this.resourcesCurrentlyBeingLoaded.remove();
    			}
    		}
    	}
    
    • doLoadBeanDefinitions
        // 实际从指定的XML文件加载 bean 定义的方法
    	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    			throws BeanDefinitionStoreException {
    
    		try {
    		    // 通过doLoadDocument加载inputSource资源,返回一个 doc 对象
    			Document doc = doLoadDocument(inputSource, resource);
    			// 注册给定DOM文档中包含的bean定义,完成对 xml 的解析
    			int count = registerBeanDefinitions(doc, resource);
    			if (logger.isDebugEnabled()) {
    				logger.debug("Loaded " + count + " bean definitions from " + resource);
    			}
    			return count;
    		}
    		catch (BeanDefinitionStoreException ex) {
    			throw ex;
    		}
    		catch (SAXParseException ex) {
    			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    		}
    		catch (SAXException ex) {
    			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    					"XML document from " + resource + " is invalid", ex);
    		}
    		catch (ParserConfigurationException ex) {
    			throw new BeanDefinitionStoreException(resource.getDescription(),
    					"Parser configuration exception parsing XML from " + resource, ex);
    		}
    		catch (IOException ex) {
    			throw new BeanDefinitionStoreException(resource.getDescription(),
    					"IOException parsing XML document from " + resource, ex);
    		}
    		catch (Throwable ex) {
    			throw new BeanDefinitionStoreException(resource.getDescription(),
    					"Unexpected exception parsing XML document from " + resource, ex);
    		}
    	}
    

    可以看出 doLoadBeanDefinitions 是对 spring 装配 bean 的主要实现。

    5. 总结

    通过上面的分析得知,spring 想要把 bean 注册到工厂,然后再从工厂中获取(IoC容器思想)具体需要以下操作(文中采取的是xml方式注入,和注解方式注入实质上原理一样):

    • 通过ClassPathResource 把 xml 配置文件加载进来,加载方式有两种:
      1. 通过默认的线程上下文类加载器(SystemClassLoader)
      2. 通过给定的 class 对象
    • 定义一个Bean工厂 DefaultListableBeanFactory用来装配和管理Bean的所有信息,指定注入的相关方式,但这时和资源文件还没有任何交互
    • 定义一个资源读取器BeanDefinitionReader,调用其实现类XmlBeanDefinitionReader把读取到的beans信息装配到DefaultListableBeanFactory,这时已经准备好了装配bean的加载器和环境并和bean工厂关联起来。
    • 通过调用XmlBeanDefinitionReader.loadBeanDefinitions()方法把加载进来xml资源解析并装配成bean,一同注册到DefaultListableBeanFactory。此过程中,底层还有很多操作,可以概括为先把 xml 转成 inputSource 流资源,再转化成相应的 doc 对象,最终在DefaultBeanDefinitionDocumentReader类中通过doRegisterBeanDefinitions 方法,递归遍历doc对象的所有节点和元素从而完成bean定义的注册。

    至此操作已全部完毕。

    展开全文
  • 前言 Engine容器 Host容器 前言 Connector把封装了Request对象...在说Container容器之前,有必要对Container容器有一个简单的了解,Container容器是子容器的父接口,所有的子容器都必须实现这个接口,在Tomcat...

    Tomcat


    前言

    Connector把封装了Request对象以及Response对象的Socket传递给了Container容器,那么在Contianer容器中又是怎么样的处理流程呢?在说Container容器之前,有必要对Container容器有一个简单的了解,Container容器是子容器的父接口,所有的子容器都必须实现这个接口,在Tomcat中Container容器的设计是典型的责任链设计模式,其有四个子容器:Engine、Host、Context和Wrapper。这四个容器之间是父子关系,Engine容器包含Host,Host包含Context,Context包含Wrapper。

    我们在web项目中的一个Servlet类对应一个Wrapper,多个Servlet就对应多个Wrapper,当有多个Wrapper的时候就需要一个容器来管理这些Wrapper了,这就是Context容器了,Context容器对应一个工程,所以我们新部署一个工程到Tomcat中就会新创建一个Context容器。Container容器的处理过程也比较复杂,下面是一个大概的流程:
    Container

    上面出现了Pipeline与Valve,这两个对象可以分别理解为管道与管道中闸门,当收到从Connector的请求后,这个请求要通过一个个管道以及管道中一个个的闸门,只有全部通过才能最终被具体的Servlet处理。要注意的是,每一个容器都有自己的管道和闸门,这些管道与闸门都是由容器自身老控制的,所以我们可以看到注入StandardEngineValve等类了。

    下面就从Container容器的四个子容器入手,分析每一个容器是怎么样处理的:

    Engine容器

    Engine容器包含Host容器,根据文章第一部分的架构图,可以知道其管理的容器是Host,Engine是一个接口,其标准实现类是StandardEngine,下面是其类结构图:
    Engine

    StandardEngine

    注意其中的addChild方法,其类型是Container,但是其实际管理的就是Host容器。Engine容器处理请求的流程可以简化如下:
    StandardEngine1

    在刚开始的流程图中调用了StandardEngineValve的invoke方法,这个方法的具体实现如何呢?

        /**
         * Select the appropriate child Host to process this request,
         * based on the requested server name.  If no matching Host can
         * be found, return an appropriate HTTP error.
         *
         * @param request Request to be processed
         * @param response Response to be produced
         *
         * @exception IOException if an input/output error occurred
         * @exception ServletException if a servlet error occurred
         */
        @Override
        public final void invoke(Request request, Response response)
            throws IOException, ServletException {
            // Select the Host to be used for this Request
            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());
            }
            // Ask this Host to process this request
            host.getPipeline().getFirst().invoke(request, response);
        }

    可以看到这个方法的任务就是选择可用的Host容器处理当前的请求,选择Host容器后,就调用其invoke方法,所以具体的处理就转移到了Host容器。


    Host容器

    Host容器是Engine容器的子容器,上面也说到Host是受Engine容器管理的,就是指一个虚拟主机,比如我们在访问具体jsp页面URL中localhost就是一个虚拟主机,其作用是运行多个应用,并对这些应用进行管理,其子容器是Context,而且一个主机还保存了主机的相关信息。Host的标准实现类是StandardHost,其闸门实现是StandardHostValve,下面是StandardHost与StandardHostValve的类结构图:

    StandardHost

    StandardHostValue

    Host容器的处理流程可以简化如下:
    StandardHostValue

    接着我们回到Engine容器的invoke方法,下面是host.getPipeline().getFirst().invoke(request, response)的方法源码:

        @Override
        public final void invoke(Request request, Response response)
            throws IOException, ServletException {
            // Select the Context to be used for this Request
            Context context = request.getContext();
            if (context == null) {
                response.sendError
                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                     sm.getString("standardHost.noContext"));
                return;
            }
            // Bind the context CL to the current thread
            if( context.getLoader() != null ) {
                // Not started - it should check for availability first
                // This should eventually move to Engine, it's generic.
                if (Globals.IS_SECURITY_ENABLED) {
                    PrivilegedAction<Void> pa = new PrivilegedSetTccl(
                            context.getLoader().getClassLoader());
                    AccessController.doPrivileged(pa);                
                } else {
                    Thread.currentThread().setContextClassLoader
                            (context.getLoader().getClassLoader());
                }
            }
            if (request.isAsyncSupported()) {
                request.setAsyncSupported(context.getPipeline().isAsyncSupported());
            }
            // Don't fire listeners during async processing
            // If a request init listener throws an exception, the request is
            // aborted
            boolean asyncAtStart = request.isAsync(); 
            // An async error page may dispatch to another resource. This flag helps
            // ensure an infinite error handling loop is not entered
            boolean errorAtStart = response.isError();
            if (asyncAtStart || context.fireRequestInitEvent(request)) {
                // Ask this Context to process this request
                try {
                    context.getPipeline().getFirst().invoke(request, response);
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    if (errorAtStart) {
                        container.getLogger().error("Exception Processing " +
                                request.getRequestURI(), t);
                    } else {
                        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
                        throwable(request, response, t);
                    }
                }
    
                // If the request was async at the start and an error occurred then
                // the async error handling will kick-in and that will fire the
                // request destroyed event *after* the error handling has taken
                // place
                if (!(request.isAsync() || (asyncAtStart &&
                        request.getAttribute(
                                RequestDispatcher.ERROR_EXCEPTION) != null))) {
                    // Protect against NPEs if context was destroyed during a
                    // long running request.
                    if (context.getState().isAvailable()) {
                        if (!errorAtStart) {
                            // Error page processing
                            response.setSuspended(false);
    
                            Throwable t = (Throwable) request.getAttribute(
                                    RequestDispatcher.ERROR_EXCEPTION);
    
                            if (t != null) {
                                throwable(request, response, t);
                            } else {
                                status(request, response);
                            }
                        }
    
                        context.fireRequestDestroyEvent(request);
                    }
                }
            }
            // Access a session (if present) to update last accessed time, based on a
            // strict interpretation of the specification
            if (ACCESS_SESSION) {
                request.getSession(false);
            }
            // Restore the context classloader
            if (Globals.IS_SECURITY_ENABLED) {
                PrivilegedAction<Void> pa = new PrivilegedSetTccl(
                        StandardHostValve.class.getClassLoader());
                AccessController.doPrivileged(pa);                
            } else {
                Thread.currentThread().setContextClassLoader
                        (StandardHostValve.class.getClassLoader());
            }
        }

    其处理过程可以总结如下:

    1. 为特定的请求URL选择一个Context容器
    2. 把Context容器绑定到线程中
    3. 判断是否是一个异步请求
    4. 让Context去处理这个请求
    5. Context执行invoke方法,进入管道中,由StandardContextValve(是ContextValve的标准实现类)处理



    原文博主:rhwayfunn

    展开全文
  • Docker的三大核心组件:镜像、容器与仓库
    展开全文
  • 容器(Container): 容器的存在离不开镜像的支持,它是镜像运行时的一个载体。容器可以被创建、启动、停止、删除、暂停等。这些容器彼此之间相互隔离、互不可见的。 Docker容器有一个设计上的机制,即容器与应用...

    容器(Container):

    容器的存在离不开镜像的支持,它是镜像运行时的一个载体。容器可以被创建、启动、停止、删除、暂停等。这些容器彼此之间相互隔离、互不可见的。

    Docker容器有一个设计上的机制,即容器与应用是同生共死的。当容器的应用都关闭,停止运行了,那么容器也会跟着自动退出,停止运行。

    镜像和容器的关系:就像是面向对象程序设计中的类和实例一样。

    • 镜像是静态的定义,里边有应用。
    • 容器是动态的,是镜像运行时的实体。

     

    一、容器的创建/启动/暂停/终止

    创建容器和启动容器两个命令可以使用一个 run命令搞定,它们支持参数相同。容器使用别名和id都可以

    1、创建容器 - docker create 命令

    创建一个新的容器但不启动它,返回容器的id,不指定名字时,自动生成。

    基本语法:docker  [container] create [OPTIONS] IMAGE

    [root@centos7 ~]# docker create -it centos:7
    c26038331db72bffd851c380bde4d554270e49085ba87f34a7f25e0bf0bdad9a
    [root@centos7 ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    c26038331db7        centos:7            "/bin/bash"         49 seconds ago      Created                                 keen_kare

    2、启动容器 - docker  start 命令

    启动一个或多个已经被停止的容器,使用容器的id或者name都可以。

    基本语法:docker  [container] start [OPTIONS] CONTAINER [CONTAINER...]

    [root@centos7 ~]# docker start c26038331db7
    c26038331db7
    [root@centos7 ~]# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    c26038331db7        centos:7            "/bin/bash"         3 minutes ago       Up 5 seconds 

    3、进入容器 - docker attach 命令

    连接上正在运行中的容器。注意,与 docker exec 的区别,推荐使用 docker exec命令。

    基本语法:docker [container] attach [OPTIONS] CONTAINER

    [root@c26038331db7 /]# read escape sequence
    [root@centos7 ~]# docker attach c26038331db7
    [root@c26038331db7 /]# read escape sequence
    [root@centos7 ~]#

    使用 ctrl+q+p 暂时退出容器,但是正在运行中的容器不会关闭。 

    4、暂停容器 - docker stop 命令

    暂停一个运行中的容器,并暂停容器中所有的进程。

    基本语法:docker  [container] pause [OPTIONS] CONTAINER [CONTAINER...]

    [root@centos7 ~]# docker pause c26038331db7

    5、恢复容器 - docker unpause命令

    将一个处于paused状态的容器恢复到运行状态,并恢复容器中所有的进程。

    基本语法:docker [container] unpause [OPTIONS] CONTAINER [CONTAINER...]

    [root@centos7 ~]# docker unpause c26038331db7

    6、终止容器 - docker stop 命令

    停止一个运行中的容器。该命令首先会向容器发送SIGTERM信号,等待一段超时时间后(默认为10秒),再发送SIGKILL信号来终止容器。

    基本语法:docker  [container] stop [OPTIONS] CONTAINER [CONTAINER...]

    [root@centos7 ~]# docker stop c26038331db7

    7、重启容器 - docker  restart 命令

    该命令是将一个运行态的容器先终止,然后再重新启动容器。

    基本语法:docker  [container] restart [OPTIONS] CONTAINER [CONTAINER...]

    [root@centos7 ~]# docker restart c26038331db7

    8、退出容器 - exit命令或者使用 Ctrl + D

    使用 docker attach命令进入容器使用 exit退出容器时,会终止容器。

    使用 docker exec命令进入容器使用 exit退出容器时,不会终止容器。

    [root@centos7 ~]# docker attach c26038331db7
    [root@c26038331db7 /]# exit 
    exit
    [root@centos7 ~]# docker ps -a 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
    2150d7c2b218        centos:7            "/bin/bash"         55 minutes ago      Up 55 minutes                                  centos7
    c26038331db7        centos:7            "/bin/bash"         About an hour ago   Exited (0) 9 seconds ago                       keen_kare

    9、杀死/终止容器 - docker kill 命令

    杀掉一个运行中的容器。该命令会直接发送 SIGKILL信号来强行终止容器。

    基本语法:docker [container] kill [OPTIONS] CONTAINER [CONTAINER...]

    OPTIONS说明:

    • -s :向容器发送一个信号
    [root@centos7 ~]# docker restart c26038331db7
    c26038331db7
    [root@centos7 ~]# docker kill -s KILL c26038331db7
    c26038331db7
    [root@centos7 ~]# docker ps -a 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
    2150d7c2b218        centos:7            "/bin/bash"         57 minutes ago      Up 57 minutes                                    centos7
    c26038331db7        centos:7            "/bin/bash"         About an hour ago   Exited (137) 4 seconds ago                       keen_kare

    10、删除容器 - docker rm 命令

    删除一个或多个容器。

    基本语法:docker [container] rm [OPTIONS] CONTAINER [CONTAINER...]

    OPTIONS说明:

    • -f, -- force=false :通过 SIGKILL 信号强制删除一个运行中的容器。
    • -l,--link=false :移除容器间的网络连接,而非容器本身。
    • -v, --volumes=false:删除与容器关联的数据卷。
    [root@centos7 ~]# docker rm -f dc87c233e993
    dc87c233e993

    批量删除所有容器:

    两条命令实现停用并删除容器,先终止容器,在批量删除。

    [root@centos7 ~]#  docker kill $(docker ps -q) 

    [root@centos7 ~]#  docker rm $(docker ps -aq) 

     

    二、docker run 命令

    基本语法:docker [container] run [OPTIONS] IMAGE [COMMAND] [ARG...]

    create命令和run命令支持的选项相同且非常多,这里列举出来,和参数配合使用还有更多功能,在使用中一个一个熟悉。

    这些选项主要包括如下几大类:与容器运行模式相关、与容器环境配置相关、与容器资源限制和安全保护相关。

    图片来自网络(感谢),也可查看官网:https://docs.docker.com/engine/reference/commandline/run/

    1、交互模式创建并启动容器 

    [root@centos7 ~]# docker run -it --name centos7 centos:7 /bin/bash
    [root@2150d7c2b218 /]# 
    [root@2150d7c2b218 /]# ls
    anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    [root@centos7 ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    2150d7c2b218        centos:7            "/bin/bash"         30 seconds ago      Up 30 seconds                           centos7

     参数:

    • -t:让Doker分配一个伪终端并绑定到容器的标准输入上, 
    • -i:让容器的标准输人保持打开。
    • --name '':给容器起别名

    该命令会创建一个新的容器并运行它。将上面提到了创建和启动容器的两条命令合为一条命令来实现。

    这样创建的容器是交互式的,可以通过保持开启的容器的标准输入,输入命令进入到容器里,命令在容器里执行的结果,也可以通过伪终端,显示出来。后面的/bin/bash(Centos)可以省略的,-it不可省略(交互式的)。

    例如:使用容器输出一个"Hello Docker",之后容器自动终止。

    [root@centos7 ~]# docker run centos:7 /bin/echo 'Hello Docker' 
    Hello Docker
    [root@centos7 ~]# /bin/echo 'Hello Docker' 
    Hello Docker

    这个docker run 和在宿主机中直接执行/bin/echo 'hello Docker' ,的运行机制是不一样。

    当利用 docker run 命令来创建并启动容器时,Docker 在后台运行的标准操作包括:

    • 检查本地是否存在指定的镜像,不存在就从公有仓库下载;
    • 利用镜像创建一个容器,并启动该容器;
    • 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
    • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
    • 从网桥的地址池配置一个 IP地址给容器;
    • 执行用户指定的应用程序;
    • 执行完毕后容器被自动终止。

    2、守护态创建并启动容器 

    通过过使用 -d 参数来实现,让Docker容器在后台以守护态(Daemonized)形式运行。

    [root@centos7 ~]# docker run -d --name ctos7 centos:7

    例如:通过sh在后台运行容器

    [root@centos7 ~]# docker run -d --name shctos7 centos:7 /bin/sh -c "while true; do echo hello world; sleep 1;done"
    dc87c233e993440395b28f3e395b21ef16393049056dcc16ffae7c17e793fdc7
    [root@centos7 ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
    dc87c233e993        centos:7            "/bin/sh -c 'while t…"   18 seconds ago      Up 17 seconds                                     shctos7

     

    三、查看容器信息

    1、列出已有容器 - docker ps 命令

    基本语法:docker [container] ps [OPTIONS]

    OPTIONS说明:

    • -a :显示所有的容器,包括未运行的。
    • -f :根据条件过滤显示的内容。
    • --format :指定返回值的模板文件。
    • -l :显示最近创建的容器。
    • -n  N:列出最近创建的N个容器。
    • --no-trunc :不截断输出。
    • -q :静默模式,只显示容器编号。
    • -s :显示总的文件大小。

    例如:列出所有的容器,包括未运行的。

    [root@centos7 ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
    dc87c233e993        centos:7            "/bin/sh -c 'while t…"   4 minutes ago       Up 4 minutes                                      shctos7
    2d2696e48c0a        centos:7            "/bin/bash"              7 minutes ago       Exited (0) 7 minutes ago                          ctos7
    2150d7c2b218        centos:7            "/bin/bash"              About an hour ago   Up About an hour                                  centos7
    c26038331db7        centos:7            "/bin/bash"              About an hour ago   Exited (137) 15 minutes ago                       keen_kare

    输出详情介绍:

    CONTAINER ID: 容器 ID。

    IMAGE: 使用的镜像。

    COMMAND: 启动容器时运行的命令。

    CREATED: 容器的创建时间。

    STATUS: 容器状态。状态有7种:

    • created(已创建)
    • restarting(重启中)
    • running(运行中)
    • removing(迁移中)
    • paused(暂停)
    • exited(停止)
    • dead(死亡)

    PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

    NAMES: 自动分配的容器名称。

    2、查看某容器元数据 - docker inspect 命令

    基本语法:docker [container] inspect  CONTAINER  [CONTAINER...]

    例如,查看某容器的具体信息,会以json格式返回包括容器Id、创建时间、路径、状态、镜像、配置等在内的各项信息:

    [root@centos7 ~]# docker inspect c26038331db7

    3、查看某容器内进程 - docker top命令

    查看容器中正在运行的进程信息,支持 ps 命令参数。

    基本语法:docker [container]  top [OPTIONS] CONTAINER [ps OPTIONS]

    该命令类似于Linux系统中的top命令,会打印出容器内的进程信息,包括PID、用户、时间、命令等。

    例如,查看某容器内的进程信息:

    [root@centos7 ~]# docker top 2150d7c2b218
    UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
    root                8701                8682                0                   16:01               pts/0               00:00:00            /bin/bash

    4、查看统计信息 - docker stats 命令

    查看统计信息,会显示CPU、内存、存储、网络等使用情况的统计信息。

    基本语法:docker  [container]  stats   [OPTIONS] [CONTAINER]

    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
    2150d7c2b218        centos7             0.00%               412KiB / 972.6MiB   0.04%               656B / 0B           0B / 0B             1
    ^C

    5、查看某容器的日志 - docker logs 命令

    获取某容器的日志输出信息。

    基本语法:docker [container] logs [OPTIONS] CONTAINER

    OPTIONS说明:

    • -f, -follow: 跟踪日志输出,持续保持输出
    • --since :显示某个开始时间的所有日志
    • -t,-timestamps: 显示时间戳
    • --tail=N :仅列出最新N条容器日志

    例如,查看上面通过sh在后台运行容器的输出可以使用如下命令:

    [root@centos7 ~]# docker logs -f -t --tail 5 dc87c233e993
    2020-09-13T09:13:33.445328235Z hello world
    2020-09-13T09:13:34.447724889Z hello world
    2020-09-13T09:13:35.449986082Z hello world
    2020-09-13T09:13:36.452266126Z hello world
    2020-09-13T09:13:37.454349812Z hello world

    四、导入导出容器

    1、导出容器 - docker export 命令

    将指定容器保存成 tar 归档文件(实质上就是容器快照),会丢弃容器的元数据。这个本地文件可以分享给他人使用。不管此时这个容器是否处于运行状态都可导出。

    基本语法:docker [container] export [OPTIONS] CONTAINER

    OPTIONS说明:

    • -o :将输入内容写到文件
    [root@centos7 ~]# docker export -o /root/abc/kz_centos7.tar centos7
    [root@centos7 ~]# ls /root/abc/ | grep kz_
    kz_centos7.tar

    通过 docker  commit命令将运行中的容器,生成镜像文件,然后通过导入导出镜像文件也可实现。

    docker  commit和docker export命令的主要区别:

    • docker export不管容器运行否都可以导出,docker  commit只有运行中的容器才可以使用。
    • docker export生成的容器快照文件将丟弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),docker  commit生成的镜像存储文件将保存完整记录,体积更大。

    2、导入容器 - docker import 命令

    导出的 tar文件导入到本地镜像库,创建成为镜像文件。

    基本语法:docker [container] import [OPTIONS] file

    [root@centos7 ~]# docker import /root/abc/kz_centos7.tar
    sha256:bcd3bedadf42beacf05cdf5f3ad29bfd5f79724f7f50482d4aadeaa56247cb7d
    [root@centos7 ~]# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    <none>              <none>              bcd3bedadf42        12 seconds ago      203MB
    [root@centos7 ~]# docker tag bcd3bedadf42 kc_ctos:7
    [root@centos7 ~]# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    kc_ctos             7                   bcd3bedadf42        2 minutes ago       203MB
    [root@centos7 ~]# docker create -it kc_ctos:7
    Error response from daemon: No command specified
    [root@centos7 ~]# docker run -it bcd3bedadf42
    docker: Error response from daemon: No command specified.
    See 'docker run --help'.

    注意:

    • 导出的容器tar文件,会丢失元数据信息,所以,必须给它添加标记之后才能使用。
    • 用导入成为的镜像文件来创建新容器并运行时。不能省略后面的子命令/bin/bash(centos)。
    [root@centos7 ~]# docker create -it kc_ctos:7 /bin/bash
    50eee11dc878d77097176d43f85823e9709df9c88adcdd436ad3be5a017002c5
    [root@centos7 ~]# docker run -it --name 'kc7' kc_ctos:7 /bin/bash         
    [root@270aba119a53 /]# 

     

    五、其他容器命令

    1、在容器中执行命令 - docker exec 命令(推荐使用 )

    在正在运行的容器中执行子命令。

    基本语法:docker [container] exec [OPTIONS] CONTAINER COMMAND [ARG...]

    OPTIONS说明:

    • -d, --detach:分离模式: 在后台运行
    • -i :打开标准输人接受用户输人命令
    • -t,--tty=true | false:分配一个伪终端

    例如:执行伪终端,进入到正在运行的容器中(交互模式)。

    [root@centos7 ~]# docker exec -it centos7 /bin/bash
    [root@2150d7c2b218 /]# exit
    [root@centos7 ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    2150d7c2b218        centos:7            "/bin/bash"         7 minutes ago      Up 30 seconds                           centos7
    

    注意:

    • 如果从这个容器使用 exit命令退出,不会导致容器的停止。
    • 如果从这个容器使用 exit命令退出,会导致容器的停止。 

    2、复制文件 - container cp命令

    用于容器与宿主机之间的数据文件拷贝。

    基本语法:

    docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

    docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

    OPTIONS说明:

    • -a, -archive: 打包模式,复制文件会带有原始的uid/gid信息;
    • -L,-follow-link :跟随软连接。当原路径为软连接时,默认只复制链接信息,使用该选项会复制链接的目标内容。

    例如:将宿主机本地的目录复制到test容器的/tmp路径下,并改名

    [root@centos7 ~]# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    2150d7c2b218        centos:7            "/bin/bash"         3 hours ago         Up 3 hours                              centos7
    [root@centos7 ~]# docker cp /root/abc/ 2150d7c2b218:/tmp/copy_abc
    [root@2150d7c2b218 /]# ls
    anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    [root@2150d7c2b218 /]# ls /tmp
    copy_abc  ks-script-V_wEqJ  yum.log

    例如:将test容器的/tmp下的目录复制到宿主机本地的/root下:

    [root@centos7 ~]# docker cp 2150d7c2b218:/tmp/copy_abc /root/
    [root@centos7 ~]# ls /root/ | grep abc
    abc
    copy_abc

    3、检查容器里文件结构的更改- docker diff 命令

    查看容器内文件结构的变更信息。

    基本语法:docker [container]  diff [OPTIONS] CONTAINER

    [root@centos7 ~]# docker diff 2150d7c2b218
    C /tmp
    A /tmp/copy_abc
    A /tmp/copy_abc/aa_dir.tar
    A /tmp/copy_abc/aa_dir.tar.bz2
    A /tmp/copy_abc/bb_dir
    A /tmp/copy_abc/file2.cfg
    A /tmp/copy_abc/jqcontosv7.tar
    A /tmp/copy_abc/kz_centos7.tar

     

    —— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。

    展开全文
  • 先看一下之前我们怎么使用spring来做...2)引入spring核心容器环境依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <...
  • 一:pod核心原理1:pod是什么Pod 是一组容器和卷(目录和文件)的集合,同一个Pod里的容器共享同一个网络命名空间,可以使用 localhost 互相通信pod是k8s管理的最小的单位pod也是一个容器,这个容器装的是docker创建的...
  • 镜像(Image),容器(Container),仓库(Repository)是我们常说的Docker的三大组件,其实我们在上一篇文章《10分钟快速掌握Docker必备基础知识》已经有简单地了解过三大组件的知识,但是并没有很详细地讲解,所以在这篇...
  • 一:pod核心原理1:pod是什么Pod 是一组容器和卷(目录和文件)的集合,同一个Pod里的容器共享同一个网络命名空间,可以使用 localhost 互相通信pod是k8s管理的最小的单位pod也是一个容器,这个容器装的是docker创建的...
  • 一. 概述 Spring容器通常指的是ApplicationContext的体系结构... 在Spring框架内部设计当中,ApplicationContext是Spring容器所管理、维护的beans对象的一个运行环境,即ApplicationContext包含一些功能组件:保存外
  • Docker 的核心组件包括: Docker 客户端 - Client Docker 服务器 - Docker daemon Docker 镜像 - Image Registry仓库 Docker 容器 - Container Docker 客户端 最常用的 Docker 客户端是 docker 命令。通过 docker...
  • Spring的IoC容器是Spring的核心,IOC(Inversion of Control )控制反转的。IoC和DI(Dependency Injection)是一个意思,也就是说对象定义它们的依赖(也就是和它们一起干活的其他对象),Spring容器会把这些依赖给...
  • Docker核心组件

    2020-12-28 20:30:06
    Docker核心组件 1. Docker架构 Docker使用客户端 - 服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器
  • 镜像(Image),容器(Container),仓库(Repository)是我们常说的Docker的三大组件,其实我们在上一篇文章《10分钟快速掌握Docker必备基础知识》已经有简单地了解过三大组件的知识,但是并没有很详细地讲解,所以在这篇...
  • Spring核心组件

    2019-04-09 11:03:49
    一 Spring核心组件 Bean spring是面向bean的编程(bean oriented programming) 将对象之间的依赖关系转而用配置文件来管理(IOC) bean的配置由BeanDefinition对象描述. beanFactory是spring提供的基本IOC容器,...
  • 镜像(Image)、容器(Container)、仓库(Repository)是我们常说的Docker的三大组件,其实我们在上一篇文章《10分钟快速掌握Docker必备基础知识》已经有简单地了解过三大组件的知识,但是并没有很详细地讲解,所以在这篇...
  • spring核心组件.txt

    2019-09-30 14:41:18
    描述了spring的两大核心组件,包括了spring中的IOC控制反转以及DI容器注入,以及springAop面向切面
  • Tomcat核心组件

    2020-07-22 13:58:47
    Tomcat相信对于所有小伙伴来说都不陌生,它是一个基于JAVA的WEB容器,其实现了JAVA EE中的 Servlet 与 jsp 规范,与Nginx apache 服务器不同在于一般用于动态请求处理。在架构设计上采用面向组件的方式设计。即整体...
  • Spring 核心组件

    2020-09-04 21:46:15
    1、核心容器:Spring启动的最基本条件 Spring-Core:核心工具类,Spring其他模块大量使用Spring-Core; Spring-Beans:Spring创建类对象并管理对象 Spring-Context:运行时Spring容器;获取外部资源、管理注解...
  • 在kubernetes集群中,每个Node节点都会启动kubelet进程,用来处理Master节点下发到本节点的任务,管理Pod和其中的容器。kubelet会在API Server上注册节点信息,定期向Master汇报节点资源使用情况,并通过cAdvisor...
  • kubernetes核心组件

    2020-03-01 09:14:21
    kubernetes的核心功能: 服务发现与负载均衡 容器自动装箱 scheduling 就是调度,把一个容器放到一个集群的某一个机器上,kubernetes会帮助我们做储存的编排,让储存声明周期能有一个连接 kubernetes 会帮助我们去做...
  • 3. 安装Docker容器... 2 4. 安装dotnet镜像... 3 5. 复制iNeuKernel到容器中... 4 6. 进入指定容器... 4 7. 安装dotnet框架... 4 8. 在Docker容器中运行iNeuKernel物联网框架... 5 1. 概述 最近有客户需求:把...
  • 本节书摘来自华章出版社《开源容器云OpenShift:构建基于Kubernetes的企业应用云平台...3.2 核心组件详解 OpenShift的核心组件及其之间的关联关系如图3-2所示。OpenShift在容器编排层使用了Kubernetes,所以OpenShi...
  • 2.2 容器的优势2.3 容器的工作原理2.3.1 Docker 的架构和核心组件2.3.2 Docker 客户端2.3.3 Docker 服务器2.3.4 Docker 服务器允许远程访问2.3.5 Docker 镜像2.3.6 Docker 容器2.3.7 Docker 镜像仓 - Registry2.3.8 ...
  • Spring 核心组件与常用模块 核心组件 常用模块 核心容器 核心容器提供了Spring框架的基本功能。 核心容器的主要组件是BeanFactory,它是工厂模式的实现。 BeanFactory使用IOC模式将应用程序的配置和依赖性规范与...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,351
精华内容 1,740
关键字:

容器核心组件