AOP 面向切面编程

1.准备工作,创建maven项目

    1. pom.xml  加入依赖

<dependencies><!--spring核心坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency>
<!--测试-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.6</version></dependency><!--注解--><dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version></dependency><!--junit5--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version><scope>test</scope></dependency></dependencies>

2. 创建配置类

@Configuration@ComponentScan(basePackages = {"com.bdqn"})public class SpringConfig {}

3. 准备计算器接口

package com.bdqn.proxy;
public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);}

 4.准备纯净计算器的实现类

package com.bdqn.proxy;
/*** 实现计算接口,单纯添加 + - * / 实现! 掺杂其他功能!*/@Componentpublic class CalculatorImpl implements Calculator {@Overridepublic int add(int i, int j) {int result=i+j;System.out.println("结果:"+result);return result;}@Overridepublic int sub(int i, int j) {int result=i-j;System.out.println("结果:"+result);return result;}@Overridepublic int mul(int i, int j) {int result=i*j;System.out.println("结果:"+result);return result;}@Overridepublic int div(int i, int j) {int result=i/j;System.out.println("结果:"+result);return result;}}
 

  5.测试效果

@SpringJUnitConfig(classes = {SpringConfig.class})public class TestAop {@AutowiredCalculator c;@Testpublic void testCalculator(){c.add(10,2);System.out.println("----------");c.sub(10,2);
System.out.println("----------");c.mul(10,2);System.out.println("----------");c.div(10,2);}}

 

    2.AOP 面向切面编程思想

AOP:Aspect Oriented Programming面向切面编程

中文:面向切面编程

定义:在程序原有的纵向执行流程中,针对某一个或某一些方法添加通知形成横向切面过程,称为面向切面编程。

    3.AOP思想主要的应用场景

AOP(面向切面编程)是一种编程范式,它通过将通用的横切关注点(如日志、事务、权限控制等)与业务逻辑分离,使得代码更加清晰、简洁、易于维护。AOP可以应用于各种场景,以下是一些常见的AOP应用场景:

1. 日志记录:在系统中记录日志是非常重要的,可以使用AOP来实现日志记录的功能,可以在方法执行前、执行后或异常抛出时记录日志。

2. 事务处理:在数据库操作中使用事务可以保证数据的一致性,可以使用AOP来实现事务处理的功能,可以在方法开始前开启事务,在方法执行完毕后提交或回滚事务。

3. 安全控制:在系统中包含某些需要安全控制的操作,如登录、修改密码、授权等,可以使用AOP来实现安全控制的功能。可以在方法执行前进行权限判断,如果用户没有权限,则抛出异常或转向到错误页面,以防止未经授权的访问。

4. 性能监控:在系统运行过程中,有时需要对某些方法的性能进行监控,以找到系统的瓶颈并进行优化。可以使用AOP来实现性能监控的功能,可以在方法执行前记录时间戳,在方法执行完毕后计算方法执行时间并输出到日志中。

5. 异常处理:系统中可能出现各种异常情况,如空指针异常、数据库连接异常等,可以使用AOP来实现异常处理的功能,在方法执行过程中,如果出现异常,则进行异常处理(如记录日志、发送邮件等)。

6. 缓存控制:在系统中有些数据可以缓存起来以提高访问速度,可以使用AOP来实现缓存控制的功能,可以在方法执行前查询缓存中是否有数据,如果有则返回,否则执行方法并将方法返回值存入缓存中。

7. 动态代理:AOP的实现方式之一是通过动态代理,可以代理某个类的所有方法,用于实现各种功能。

综上所述,AOP可以应用于各种场景,它的作用是将通用的横切关注点与业务逻辑分离,使得代码更加清晰、简洁、易于维护。

  4.AOP术语名词介绍

切点: 原有功能。           Pointcut   如:sub()方法

通知: 在切点前后执行。     Advice

--前置通知:在切点前执行 

--正常返回后置通知:在切点成功结束后执行(**寿终正寝**)

