当前位置: 首页 > news >正文

使用亚马逊云做网站wordpress 延迟加载插件

使用亚马逊云做网站,wordpress 延迟加载插件,网站建设过程心得体会,网站建设需求文档模板下载一、Agent原理剖析 使用Skywalking的时候#xff0c;并没有修改程序中任何一行 Java 代码#xff0c;这里便使用到了 Java Agent 技术#xff0c;我 们接下来展开对Java Agent 技术的学习。 1.1 Java Agent Java Agent 是从 JDK1.5 开始引入的#xff0c;算是一个比较老的…一、Agent原理剖析 使用Skywalking的时候并没有修改程序中任何一行 Java 代码这里便使用到了 Java Agent 技术我 们接下来展开对Java Agent 技术的学习。 1.1 Java Agent Java Agent 是从 JDK1.5 开始引入的算是一个比较老的技术了。作为 Java 的开发工程师我们常用的  命令之一就是 java 命令而 Java Agent 本身就是 java 命令的一个参数即-javaagent。正如上一课 时接入 SkyWalking Agent 那样 -javaagent 参数之后需要指定一个 jar 包这个 jar 包需要同时满足下 面两个条件 在META-INF目录下的MANIFEST.MF文件中必须指定premain-class配置项premain-class配置项指定的类必须提供premain()方法。 在 Java 虚拟机启动时执行 main() 函数之前虚拟机会先找到-javaagent 命令指定 jar 包然后执行 premain-class 中的 premain() 方法。用一句概括其功能的话就是main() 函数之前的一个拦截器。 使用Java Agent的步骤大概如下 定义一个MANIFEST.MF文件在其中添加premain-class配置项创建premain-class配置项指定的类并在其中实现premain()方法方法如下将MANIFEST.MF文件和premain-class指定的类一起打包成一个jar包使用-javaagent指定该jar包的路径可执行其中的premain()方法 /**** 执行方法拦截* param agentArgs-javaagent 命令携带的参数。在前面介绍 SkyWalking Agent 接入时提到* agent.service_name 这个配置项的默认值有三种覆盖方式* 其中使用探针配置进行覆盖探针配置的值就是通过该参数传入的。* param instjava.lang.instrumen.Instrumentation 是 Instrumention 包中定义的一个接口它提供了操作类定义的相关方法。*/public static void premain(String agentArgs, Instrumentation inst){System.out.println(参数: agentArgs);} 1.2定义自己的Agent 1探针工程 创建工程 hailtaxi-agent用来编写agent包该类需要用 maven-assembly-plugin打包我们先引入 该插件 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.itheima/groupIdartifactIdhailtaxi-agent/artifactIdversion1.0-SNAPSHOT/versionpropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.target/propertiesdependenciesdependencygroupIdnet.bytebuddy/groupIdartifactIdbyte-buddy/artifactIdversion1.9.2/version/dependencydependencygroupIdnet.bytebuddy/groupIdartifactIdbyte-buddy-agent/artifactIdversion1.9.2/version/dependency/dependenciesbuildpluginspluginartifactIdmaven-assembly-plugin/artifactIdconfigurationappendAssemblyIdfalse/appendAssemblyIddescriptorRefsdescriptorRefjar-with-dependencies/descriptorRef/descriptorRefsarchive !--自动添加META-INF/MANIFEST.MF --manifest!-- 添加 mplementation-*和Specification-*配置项--addDefaultImplementationEntriestrue/addDefaultImplementationEntriesaddDefaultSpecificationEntriestrue/addDefaultSpecificationEntries/manifest!-- 将 premain-class 配置项设置为com.jokermqc.LoginAgent--manifestEntriesPremain-Classcom.jokermqc.LoginAgent/Premain-Class!--Premain-Classcom.jokermqc.AgentByteBuddy/Premain-Class--/manifestEntries/archive/configurationexecutionsexecutionidmake-assembly/idphasepackage/phasegoalsgoalsingle/goal/goals/execution/executions/plugin/plugins/build /project 在该工程中编写一个类 com.itheima.LoginAgent  public class LoginAgent {/**** 执行方法拦截* param agentArgs-javaagent 命令携带的参数。在前面介绍 SkyWalking Agent 接入时提到* agent.service_name 这个配置项的默认值有三种覆盖方式* 其中使用探针配置进行覆盖探针配置的值就是通过该参数传入的。* param instjava.lang.instrumen.Instrumentation 是 Instrumention 包中定义的一个接口它提供了操作类定义的相关方法。*/public static void premain(String agentArgs, Instrumentation inst){System.out.println(参数: agentArgs);} } 从字面上理解就是运行在main()函数之前的类。在Java虚拟机启动时在执行main()函数之前会先运行指定类的premain()方法在premain()方法中对class文件进行修改它有两个入参 agentArgs启动参数在JVM启动时指定 instrumentation上文所将的Instrumentation的实例我们可以在方法中调用上文所讲的方法注册对应的Class转换器对Class文件进行修改 如下图借助InstrumentationJVM启动时的处理流程是这样的JVM会执行指定类的premain()方法在premain()中可以调用Instrumentation对象的addTransformer方法注册ClassFileTransformer。当JVM加载类时会将类文件的字节数组传递给ClassFileTransformer的transform方法在transform方法中对Class文件进行解析和修改之后JVM就会加载转换后的Class文件 然后把工程进行打包得到hailtaxi-agent-1.0-SNAPASHOT.jar,这个就是对应的探针包。 此时我们把jar包解压  MANIFEST.MF 内容如下 Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Created-By: Apache Maven Built-By: admin Build-Jdk: 1.8.0_91 Specification-Title: hailtaxi-agent Specification-Version: 1.0-SNAPSHOT Implementation-Title: hailtaxi-agent Implementation-Version: 1.0-SNAPSHOT Implementation-Vendor-Id: com.itheima Premain-Class: com.itheima.LoginAgent 2)普通工程    我们在创建一个普通工程 hailtaxi-user 在该工程中创建一个普通类并编写main方法 public class UserInfo {public static void main(String[] args) throws InterruptedException {System.out.println(张三是个中国人);//调用say()方法say();TimeUnit.SECONDS.sleep(2);} } 然后我们再在启动命令中加上刚刚生成的agent包启动命令如下 -javaagent:D:/project/skywalking/hailtaxi-agent/target/hailtaxi-agent-1.0- SNAPSHOT.jarhailtaxi-user 此时运行效果如下 1.3 自定义方法统计方法耗时  Java Agent 能做的事情非常多而刚才打印一句日志只是一个能功能展示。要想使用 java agent做 更多事这里需要关注一下 premain() 方法中的第二个参数 Instrumentation 。Instrumentation  位于 java.lang.instrument 包中通过这个工具包我们可以编写一个强大的 Java Agent 程序。 因为Instrumentation操作字节码非常麻烦所以一般不会通过Instrumentation 来操作字节码而是通过Byte Buddy下面来介绍一下byte Buddy。 1.3.1Byte Buddy介绍 Byte Buddy 是一个开源 Java 库其主要功能是帮助用户屏蔽字节码操作以及复杂的 Instrumentation API 。 Byte Buddy 提供了一套类型安全的 API 和注解我们可以直接使用这些 API 和 注解轻松实现复杂的字节码操作。另外Byte Buddy 提供了针对 Java Agent 的额外 API帮助开发人   员在 Java Agent 场景轻松增强已有代码。 引入Byte Buddy依赖 dependencygroupIdnet.bytebuddy/groupIdartifactIdbyte-buddy/artifactIdversion1.9.2/version/dependencydependencygroupIdnet.bytebuddy/groupIdartifactIdbyte-buddy-agent/artifactIdversion1.9.2/version/dependency 创建统计拦截器 /*** author maoqichaun* date 2024年03月05日 18:47*/ public class MethodTimeInterceptor {/*** 这里有一点类似于Spring AOP** param method 拦截的方法* param callable 调用对象的代理对象* return java.lang.Object* author maoqichuan* date 2024/3/5*/RuntimeTypepublic static Object interceptor(Origin Method method, SuperCall Callable? callable) throws Exception {//时间统计开始long start System.currentTimeMillis();// 执行原函数Object result callable.call();//执行时间统计System.out.println(method.getName() : (System.currentTimeMillis() - start) ms);return result;} } 这里整体实现类似动态代理执行过程也类似SpringAop中的环绕通知其中几个注解我们一起来学习 一下 RuntimeType 注解告诉 Byte Buddy 不要进行严格的参数类型检测在参数匹配失败时尝试使用 类型转换方式runtime type casting进行类型转换匹配相应方法。 Origin 注解注入目标方法对应的 Method 对象。如果拦截的是字段的话该注解应该标注到 Field 类型参数。 SuperCall这个注解比较特殊我们要在 intercept() 方法中调用目标方法的话需要通过这种方 式注入与 Spring AOP 中的 ProceedingJoinPoint.proceed() 方法有点类似需要注意的是这里不能修改调用参数从上面的示例的调用也能看出来参数不用单独传递都包含在其中了。另外 SuperCall 注解还可以修饰 Runnable 类型的参数只不过目标方法的返回值就拿不到了。 配置agent拦截 public class AgentByteBuddy {/**** 执行方法拦截* param agentArgs-javaagent 命令携带的参数。在前面介绍 SkyWalking Agent 接入时提到* agent.service_name 这个配置项的默认值有三种覆盖方式* 其中使用探针配置进行覆盖探针配置的值就是通过该参数传入的。* param instjava.lang.instrumen.Instrumentation 是 Instrumention 包中定义的一个接口它提供了操作类定义的相关方法。*/public static void premain(String agentArgs, Instrumentation inst) throws IllegalAccessException, InstantiationException {//动态构建操作根据transformer规则执行拦截操作AgentBuilder.Transformer transformer new AgentBuilder.Transformer() {Overridepublic DynamicType.Builder? transform(DynamicType.Builder? builder,TypeDescription typeDescription,ClassLoader classLoader,JavaModule javaModule) {//构建拦截规则return builder//method()指定哪些方法需要被拦截ElementMatchers.any()表示拦截所有方法.method(ElementMatchers.MethodDescriptionany())//intercept()指定拦截上述方法的拦截器.intercept(MethodDelegation.to(MethodTimeInterceptor.class));}};//采用Byte Buddy的AgentBuilder结合Java Agent处理程序new AgentBuilder//采用ByteBuddy作为默认的Agent实例.Default()//拦截匹配方式类以com.itheima开始其实即使com.jokermqc包下的所有类.type(ElementMatchers.nameStartsWith(com.jokermqc))//拦截到的类由transformer处理.transform(transformer)//安装到 Instrumentation.installOn(inst);} } 同时将pom.xml中的premain-class替换成 AgentByteBuddy然后javaagent的jar替换一下即可生效 二、 Byte Buddy 在前面学习 Java Agent 技术时结合 Byte Buddy 技术实现了统计方法执行时间的功能。    Byte Buddy 在Skywalking中被广泛使用我们接下来继续学习Byte Buddy为后续分析 SkyWalking Agent打下基 础。 2.1 Byte Buddy 应用场景 Java 是一种强类型的编程语言即要求所有变量和对象都有一个确定的类型如果在赋值操作中出现类 型不兼容的情况就会抛出异常。强类型检查在大多数情况下是可行的然而在某些特殊场景下强类 型检查则成了巨大的障碍。 我们在做一些通用工具封装的时候类型检查就成了很大障碍。比如我们编写一个通用的Dao实现数据 操作我们根本不知道用户要调用的方法会传几个参数、每个参数是什么类型、需求变更又会出现什么 类型几乎没法在方法中引用用户方法中定义的任何类型。我们绝大多数通用工具封装都采用了反射机 制通过反射可以知道用户调用的方法或字段但是Java反射有很多缺陷 1:反射性能很差 2:反射能绕开类型安全检查不安全比如权限暴力破解 学完agent后我们可以基于agent做出一些改变运行时代码生成在 Java 应用启动之后再动态生成一 些类定义这样就可以模拟一些只有使用动态编程语言编程才有的特性同时也不丢失 Java 的强类型  检查。在运行时生成代码需要特别注意的是 Java 类型被 JVM 加载之后一般不会被垃圾被回收因此 不应该过度使用代码生成。 java编程语言代码生成库不止 Byte Buddy一个以下代码生成库在 Java 中也很流行 Java ProxyJava Proxy 是 JDK 自带的一个代理工具它允许为实现了一系列接口的类生成代理类。Java Proxy 要求 目标类必须实现接口是一个非常大限制例如在某些场景中目标类没有实现任何接口且无法修改目 标类的代码实现Java Proxy 就无法对其进行扩展和增强了。CGLIB:CGLIB 诞生于 Java 初期但不幸的是没有跟上 Java 平台的发展。虽然 CGLIB 本身是一个相当强大的 库但也变得越来越复杂。鉴于此导致许多用户放弃了 CGLIB 。JavassistJavassist 的使用对 Java 开发者来说是非常友好的它使用Java 源代码字符串和 Javassist 提供的一些简 单 API  共同拼凑出用户想要的 Java 类Javassist 自带一个编译器拼凑好的 Java 类在程序运行时会  被编译成为字节码并加载到 JVM 中。Javassist 库简单易用而且使用 Java 语法构建类与平时写 Java 代 码类似但是 Javassist 编译器在性能上比不了 Javac 编译器而且在动态组合字符串以实现比较复杂 的逻辑时容易出错。 Byte BuddyByte Buddy 提供了一种非常灵活且强大的领域特定语言通过编写简单的 Java 代码即可创建自定义的 运行时类。与此同时Byte Buddy 还具有非常开放的定制性能够应付不同复杂度的需求。 上面所有代码生成技术中我们推荐使用Byte Buddy因为Byte Buddy代码生成可的性能最高Byte Buddy 的主要侧重点在于生成更快速的代码如下图 2.2 Byte buddy学习  我们接下来详细讲解一下Byte Buddy Api 对重要的方法和类进行深度剖析。 2.2.1 ByteBuddy语法 任何一个由 Byte Buddy 创建/增强的类型都是通过 ByteBuddy 类的实例来完成的我们先来学习一下 ByteBuddy类如下代码 DynamicType.Unloaded? dynamicType new ByteBuddy()// 生成 Object的子类.subclass(Object.class)// 生成类的名称为com.jokermqc.Type.name(com.jokermqc.Type).make(); Byte Buddy 动态增强代码总共有三种方式 subclass:对应 ByteBuddy.subclass() 方法。这种方式比较好理解就是为目标类即被增强的类 生成一个子类在子类方法中插入动态代码。 rebasing:对应 ByteBuddy.rebasing() 方法。当使用 rebasing 方式增强一个类时,Byte Buddy 保存目标类中所有方法的实现也就是说当 Byte Buddy 遇到冲突的字段或方法时会将原来的字段或 方法实现复制到具有兼容签名的重新命名的私有方法中而不会抛弃这些字段和方法实现。从而达到不丢失 实现的目的。这些重命名的方法可以继续通过重命名后的名称进行调用。 redefinition:对应 ByteBuddy.redefine() 方法。当重定义一个类时Byte Buddy 可以对一个已 有的类添加属性和方法或者删除已经存在的方法实现。如果使用其他的方法实现替换已经存在的方法实现则原来存在的方法实现就会消失。 通过上述三种方式完成类的增强之后我们得到的是 DynamicType.Unloaded 对象表示的是一个未 加载的类型我们可以使用 ClassLoadingStrategy 加载此类型。  Byte Buddy 提供了几种类加载策略 这些策略定义在 ClassLoadingStrategy.Default 中其中 WRAPPER 策略创建一个新的 ClassLoader 来加载动态生成的类型。CHILD_FIRST 策略创建一个子类优先加载的 ClassLoader 即打破了双亲委派模型。  INJECTION 策略使用反射将动态生成的类型直接注入到当前 ClassLoader 中。      实现如下 Class? dynamicClazz new ByteBuddy()// 生成 Object的子类.subclass(Object.class)// 生成类的名称为com.joker.Type.name(com.joker.Type).make().load(Demo.class.getClassLoader()//使用WRAPPER 策略加载生成的动态类型.ClassLoadingStrategy.Default.WRAPPER).getLoaded(); 前面动态生成的dynamicType类只是简单的继承了Object类在实际的应用中动态生成的新类型一般的目的就是为了增强原始的方法下面通过一个示例展示Byte Buddy如何增强toString方法 // 创建ByteBuddy对象String str new ByteBuddy()// subclass增强方式.subclass(Object.class)// 新类型的类名.name(com.joker.Type)// 拦截其中的toString()方法.method(ElementMatchers.named(toString))// 让toString()方法返回固定值.intercept(FixedValue.value(Hello World!)).make()// 加载新类型默认WRAPPER策略.load(ByteBuddy.class.getClassLoader()).getLoaded()// 通过 Java反射创建 com.xxx.Type实例.newInstance()// 调用 toString()方法.toString(); 首先需要关注的是这里的method方法method()方法可以通过传入的ElementMatchers参数匹配多个需要修改的方法这的ElementMarchers.named(toString)就是按照方法名来匹配。如果通过存在多个重载方法也可以使用ElementMarchers其他API来进一步描述方法的签名如下所示 // 指定方法名称ElementMatchers.named(toString)// 指定方法的返回值.and(ElementMatchers.returns(String.class))// 指定方法参数.and(ElementMatchers.takesArguments(0)); 接下来要关注的是intercept方法通过method方法拦截到的所有方法会有intercept()方法指定的Implementtation对象决定如何增强这里的FixValue.value()会将方法的视线修改为固定值上面的例子就是固定返回字符串“Hello World”。 2.2.2 ByteBuddy创建代理 我们先创建一个普通类再为该类创建代理对象创建代理对方法进行拦截处理。 1普通类 public class UserService {//方法1public String username(){System.out.println(com.jokermqc.service.UserService.username.....);return 张三;}//方法2public String address(String username){System.out.println(com.jokermqc.service.UserService.address(String username).....);return username来自 【湖北省武汉市】;}//方法3public String address(String username,String city){System.out.println(com.jokermqc.service.UserService.address(String username,String city).....);return username来自 【湖北省city】;} } 2创建代理对象 //创建ByteBuddyUserService userService new ByteBuddy()//指定创建UserServiceImpl对象的子类.subclass(UserService.class)//匹配方法,所有方法均被拦截.method(ElementMatchers.isDeclaredBy(UserService.class))//任何拦截都返回一个固定值.intercept(MethodDelegation.to(new AspectLog()))//创建动态对象.make().load(ByteBuddy.class.getClassLoader(),ClassLoadingStrategy.Default.INJECTION).getLoaded().newInstance();userService.username();userService.address(王五,武汉);userService.address(张三); 2.2.3 ByteBuddy在程序中的应用 上面我们创建代理的案例中把返回值设置成了固定值但在真实程序汇总通常是要做特定业务流程处 理比如事务、日志、权限校验等此时我们需要用到ByteBuddy的MethodDelegation对象它可以  将拦截的目标方法委托给其他对象处理这里有几个注解我们先进行说明 RuntimeType不进行严格的参数类型检测在参数匹配失败时尝试使用类型转换方式runtime typecasting进行类型转换匹配相应方法 This注入被拦截的目标对象。 AllArguments注入目标方法的全部参数。 Origin注入目标方法对应的 Method 对象。如果拦截的是字段的话该注解应该标注到 Field 类型参数。 Super注入目标对象。通过该对象可以调用目标对象的所有方法。 SuperCall这个注解比较特殊我们要在 intercept() 方法中调用目标方法的话需要通过这种 方式注入与 Spring AOP 中的 ProceedingJoinPoint.proceed() 方法有点类似需要注意的是   这里不能修改调用参数从上面的示例的调用也能看出来参数不用单独传递都包含在其中了。 另外SuperCall 注解还可以修饰 Runnable 类型的参数只不过目标方法的返回值就拿不到了。 我们对上面的源对象userservice进行一个增强做一个日志切面 1创建代理对象 public static void main(String[] args) throws Exception {//创建ByteBuddyUserService userService new ByteBuddy()//指定创建UserServiceImpl对象的子类.subclass(UserService.class)//匹配方法,所有方法均被拦截.method(ElementMatchers.isDeclaredBy(UserService.class))//任何拦截都返回一个固定值.intercept(MethodDelegation.to(new AspectLog()))//创建动态对象.make().load(ByteBuddy.class.getClassLoader(),ClassLoadingStrategy.Default.INJECTION).getLoaded().newInstance();userService.username();userService.address(王五,武汉);userService.address(张三);} 2增强处理类 public class AspectLog {RuntimeTypepublic Object intercept(// 目标对象This Object obj,// 注入目标方法的全部参数AllArguments Object[] allArguments,// 调用目标方法必不可少SuperCall Callable? zuper,// 目标方法Origin Method method,// 目标对象Super Object instance) throws Exception {//目标方法执行前执行日志记录System.out.println(准备执行Methodmethod.getName());// 调用目标方法Object result zuper.call();//目标方法执行后执行日志记录System.out.println(方法执行完成Methodmethod.getName());return result;} } 运行结果如下 以上就是Skywalking Agent原理的解析主要是介绍了什么是Java Agent以及Byte Buddy的使用因为在Skywalking中就是使用了ByteBuddy对字节码进行增强有了这个技术基础才能更好的理解Skywalking源码
http://www.pierceye.com/news/942857/

