凉衫薄

人生哪能多如意,万事只求半称心。
最新文章
一、简介 在传统的开发模式中,需要在代码中手动new对象,这样不仅不美观,而且不易于维护。有了IoC,我们可以将对象的管理与维护交给容器管理,使得程序的设计更加地解耦合。为了让大家更好地理解IoC原理,我参考了Spring IoC源码和网络上的一些例子,这篇文章将会教大家如何从零开始手动构建我们自己的Spring框架,其中我去除了源码中一些复杂的特性和设计模式,争取以最简洁易懂的方式实现IoC。接下来,我还会陆续完成AOP,MVC等常用Spring模块的从零构建。不要害怕重复造轮子,手撸框架是一件很伟大的事情。完整版的代码已经上传到个人GitHub,请点击这里。 二、代码结构 └─java └─net.stackoverflow.summer ├─aop (aop模块相关代码) │ ├─beans (IoC模块相关代码) │ ├─core (核心) │ │ AbstractBeanDefinitionReader.java bean定义信息读取器抽象类 │ │ BeanDefinition.java bean定义信息类 │ │ BeanDefinitionReader.java bean定义信息读取器接口 │ │ BeanReference.java bean依赖参照类 │ │ XmlAttributeConstant.java Xml配置文件属性常量定义 │ │ XmlBeanDefinitionReader.java 基于xml配置方式bean定义信息读取器 │ │ │ ├─factory (工厂类) │ │ AbstractBeanFactory.java 抽象bean工厂类 │ │ BeanFactory.java bean工厂接口 │ │ XmlBeanFactory.java 基于xml配置bean工厂类 │ │ │ └─io (输入输出相关) │ ClassPathResource.java 类路径资源 │ Resource.java 资源接口 │ ResourceLoader.java 资源加载器 │ ├─context (context模块) │ AbstractApplicationContext.java 应用上下文抽象类 │ ApplicationContext.java 应用上下文接口 │ ClassPathXmlApplicationContext.java Xml配置方式应用上下文 │ └─mvc (MVC模块) 三、重要接口和组件设计 BeanDefinition:首先我们需要一个类来保存bean的元数据,所谓元数据就是描述数据的数据,其中包括bean的全限定名,Class对象,是否懒加载,是否多例或单例,属性等,源码如下: public class BeanDefinition { //bean实例 private Object bean; //bean的Class对象 private Class beanClass; //bean的全限定名 private String className; //是否懒加载 private boolean lazyInit; //bean的属性信息 private Map<String, Object> properties; public BeanDefinition() { this.properties = new HashMap<>(); this.lazyInit = false; } public Object getBean() { return bean; } public void setBean(Object bean) { this.bean = bean; } public Class getBeanClass() { return this.beanClass; } public void setClassName(String name) { this.className = name; try { this.beanClass = Class.forName(name); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public String getClassName() { return this.className; } public Map<String, Object> getProperties() { return properties; } public void setProperties(Map<String, Object> properties) { this.properties = properties; } public boolean isLazyInit() { return lazyInit; } public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } } BeanReference:使用过Spring的人都知道有些bean的属性是另一个bean,另一个bean在其他地方定义了,这时候我们需要通过参照引用过来,BeanReference就是用来描述参照信息的一个类,源码如下: public class BeanReference { private String name; private Object bean; public BeanReference(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void setBean(Object bean) { this.bean = bean; } public Object getBean() { return this.bean; } } XmlBeanDefinitionReader:有了元数据和参照的定义,我们该考虑如何从配置中读取这些信息。从该类的类名可以看出这是一个BeanDefition的读取器,并且还是从Xml配置文件中读取的。该类继承了AbstractBeanDefinitionReader,且实现了BeanDefinitionReader接口,这样设计的目的考虑到将来从其他途径读取BeanDefinition的扩展,比如AnnotationConfigBeanDefinitionReader就是从注解配置信息来读取我们的BeanDefinition,源码如下: public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { public XmlBeanDefinitionReader(ResourceLoader resourceLoader) { super(resourceLoader); } /** * 从路径中读取xml配置文件 * * @param location xml配置文件路径 * @throws Exception 异常 */ public void readXml(String location) throws Exception { InputStream inputstream = getResourceLoader().getResource(location).getInputStream(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.parse(inputstream); registerBeanDefinitions(doc); inputstream.close(); } /** * 注册BeanDefinition * * @param doc xml文档对象 */ private void registerBeanDefinitions(Document doc) { Element root = doc.getDocumentElement(); parseBeanDefinitions(root); } /** * 从bean节点中解析BeanDefinition * * @param root 根节点对象 */ private void parseBeanDefinitions(Element root) { NodeList nl = root.getElementsByTagName(XmlAttributeConstant.BEAN); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element element = (Element) node; processBeanDefinition(element); } } } /** * 处理BeanDefinition,解析id,class,lazy-init等属性 * * @param element xml配置文件中的 bean 节点 */ private void processBeanDefinition(Element element) { String id = element.getAttribute(XmlAttributeConstant.ID); String className = element.getAttribute(XmlAttributeConstant.CLASS); BeanDefinition beanDefinition = new BeanDefinition(); String lazyInit = element.getAttribute(XmlAttributeConstant.LAZY_INIT); if (lazyInit != null && lazyInit.equals("true")) { beanDefinition.setLazyInit(true); } beanDefinition.setClassName(className); addProperty(element, beanDefinition); getRegistry().put(id, beanDefinition); } /** * 给 beanDefinition 添加属性 * * @param element bean节点对象 * @param beanDefinition beanDefinition对象 */ private void addProperty(Element element, BeanDefinition beanDefinition) { NodeList propertyNode = element.getElementsByTagName(XmlAttributeConstant.PROPERTY); for (int i = 0; i < propertyNode.getLength(); i++) { Node node = propertyNode.item(i); if (node instanceof Element) { Element propertyEle = (Element) node; String name = propertyEle.getAttribute(XmlAttributeConstant.NAME); String value = propertyEle.getAttribute(XmlAttributeConstant.VALUE); if (value != null && value.length() > 0) { beanDefinition.getProperties().put(name, value); } else { String ref = propertyEle.getAttribute(XmlAttributeConstant.REFERENCE); if (ref == null || ref.length() == 0) { throw new IllegalArgumentException("参数ref不能为空"); } BeanReference beanRef = new BeanReference(name); beanDefinition.getProperties().put(name, beanRef); } } } } } XmlBeanFactory:现在我们已经能够从配置信息中读取我们的BeanDefinition了,接下来我们需要根据这些bean的定义来生成bean实例。XmlBeanFactory是一个从Xml配置中生成bean的工厂类,它用来生成bean,并将bean注册到容器。该类继承自AbstractBeanFactory抽象类,并实现了BeanFactory接口,目的同样是考虑将来的扩展性,因为将来还可能会有AnnotationConfigBeanFactory,从注解配置中生成bean的工厂类等,源码如下: public class XmlBeanFactory extends AbstractBeanFactory { /** * 根据bean定义信息创建bean实例(忽略懒加载) * * @param beanDefinition beanDefinition对象 * @return 返回bean实例 * @throws Exception 异常 */ @Override protected Object createBean(BeanDefinition beanDefinition) throws Exception { Object bean = beanDefinition.getBeanClass().newInstance(); for (Map.Entry<String, Object> entry : beanDefinition.getProperties().entrySet()) { Field declaredField = bean.getClass().getDeclaredField(entry.getKey()); declaredField.setAccessible(true); Object value = entry.getValue(); if (value instanceof BeanReference) { BeanReference beanReference = (BeanReference) value; value = getBean(beanReference.getName()); beanReference.setBean(value); } declaredField.set(bean, value); } return bean; } /** * 根据bean定义信息创建bean实例(不忽略懒加载) * * @param beanDefinition beanDefinition对象 * @return 返回bean实例 * @throws Exception 异常 */ @Override protected Object createBeanLazy(BeanDefinition beanDefinition) throws Exception { Object bean = beanDefinition.getBeanClass().newInstance(); for (Map.Entry<String, Object> entry : beanDefinition.getProperties().entrySet()) { Field declaredField = bean.getClass().getDeclaredField(entry.getKey()); declaredField.setAccessible(true); Object value = entry.getValue(); if (value instanceof BeanReference) { BeanReference beanReference = (BeanReference) value; BeanDefinition definition = registry.get(entry.getKey()); if (definition.isLazyInit()) { value = null; } else { value = getBeanLazy(beanReference.getName()); beanReference.setBean(value); } } declaredField.set(bean, value); } return bean; } } AbstractBeanFactory:这个是bean工厂类的抽象类,实现了BeanFactory中的接口,并对子类提供了一些公共的方法和抽象方法,源码如下: public abstract class AbstractBeanFactory implements BeanFactory { //bean容器 protected Map<String, BeanDefinition> registry = new HashMap<>(); /** * 根据名称(id)获取bean实例(不忽略懒加载) * * @param name 名称(id) * @return 返回bean实例 * @throws Exception 异常 */ protected Object getBeanLazy(String name) throws Exception { BeanDefinition beanDefinition = registry.get(name); if (beanDefinition == null) { throw new IllegalArgumentException("未定义的bean"); } Object bean = beanDefinition.getBean(); if (bean == null && !beanDefinition.isLazyInit()) { bean = createBeanLazy(beanDefinition); beanDefinition.setBean(bean); registry.put(name, beanDefinition); } return bean; } /** * 根据bean名称(id)获取bean实例 * * @param name bean名称(id) * @return 返回bean实例 * @throws Exception 异常 */ @Override public Object getBean(String name) throws Exception { BeanDefinition beanDefinition = registry.get(name); if (beanDefinition == null) { throw new IllegalArgumentException("未定义的bean"); } Object bean = beanDefinition.getBean(); if (bean == null) { bean = createBean(beanDefinition); beanDefinition.setBean(bean); registry.put(name, beanDefinition); } else { checkReference(bean, beanDefinition); } return bean; } /** * 检查bean依赖的参照对象是否为空 * * @param bean 被检查的bean对象 * @param beanDefinition beanDefinition对象 * @throws Exception 异常 */ protected void checkReference(Object bean, BeanDefinition beanDefinition) throws Exception { for (Map.Entry<String, Object> entry : beanDefinition.getProperties().entrySet()) { Field declaredField = bean.getClass().getDeclaredField(entry.getKey()); declaredField.setAccessible(true); Object value = entry.getValue(); if (value instanceof BeanReference) { BeanReference beanReference = (BeanReference) value; if (beanReference.getBean() == null) { value = getBean(beanReference.getName()); beanReference.setBean(value); declaredField.set(bean, value); } else { checkReference(beanReference.getBean(), registry.get(beanReference.getName())); } } } } /** * 向容器注册bean定义信息 * * @param name bean名称(id) * @param beanDefinition beanDefinition对象 * @throws Exception 异常 */ public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception { if (!beanDefinition.isLazyInit()) { Object bean = createBeanLazy(beanDefinition); beanDefinition.setBean(bean); } registry.put(name, beanDefinition); } /** * 根据bean定义信息创建bean实例(忽略懒加载) * * @param beanDefinition beanDefinition对象 * @return 返回bean实例 * @throws Exception 异常 */ protected abstract Object createBean(BeanDefinition beanDefinition) throws Exception; /** * 根据bean定义信息创建bean实例(不忽略懒加载) * * @param beanDefinition beanDefinition对象 * @return 返回bean实例 * @throws Exception 异常 */ protected abstract Object createBeanLazy(BeanDefinition beanDefinition) throws Exception; } ClassPathXmlApplicationContext:使用过Sprnig的人对这个类名应该很熟悉了,这是整个程序的上下文入口,也是bean的容器。它基本的工作流程是调用读取器读取BeanDefinition,并通过工厂类将bean注册到容器。它实现了BeanFactory接口,并且静态代理了BeanFactory接口的实现类,对外提供了一个统一的getBean(String name)方法,源码如下: public class ClassPathXmlApplicationContext extends AbstractApplicationContext { private String location; public ClassPathXmlApplicationContext(String location) throws Exception { super(new XmlBeanFactory()); this.location = location; refresh(); } /** * 重载bean定义实现方法 * * @param beanFactory bean工厂类 * @throws Exception 异常 */ @Override protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(new ResourceLoader()); reader.readXml(location); for (Map.Entry<String, BeanDefinition> entry : reader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(entry.getKey(), entry.getValue()); } } } 以上是比较重要的接口和组件,如果看得比较迷糊,请上Github参考完整的代码,点击这里。 四、测试用例 定义一个pojo类和一个服务类: public class User { public User() { System.out.println("User constructor"); } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class UserService { private User user; public UserService() { System.out.println("UserService constructor"); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public void say() { System.out.println("I am " + user.getName()); } } 定义Xml配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="user" class="net.stackoverflow.summer.pojo.User"> <property name="name" value="matrix"/> </bean> <bean id="userService" class="net.stackoverflow.summer.service.UserService"> <property name="user" ref="user"/> </bean> </beans> 单元测试用例代码: public class TestIoC { @Test public void testIoC() { try { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.say(); } catch (Exception e) { e.printStackTrace(); } } } 运行后输出: User constructor UserService constructor I am matrix 接下来测试懒加载,将Xml配置文件中的user节点中加入懒加载属性lazy-init="true": <?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="user" class="net.stackoverflow.summer.pojo.User" lazy-init="true"> <property name="name" value="matrix"/> </bean> <bean id="userService" class="net.stackoverflow.summer.service.UserService"> <property name="user" ref="user"/> </bean> </beans> 在单元测试代码中的UserService userService = (UserService) applicationContext.getBean("userService");处打上断点,运行程序,输出: UserService constructor 继续往下运行代码,输出: UserService constructor User constructor I am matrix 产生这种现象的原因是,user对象被懒加载了,所以上下文初始化的时候,并没有创建user对象,直到获取userService对象的时候,该IoC框架检查到userService依赖user,但是容器中user对象为空,所以这时候才将user实例化,并依赖注入给userService,这就是懒加载功能。 五、结束 进行到这,一个最基础的IoC框架算是完成了,接下来会陆续推出AOP和MVC等模块的从零构建,敬请期待。人生苦短,多写点技术代码,少写点业务代码,别让自己活成了一个码农。今天就23岁了,一没房贷,二没车贷,三没成家,四没孩子,一人吃饱全家不饿,人生中最轻松的一段时光,可以毫无顾虑地去自己想去的地方,放手去追求自己想做的事,新的开始,加油!
申请SSL证书 以阿里云申请的免费SSL证书为例,在阿里云购买域名后,在域名管理界面可以看到申请SSL证书的字样。申请免费证书后,下载到本地,可以得到一个证书和一个密码。 配置Tomcat 1. 将下载好的证书上传到服务器 2. 修改Tomcat的配置文件server.xml(总共需要修改三处地方) 2.1. 找到下面这一段,将注释去掉,补充没有的属性,certificateKeystoreFile为你的证书的位置,certificateKeystoreType为你的证书的类型,certificateKeystorePassword为你的密码。 <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/key.pfx" certificateKeystoreType="PKCS12" certificateKeystorePassword="123456" /> </SSLHostConfig> </Connector> 2.2. 找到这一段,将port改为80,将redirectPort改为443,作用是将http协议自动跳转到https <Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="443" /> 2.3. 找到这一段,将redirectPort改为443 <Connector port="8009" protocol="AJP/1.3" redirectPort="443" /> 3. 修改web.xml文件,在</welcome-file-list>标签后面加上这一段 <login-config> <!-- Authorization setting for SSL --> <auth-method>CLIENT-CERT</auth-method> <realm-name>Client Cert Users-only Area</realm-name> </login-config> <security-constraint> <!-- Authorization setting for SSL --> <web-resource-collection > <web-resource-name >SSL</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> 重启Tomcat服务,完成
1. Java语法 很多人推荐《Java编程思想》,我是不推荐这本书入门,外国人写的东西就是啰啰嗦嗦,《从入门到精通》系列挺好的,习惯了中国式教育,高效快速。 2. Java Web 说实话,jsp这些东西已经很过时了,但是servlet-api里面的一些东西直接影响了你学后面的一些东西,比如:过滤器,监听器,会话之类的,多看看web.xml里的一些配置,知道这些东西该怎么配。 3. Maven 项目依赖,构建管理工具,学会如何配置仓库,镜像,特别重点:生命周期和插件。 4. SSM还是SSH SSH是指(spring+struts2+hibernate),SSM是指(spring+springMVC+mybatis),结合现在形式来看,除非你去维护一些老项目,不然SSH这一套绝对过时了,当然spring-data-jpa里面用到了hibernate,这个可以学学,不然你就去学SSM,下面分开来讲。 5. Spring Java的生态真的得感谢Spring,具体的自己去看书,下面划一下重点。 1、IoC控制反转 2、AOP面向切面编程 3、Bean生命周期 4、Spring数据库事务(敲黑板特别重点,期末要考:四种隔离级别和传播行为) 5、jdk代理和cglib代理的区别 实战:Maven创建web项目后,如何写配置文件整合Spring(一个程序员最起码离开各种平台要学会搭项目,配置项目)。 6. Spring MVC 作为Spring全家桶的一个成员完美的诠释了MVC架构,下面划一下重点。 1、Spring MVC处理请求流程(敲黑板特别重点,期末要考) 2、Spring MVC几种注解的应用 实战:在上一个实战的基础上,把Spring MVC给整合进去,怎么去写配置 7. Mybatis 比较流行的持久化框架,优点在于暴露sql,便于sql优化,适合互联网架构场景。下面划一下重点。 1、懒加载,别名,Typehandler等概念 2、mapper.xml文件的书写 3、一对多关系的查询 4、分页插件 实战:在上一个实战的基础上,把Mybatis给整合进去,怎么去写配置文件。能够做到SSM的整合算是互联网架构入门了,真是这样。 8. redis 当下最最流行的缓存中间件,不废话,直接划重点 1、redis的几种数据结构 2、redis命令行接口的使用 3、redis编程接口的使用 4、redis的主从结构 5、SSM项目如何整合Redis,RedisTemplate和CacheManager等一些常见API的使用 实战:在整合了SSM框架的基础上,通过Spring把Redis也给整合进去,如何去写配置 9. rabbitmq 消息队列,除此之外还有activemq,这里只介绍rabbitmq,划重点 1、熟悉amqp协议 2、rabbitmq中几种交换机的区别和使用场景 3、rabbitmq的几种使用场景(削峰,异步,解耦) 4、rabbitmq的命令行接口和编程接口 5、SSM项目整合rabbitmq,熟悉AmqpTemplate,RabbitTemplate,MessageListener等API 实战:在整合SSM框架的基础上,通过Spring把Rabbitmq给整合进去,如何去写配置 10. zookeeper,dubbo 这两个放一块讲,zookeeper作为分布式协同中间件,平时用的比较多的地方算是在dubbo里面了,dubbo是阿里推出的一个RPC框架,dubbox是当当网在dubbo的基础上支持了RESTFUl接口,划重点。 1、zookeeper的数据结构 2、zookeeper的选主算法 3、zookeeper的命令行接口和编程接口 4、dubbo的流程,原理和配置,如何向注册中心注册 实战:在整合SSM框架的基础上,通过Spring将zookeeper和dubbo给整合进项目里,如何去写配置。 11. shiro 这东西严格来说不是中间件,算一个授权认证框架,还有Spring-Security也是,不过Spring-security比较重量级,一般会选择使用shiro,下面划重点。 1、整个shiro处理授权认证流程的架构都很重要 2、如何通过shiro过滤器代理web请求 3、如何开发自定义Realm 4、凭证匹配器 5、三种过滤器(FormAuthenticationFilter,UserFilter,LogoutFilter) 6、如何自定义过滤器 7、会话管理器(会话持久化) 8、缓存管理器(怎么去整合redis缓存) 9、rememberMe管理器 10、安全管理器 11、如何定义URL过滤规则 实战:在整合SSM框架的基础上,通过Spring将shiro给整合进项目里,如何去写配置,如何实现授权认证流程,如何进行权限管理 12. Spring boot 上面在实战过程中,通过Spring去整合各种框架和中间件的xml配置是不是写得很头痛,现在有了一个更好得东西叫Spring boot,这个东西没别的,就是帮你解决以上配置繁琐的问题的。Spring boot是基于约定的配置和自动化配置。什么是约定的配置呢?比如,一般我们项目会设置端口为8080,所以他就帮你约定配置好了这个端口,你就不需要去配置端口了,当然你要想改为其他端口也还是可以改的。什么是自动化配置呢?比如Spring boot检测到你类路径下有Mybatis相关的类,那么他就会从你的properties中,去找数据库ip,用户,密码等,然后帮你把mybatis自动给配置好,有了这东西,你能从这些繁琐的配置中解放出来,而更关注于业务层面。 13. Spring Cloud 当下流行的一个微服务框架,以Spring boot项目为基础,划重点。 1、服务治理中心 2、微服务之间的互相调用(RestTemplate和Feign) 3、网关(zuul和gateway) 4、服务容错(降级和熔断的概念和实现) 5、服务追踪 6、消息总线 7、配置中心 8、Ribbon客户端负载均衡策略 9、分布式事务(敲黑板特别重点,期末要考) 14. Linux 1、目录文件的操作 2、软件的安装及配置 3、Linux系统的目录结构 4、Vi/Vim编辑器的使用 5、通过源码编译软件(有些软件根本就不提供二进制发行版,你不得不通过源码编译OpenCV、Redis) 6、进程的操作,网络的操作 7、《UNIX环境高级编程》选读,你能了解Linux C一些API,对Linux更了解 8、不同发行版的区别(主流的就三种系列Redhat,debian,arch) 15. docker 现在都是云原生应用,容器化部署,devops的热门,更是将docker推向高潮,最为一个开发人员,最基本的运维还是要懂的,其实你会Linux的话,docker简直如鱼得水,下面划重点。 1、docker基本的命令(拉取镜像,创建容器,commit镜像,push镜像) 2、dockerfile脚本的书写,如何去构建镜像 3、进入运行容器的几种方式(attach,exec,ssh等) 4、docker-compose编排docker服务,docker-compose.yml配置的书写 16. nginx 反向代理服务器,划重点。 1、反向代理和正向代理的区别和概念 2、nginx配置,如何转发请求 3、动静分离,负载均衡等概念 17. Java多线程 1、synchronized同步 2、lock同步 3、死锁问题 4、volatile关键字 5、线程状态的变化 6、线程组的概念 7、线程间的通信 18. JVM JVM虚拟机这东西全是重点,去看书死啃 19. 设计模式 1、单例模式 2、适配器模式 3、工厂模式 4、观察者模式 5、装饰器模式 6、代理模式 7、建造者模式 8、桥接模式 9、责任链模式 20. 数据结构与算法 1、线性表(链表,对列,栈) 2、树(二叉树,排序二叉树,红黑树,B树,B+树,平衡二叉树,赫夫曼树) 3、森林(树和森林的转换) 4、图论(如何找最短路径) 5、各种排序算法 结束 好好看看吧,会对你有帮助,欢迎补充。
redis镜像 FROM debian:latest WORKDIR / RUN apt-get update && apt-get install -y redis-server RUN sed -i -e 's@bind 127.0.0.1@bind 0.0.0.0@g' /etc/redis/redis.conf RUN sed -i -e 's@protected-mode yes@protected-mode no@g' /etc/redis/redis.conf RUN sed -i -e 's@daemonize yes@daemonize no@g' /etc/redis/redis.conf RUN echo "requirepass 19960821" >> /etc/redis/redis.conf EXPOSE 6379 CMD ["redis-server","/etc/redis/redis.conf"] rabbitmq镜像 FROM debian:latest WORKDIR / RUN apt-get update && apt-get install -y erlang rabbitmq-server RUN rabbitmq-plugins enable --offline rabbitmq_management #RUN rabbitmq-server -detached &&\ #rabbitmqctl delete_user guest &&\ #rabbitmqctl add_user admin 19960821 &&\ #rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*" &&\ #rabbitmqctl set_user_tags admin administrator EXPOSE 5672 EXPOSE 15672 CMD ["rabbitmq-server"] mysql或mariadb镜像 FROM debian:latest WORKDIR / RUN apt-get update && apt-get install -y mysql-client mysql-server RUN sed -i 's/^bind-address/#&/' /etc/mysql/mariadb.conf.d/50-server.cnf RUN /etc/init.d/mysql start &&\ mysql -e "grant all privileges on *.* to 'root'@'%' identified by '19960821' WITH GRANT OPTION;" &&\ mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by '19960821' WITH GRANT OPTION;" &&\ mysql -uroot -p19960821 -e "flush privileges;" EXPOSE 3306 CMD ["mysqld"] tomcat镜像 FROM java:latest WORKDIR / COPY ./apache-tomcat-9.0.16.tar.gz / RUN tar zxf apache-tomcat-9.0.16.tar.gz RUN mv apache-tomcat-9.0.16 /usr/local/tomcat RUN rm apache-tomcat-9.0.16.tar.gz ENV CATALINA_HOME=/usr/local/tomcat ENV CATALINA_BASE=/usr/local/tomcat ENV PATH=$CATALINA_HOME/bin:$PATH EXPOSE 8080 CMD ["catalina.sh", "run"] java环境镜像 FROM debian:latest WORKDIR / COPY ./jdk-8u202-linux-x64.tar.gz / RUN tar zxf jdk-8u202-linux-x64.tar.gz RUN mv jdk1.8.0_202 /usr/local/jdk RUN rm jdk-8u202-linux-x64.tar.gz ENV JAVA_HOME=/usr/local/jdk ENV JRE_HOME=$JAVA_HOME/jre ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH ENV PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
一、准备工作 1.下载Arch Linux镜像 2.用U盘刻录好 3.划分出一块空白的硬盘 4.在bios中设置从U盘启动 5.插好U盘,开机 二、开始安装 2.1 分区 说明:至少需要三个分区,EFI分区,根分区,交换分区 1.运行cfdisk命令新建EFI分区,分区类型选择GPT 2.运行fdisk命令新建根分区,和交换分区,分区类型都选择p主分区 3.不出意外,你的硬盘将会分为三个分区/dev/sda1,/dev/sda2,/dev/sda3 2.2 格式化分区 说明:EFI分区格式化fat格式,根分区格式化ext4格式,交换分区格式化swap格式 运行以下命令 mkfs.vfat -F32 /dev/sda1 mkfs.ext4 /dev/sda2 mkswap /dev/sda3 swapon /dev/sda3 #激活交换分区 2.3 挂载分区 说明:根分区挂载到/mnt下,EFI分区挂载到/mnt/boot/efi下,交换分区不需要挂载 运行以下命令 mount /dev/sda2 /mnt mkdir -p /mnt/boot/efi #新建efi目录 mount /dev/sda1 /mnt/boot/efi 2.4 安装基本系统 说明:一般安装base、base-devel这两个包,为了后续配置方便,可以顺便安装vim编辑器 运行以下命令 pacstrap -i /mnt base base-devel vim genfstab -p -U /mnt >> /mnt/etc/fstab 2.5 配置新系统 说明:Arch Linux是一款完全基于个人定制的Linux,可配置项很多,可根据自己需要进行配置,但下面几项配置几乎是新系统必须的:时区、网络、本地化、系统引导等。 改变root到新系统 arch-chroot /mnt /bin/bash 2.5.1 时区 设置时区和系统时钟 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime hwclock --systohc --utc 2.5.2 本地化配置 用vim编辑/etc/locale.gen,去掉en_US.UTF8、zh_CN.UTF8、zh_TW.UTF8前的注释 vim /etc/locale.gen locale-gen 创建locale.conf并编辑LANG这一变量 echo LANG=en_US.UTF-8 > /etc/locale.conf 2.5.3 网络配置 配置hostname,hosts文件 echo Arch >> /etc/hostname echo 127.0.0.1 localhost >> /etc/hosts echo ::1 localhost >> /etc/hosts echo 127.0.0.1 arch.localdomain arch >> /etc/hosts 设置dhcp服务开机自启 systemctl enable dhcpcd 2.6 改变root密码 passwd 2.7 安装系统引导 安装grub作为系统引导,命令如下 pacman -S grub efibootmgr grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=grub grub-mkconfig -o /boot/grub/grub.cfg 2.8 重启系统 exit umount /mnt/boot/efi umount /mnt reboot 三、安装桌面环境 通过以上步骤,基本系统已经安装好了,现在需要安装桌面环境和一些基本的驱动 3.1 安装xorg服务 pacman -S xorg-server xorg-server-utils#后面这个包好像现在没了,去掉也好像没问题 3.2 安装显卡驱动 核显 pacman -S xf86-video-intel 独显 pacman -S xf86-video-nouveau 3.3 安装触摸板驱动 pacman -S xf86-input-synaptics 3.4 安装常用字体 pacman -S ttf-dejavu wqy-microhei 3.5 安装桌面 以gnome桌面为例,需要安装kde或xfce等其他桌面环境的,可以参考Arch wiki pacman -S gnome gnome-extra gdm systemctl enable gdm 四、结束 至此为止,一个Arch Linux的基本的安装过程就结束了,开始Arch的入坑之旅吧。