--异常后置通知:在切点出现异常后执行(**死于非命**)

--后置通知:在切点最终结束后执行(**盖棺定论**)

--环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置]

    切面: 所有功能统称。

    织入: 将通知切面嵌入到切点生成代理对象的过程。

 5.Spring Aop基于注解方式实现

   1.Spring Aop 底层技术组成

动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。

cglib:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口

AspectJ:早期的AOP实现的框架,SpringAOP借用了AspectJ中的AOP注解。

   2. 实现步骤

     1. pom.xml  加入AOP相关的依赖

<!--spring核心坐标,引入AOP坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency><!--spring-aop依赖的aspectjweaver--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.6</version></dependency>

       2. 声明切面类

package com.bdqn.advice;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;//@Aspect表示这个类是一个切面类@Aspect//@Component注解保证这个切面类能够放入IOC容器@Componentpublic class LogAdvice {/*** 前置通知* @Before注解:声明当前方法是前置通知方法* value属性:指定切入点表达式,由切入点表达式控制当前通知方法要作用在哪一个目标方法上*/@Before(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logBefore() {System.out.println("[AOP前置通知] 方法开始了");}/*** 正常后置通知:只有切点正常返回,才会执行*/@AfterReturning(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logAfterSuccess() {System.out.println("[AOP返回通知] 方法成功返回了");}/*** 异常通知:只有切点出现异常,才会执行*/@AfterThrowing(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logAfterException() {System.out.println("[AOP异常通知] 方法抛异常了");}/*** finally后置通知:不管是否出现异常,都会执行*/@After(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logFinally() {System.out.println("[AOP后置通知] 方法最终结束了");}

}

   3. 配置类方式,开启aspectj注解支持

@Configuration@ComponentScan(basePackages = {"com.bdqn"})//作用等于 <aop:aspectj-autoproxy /> 配置类上开启 Aspectj注解支持!@EnableAspectJAutoProxypublic class SpringConfig{}

  4.测试效果