相关文章:

  • 北京网站制作百度推广潜江资讯网二手房出售
  • 北京建网站软件深圳企业网站
  • 网站关键词互点备案网站简介怎么写
  • 网站建设报告书范文哈尔滨网站公司哪家好
  • 景观毕业设计作品网站公司网站销售平台建设费分录
  • 品牌网站建设还来大蝌蚪华为手机WordPress
  • 东莞制作企业网站公司网站营销活动页面制作
  • 有中文网站 怎么做英文网站企业网站建设 价格
  • 网络游戏网站开发建设工程施工合同样本
  • 陕西网站制作公司泸州中泸集团建设有限公司网站
  • 营销型网站建设的概念电子商务公司最低注册资本
  • 计划书网站推广的目录怎么做太原便宜做网站的公司哪家好
  • wordpress 直播插件麒麟seo外推软件
  • 网站检测报告哪里做寰宇seo
  • 徐州微信网站建设网站建设员课程
  • 做现货需要关注的网站wordpress+游戏网站
  • 佛山北京网站建设网络营销推广有哪些方法
  • 免费注册网站网址合肥网站建设第一品牌
  • 青州建网站网站建设seo虾哥网络
  • 网站框架怎么设计wordpress新闻页面模板下载
  • 国外网站平台做微信公众号的是哪个网站
  • 岳池住房和城乡建设厅网站wordpress插件清单 很多很全
  • 换域名对网站的影响做黑枸杞的公司网站
  • 昌平沙河网站建设深圳哪些公司需要做网站
  • 海尔网站建设策划书wordpress输出分类
  • 软文营销的方法广东网站建设seo优化制作设计
  • 网站怎样做推广计划创意设计ppt
  • 网站项目报价方案wordpress留言版添加
  • 网站改版协议目前哪个网站建设的最好
  • 网站建设风险管理计划长沙公司网站模板制作方案