@SpringJUnitConfig(classes = {SpringConfig.class})public class TestAop {@AutowiredCalculator c;@Testpublic void testCalculator(){c.add(10,20);System.out.println("----------");c.div(10,5);System.out.println("----------");c.div(10,0);}}

     5. 输出结果

 6.获取通知细节信息

   1.JointPoint接口

     需要获取方法签名、传入的实参等信息时,可以在通知方法声明JoinPoint类型的形参。

      要点1:JoinPoint 接口通过 getSignature() 方法获取目标方法的签名(方法声明时的完整信息)

      要点2:通过目标方法签名对象获取方法名

      要点3:通过 JoinPoint 对象获取外界调用目标方法时传入的实参列表组成的数组

   /*** 前置通知* @Before注解:声明当前方法是前置通知方法* value属性:指定切入点表达式,由切入点表达式控制当前通知方法要作用在哪一个目标方法上* 在方法形参位置声明一个JoinPoint类型的参数,Spring就会将这个对象传入根据JoinPoint对象就可以获取目标方法名称、实际参数列表*/@Before(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logBefore(JoinPoint joinPoint) {// 1.通过JoinPoint对象获取目标方法签名对象// 方法的签名:一个方法的全部声明信息Signature signature = joinPoint.getSignature();// 2.通过方法的签名对象获取目标方法的详细信息//获取目标方法名String methodName = signature.getName();System.out.println("methodName = " + methodName);//获取目标方法修饰符int modifiers = signature.getModifiers();System.out.println("modifiers = " + modifiers);//获取目标获取带修饰符的类路径String declaringTypeName = signature.getDeclaringTypeName();System.out.println("declaringTypeName = " + declaringTypeName);// 3.通过JoinPoint对象获取外界调用目标方法时传入的实参列表Object[] args = joinPoint.getArgs();System.out.println("[AOP前置通知] " + methodName + "方法开始了,参数列表:" + Arrays.toString(args));}

   2.方法返回值

     在返回通知中,通过@AfterReturning注解的returning属性获取目标方法的返回值!

/*** 正常后置通知:只有切点正常返回,才会执行* 在返回通知中获取目标方法返回值分两步:第一步:在@AfterReturning注解中通过returning属性设置一个名称第二步:使用returning属性设置的名称在通知方法中声明一个对应的形参*/@AfterReturning(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))",returning = "targetMethodReturnValue")public void logAfterSuccess(JoinPoint joinPoint, Object targetMethodReturnValue) {String methodName = joinPoint.getSignature().getName();System.out.println("[AOP返回通知] "+methodName+"方法成功结束了,返回值是:" + targetMethodReturnValue);}

   3.异常对象捕捉

     在异常通知中,通过@AfterThrowing注解的throwing属性获取目标方法抛出的异常对象

/*** 异常通知:只有切点出现异常,才会执行* 在异常通知中获取目标方法抛出的异常分两步:* 第一步:在@AfterThrowing注解中声明一个throwing属性设定形参名称* 第二步:使用throwing属性指定的名称在通知方法声明形参,Spring会将目标方法抛出的异常对象从这里传给我们*/@AfterThrowing(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))",throwing = "e")public void logAfterException(JoinPoint joinPoint,Throwable e) {String methodName = joinPoint.getSignature().getName();System.out.println("[AOP异常通知] "+methodName+"方法抛异常了,异常类型是:" + e.getClass().getName());}

   4.切点表达式语法

     1.切点表达式作用

       AOP切点表达式(Pointcut Expression)是一种用于指定切点的语言,它可以通过定义匹配规则,来选择需要被切入的目标对象。

     2. 切点表达式语法

  5.重用(提取)切点表达式

    1. 重用切点表达式优点

    @Before(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logBefore() {System.out.println("[AOP前置通知] 方法开始了");}/*** 正常后置通知:只有切点正常返回,才会执行*/@AfterReturning(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logAfterSuccess() {System.out.println("[AOP返回通知] 方法成功返回了");}/*** 异常通知:只有切点出现异常,才会执行*/@AfterThrowing(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logAfterException() {System.out.println("[AOP异常通知] 方法抛异常了");}/*** finally后置通知:不管是否出现异常,都会执行*/@After(value = "execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void logFinally() {System.out.println("[AOP后置通知] 方法最终结束了");}

  上面案例,是我们之前编写切点表达式的方式,发现, 所有增强方法的切点表达式相同!

出现了冗余,如果需要切换也不方便统一维护!

我们可以将切点提取,在增强上进行引用即可!

  2.内部引用

     2.1 提取

/*** 提取切点:切入点表达式重用*/@Pointcut("execution(* com.bdqn.proxy.CalculatorImpl.*(..))")public void pointcut() {}

     2.2 同一类引用

@Before(value = "pointcut()")public void logBefore(JoinPoint joinPoint) {

2.3 不同类中引用

@Before(value = "com.bdqn.advice.LogAdvice.pointcut()")public void logBefore(JoinPoint joinPoint) {

  3.切点统一管理

@Component

public class AtguiguPointCut {

   

    @Pointcut(value = "execution(public int *..Calculator.sub(int,int))")

    public void atguiguGlobalPointCut(){}

   

    @Pointcut(value = "execution(public int *..Calculator.add(int,int))")

    public void atguiguSecondPointCut(){}

   

    @Pointcut(value = "execution(* *..*Service.*(..))")

    public void transactionPointCut(){}

}

  6. 环绕通知

 环绕通知对应整个 try...catch...finally 结构,包括前面四种通知的所有功能。

/*** 环绕通知=前置+后置通知+异常通知* 通过在通知方法形参位置声明ProceedingJoinPoint类型的形参,Spring会将这个类型的对象传给我们*/@Around(value = "pointcut()")public Object txArroud(ProceedingJoinPoint joinPoint) {// 通过ProceedingJoinPoint对象获取外界调用目标方法时传入的实参数组Object[] args = joinPoint.getArgs();// 通过ProceedingJoinPoint对象获取目标方法的签名对象Signature signature = joinPoint.getSignature();// 通过签名对象获取目标方法的方法名String methodName = signature.getName();// 声明变量用来存储目标方法的返回值Object result = null;try {// 在目标方法执行前:开启事务(模拟)System.out.println("[AOP 环绕通知] 开启事务,方法名:" + methodName + ",参数列表:" + Arrays.asList(args));// ProceedingJoinPoint对象调用目标方法目标方法的返回值一定要返回给外界调用者result = joinPoint.proceed(args);// 在目标方法成功返回后:提交事务(模拟)System.out.println("[AOP 环绕通知] 提交事务,方法名:" + methodName + ",方法返回值:" + result);}catch (Throwable e){// 在目标方法抛异常后:回滚事务(模拟)System.out.println("[AOP 环绕通知] 回滚事务,方法名:" + methodName + ",异常:" + e.getClass().getName());}finally {// 在目标方法最终结束后:释放数据库连接System.out.println("[AOP 环绕通知] 释放数据库连接,方法名:" + methodName);}return result;}

7. Spring AOP的jdk 和Cglib动态代理生效

   在目标类没有实现任何接口的情况下,Spring会自动使用cglib技术实现代理。

   总结:

a.  如果目标类有接口,选择使用jdk动态代理

b.  如果目标类没有接口,选择cglib动态代理

c.  如果有接口,接口接值

d.  如果没有接口,类进行接值

8. 注解实现总结

 9.Spring Aop基于XML方式实现 (了解)

   1. 准备工作

      加入依赖:和基于注解的 AOP 时一样

      准备代码:把测试基于注解功能时的Java类复制到新module中,去除所有注解。

    2. 配置Spring配置文件

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启aspectj框架注解支持--><aop:aspectj-autoproxy></aop:aspectj-autoproxy><!-- 配置目标类的bean --><bean id="calculator" class="com.bdqn.proxy.CalculatorImpl"/><!-- 配置切面类的bean --><bean id="logAdvice" class="com.bdqn.advice.LogAdvice"/><!-- 配置AOP --><aop:config><!-- 配置切入点表达式 --><aop:pointcut id="logPointCut" expression="execution(* com.bdqn.proxy.CalculatorImpl.*(..))"/><!-- aop:aspect标签:配置切面  ref属性:关联切面类的bean --><aop:aspect ref="logAdvice"><!-- aop:before标签:配置前置通知 --><!-- method属性:指定前置通知的方法名 --><!-- pointcut-ref属性:引用切入点表达式 --><aop:before method="logBefore" pointcut-ref="logPointCut"/><!-- aop:after-returning标签:配置返回通知 --><!-- returning属性:指定通知方法中用来接收目标方法返回值的参数名 --><aop:after-returning method="logAfterSuccess" pointcut-ref="logPointCut" returning="targetMethodReturnValue"/><!-- aop:after-throwing标签:配置异常通知 --><!-- throwing属性:指定通知方法中用来接收目标方法抛出异常的异常对象的参数名 --><aop:after-throwing method="logAfterException" pointcut-ref="logPointCut" throwing="e"/><!-- aop:after标签:配置后置通知 --><aop:after method="logFinally" pointcut-ref="logPointCut"/><!-- aop:around标签:配置环绕通知 --><aop:around method="logArroud" pointcut-ref="logPointCut"/></aop:aspect></aop:config></beans>

    3. 测试

@SpringJUnitConfig(locations = "classpath:applicationContext.xml")public class TestAop {@AutowiredCalculator c;@Testpublic void testCalculator(){c.add(10,20);System.out.println("----------");c.div(10,0);}}

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

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

相关文章

算术移位的学习

术移位&#xff08;Arithmetic Shift&#xff09;是一种位移操作&#xff0c;主要用于有符号整数。它与逻辑移位相似&#xff0c;但在处理负数时有一些显著的不同。算术移位能够保持符号位的完整性&#xff0c;因此在有符号数的移位运算中非常有用。 算术移位的类型 算术左移&…

打造商业数字化生态,价值何在?

​在当今数字化时代&#xff0c;商业格局正发生着深刻变革。打造商业数字化生态&#xff0c;成为众多企业的战略选择。那么&#xff0c;它的价值究竟几何呢&#xff1f; 商业数字化生态是利用数字技术&#xff0c;将企业、消费者、合作伙伴等各方连接起来&#xff0c;形成相互依…

AI时代,谷歌会像当年的IBM一样陨落吗?

​从2015年到2024年 在2015年的某个清晨&#xff0c;阳光透过硅谷的薄雾&#xff0c;照亮了谷歌总部那标志性的入口。那时&#xff0c;谷歌正处于技术的巅峰&#xff0c;人们怀着激动的心情讨论着它如何将机器学习和人工智能&#xff08;AI&#xff09;无缝融入到所有产品中。它…

ubuntu 开启haproxy UI

一、修改haproxy.cfg nano /etc/haproxy/haproxy.cfg 添加一段 listen statsbind *:8080stats enablestats uri /uistats refresh 10sstats auth admin:123456stats admin if TRUE 重启 sudo systemctl restart haproxy 浏览器访问&#xff1a; http://192.168.31.182:80…

CMakeLists.txt 编写规则

目录 1. 注释 1.1 注释行 1.2 注释块 2. CMakeLists.txt的编写 2.1 同意目录下的源文件 2.2 SET指令 2.3 file和aux_source_directory 2.4 包含头文件 2.5 生成动态库和静态库 2.6 链接库文件 2.7 message指令 2.8 移除操作 2.9 find_library和find_package 3. 常…

Node.js初学者指南:搭建HTTP服务器、获取请求信息及响应、变量声明与NPM包管理

精神畅快&#xff0c;心气平和&#xff1b;饮食有节&#xff0c;寒暖当心&#xff1b;起居以时&#xff0c;劳逸均匀 文章目录 node.js使用http搭建服务器的问题获取请求相关的信息响应相关的信息var、let、const对比npm使用全局安装包 node.js 概念 node.js是一个基于Chrome …

渗透实战 JS文件怎么利用

1.前言 关于JS在渗透测试中的关键作用&#xff0c;想必不用过多强调&#xff0c;在互联网上也有许多从JS中找到敏感信息从而拿下关键系统的案例。大部分师傅喜欢使用findsomething之类的浏览器插件&#xff0c;也有使用诸如Unexpected.information以及APIFinder之类的Burp插件…

QT--文本框 QLineEdit、qtextedit

在Qt中&#xff0c;文本框&#xff08;QLineEdit 或 QTextEdit&#xff09;和标签&#xff08;QLabel&#xff09;是两种不同的部件&#xff08;widget&#xff09;&#xff0c;它们的主要区别在于用途和功能&#xff1a; QLabel&#xff08;标签&#xff09; 用途&#xff1…

企业数字化转型的理论指南:构建未来企业的关键策略与实践路径

数字化转型已经成为当今企业发展和市场竞争的核心驱动力&#xff0c;而在这一过程中&#xff0c;企业架构&#xff08;EA&#xff09;发挥着至关重要的作用。这本白皮书《世界级企业架构&#xff1a;建立和发展EA能力的领导者方法》提供了深入的理论指导&#xff0c;为企业如何…

专线物流公告服务平台痛点分析:重塑信任、效率与透明度的新篇章

专线物流公告服务平台痛点分析&#xff1a;重塑信任、效率与透明度的新篇章 在当今全球化的商业环境中&#xff0c;专线物流服务作为连接生产与消费的关键纽带&#xff0c;其重要性不言而喻。然而&#xff0c;随着市场竞争的加剧和消费者需求的日益多样化&#xff0c;专线物流…

禁止VMware Service进程开机自动启动

方法一&#xff1a;使用服务管理器 (Services.msc) 打开服务管理器&#xff1a; 按 Win R 打开运行对话框&#xff0c;输入 services.msc&#xff0c;然后按 Enter。 找到 VMware Authorization Service&#xff1a; 在服务列表中找到 VMware Authorization Service。 更改启动…

由云智慧发起的《数字政府统一运维 第1部分:运维平台建设指南》团标正式发布

2024年9月&#xff0c;由云智慧和中国信通院联合主导的《数字政府统一运维 第1部分&#xff1a;运维平台建设指南》团体标准完成编写&#xff0c;经中国互联网协会相关专家审查通过并准予发布&#xff0c;标准编号&#xff1a;T/ISC 0062-2024。 中国数字政府建设已经进入了高…

java高频面试题汇总

Java 基础 Java 中的序列化和反序列化是什么&#xff1f; 序列化是将 Java 对象转换为字节流的过程&#xff0c;以便可以将其存储在文件中或通过网络进行传输。反序列化则是将字节流恢复为 Java 对象的过程。通过实现 Serializable 接口&#xff0c;Java 对象可以支持序列化。…

基于Arduino的LED亮灭按键控制

一、项目简介 通过一个按键控制LED的亮灭&#xff0c;实现按键按一下LED点亮&#xff0c;再按一下LED熄灭&#xff0c;交替循环。 二、控制原理 1. 按键检测原理&#xff1a; 将Arduino的监测端口设置为输入上拉模式&#xff08;INPUT_PULLUP&#xff09;&#xff0c;用于连…

Python实现文本数据可视化:构建动态词云

引言 在信息爆炸的时代&#xff0c;如何有效地从海量的文本数据中提取关键信息并直观展示&#xff0c;成为数据分析师和研究人员面临的重要挑战。词云作为一种流行的文本可视化工具&#xff0c;通过不同大小、颜色和字体的文字展示文本中关键词的出现频率或重要性&#xff0c;…

某ai gpt的bug

某ai gpt的bug 背景 遇到了一个奇怪的现象&#xff1a; 输入内容 2024-10-21 10:09:31,052 ERROR o.a.j.t.JMeterThread: Test failed! java.lang.IllegalArgumentException:输出结果

Java应用程序的测试覆盖率之设计与实现(二)-- jacoco agent

说在前面的话 要想获得测试覆盖率报告&#xff0c;第一步要做的是&#xff0c;采集覆盖率数据&#xff0c;并输入到tcp。 而本文便是介绍一种java应用程序部署下的推荐方式。 作为一种通用方案&#xff0c;首先不想对应用程序有所侵入&#xff0c;其次运维和管理方便。 正好…

动态路由:RIP实验

1.划分IP 2.配置环回 3.接口配置IP地址 4.进入RIP中&#xff0c;关闭手工汇总&#xff0c;选择版本号&#xff0c;宣告 5.ping命令查看是否全网通 6.在R3上配置缺省路由 [R3-rip-1]default-route originate 在边界路由器上下发缺省 7.为了安全配置手工认证 [R1-Gigab…

WordPress+Nginx 安装教程

WordPress 是一个开源的网站建设工具&#xff0c;可以用它来“快速”搭建个人博客&#xff0c;官网等等。它本身是用 php 开发的&#xff0c;本身部署不复杂&#xff0c;主要是需要一些配套的东西才能跑起来&#xff0c;网上的一些教程也是写的不清不楚&#xff0c;本文针对非 …

【宠物空气净化器选购指南】希喂、米家、IAM、352 、霍尼韦尔测评

前段时间一个朋友给我吐槽说&#xff0c;入了个宠物空气净化器&#xff0c;根本就是智商税。毛吸不进去堵在进风口不说&#xff0c;运行声音跟隔壁在装修似的&#xff0c;一开机猫就躲床底下不出来。总之&#xff0c;已经闲置很长一段时间了。更离谱的是&#xff0c;最近家里隐…