礼泉住房和城乡建设局网站京东的网站建设分析

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

礼泉住房和城乡建设局网站,京东的网站建设分析,包头网站建设包头,网页设计教程心得体会javassist介绍 Javassist是一个开源的分析、编辑和创建Java字节码的类库#xff0c;主要优点是简单#xff0c;不需要了解虚拟机指令#xff0c;就能动态改变类的结构#xff0c;或者动态生成类。 apisdk应用javassist 在apisdk中主要依靠javassist增强开发者声明的开放…javassist介绍 Javassist是一个开源的分析、编辑和创建Java字节码的类库主要优点是简单不需要了解虚拟机指令就能动态改变类的结构或者动态生成类。 apisdk应用javassist 在apisdk中主要依靠javassist增强开发者声明的开放接口例如开发者声明接口 public interface TestOpenapiServiceV2 {RequestMapping(path openapi/{group_id}/users, method RequestMethod.GET)ListUserVO getList(Path(group_id) String groupId); }应用启动时扫描的TestOpenapiServiceV2会被javassist增强生成新的内存类如下 public interface \(TestOpenapiServiceV2 {RequestMapping(path openapi/{group_id}/users, method RequestMethod.GET)ListUserVO getList(Path(group_id) String groupId, SdkContext sdkContext); }内存类的命名 \) 原始类名同时复制所有原始方法并判断原始方法是否存在SdkContext.class如果不存在则需要在虚拟方法上添加SdkContext方法参数。 上面简单的描述了javassist做了哪些事情你可能会想这有啥难度直接调用javassist的api拷贝类和方法就行了。然而实际的开发过程中踩了很多坑巩固了Class类文件结构的知识点。 《深入理解Java虚拟机》这本书有讲“Class类文件结构”里面有“字段表集合”、“方法表集合”、“属性表集合”我相信大部分开发者只是在书面上看过觉得这些东西太抽象了不知道底层表示了什么希望通过javassist你可以了解一些底层的表现。 核心代码 EnhanceProxyInstance 代理对象包装 扫描到开放接口A后交给EnhanceProxyInstance处理Class的增强得到新接口B然后调用apisdk生成B的代理对象EnhanceProxyInstance可以看成A和B的映射封装JdkDynamicAopProxy#invoke方法获取B的代理对象并执行远程调用。 EnhanceProxyInstance代码如下 public class EnhanceProxyInstance {// 开放接口真正增强的执行对象private OpenApiEnhance openApiEnhance;// javassist 增强后的代理对象private Object proxyBean;// 构造器调用 OpenApiEnhance 进行 javassist 增强SdkManager 生成增强后的代理对象public EnhanceProxyInstance(Class openApiInterface) {this.openApiEnhance new OpenApiEnhance(openApiInterface);proxyBean SdkManager.get(this.openApiEnhance.getEnhanceInterface());}// 获取代理对象JdkDynamicAopProxy 中通过 Aop 的配置对象调用此方法获取代理对象public Object getProxyBean() {return proxyBean;} }OpenApiEnhance 类增强 OpenApiEnhance#create\(0是表现javassist的入口完成了原方法的拷贝添加方法参数填充方法运行时注解、注解范型、方法参数范型等。 OpenApiEnhance#create\)0代码如下 private Class create\(0(Class openApiInterface) {// 获取原始类的 CtClassthis.sourceCtClass EnhanceUtil.pool.getCtClass(openApiInterface.getName());// 拷贝原始类生成新的内存类命名\) 原始类的名称CtClass targetCtClass EnhanceUtil.copyCtClass(openApiInterface);if (targetCtClass.isFrozen()) {targetCtClass.defrost();}CtMethod[] methods sourceCtClass.getDeclaredMethods();// 获取 SdkContext 的 CtClassCtClass sdkContext EnhanceUtil.pool.getCtClass(EnhanceUtil.SDK_CONTEXT_CLASS);// 获取原始类的常量池// 知识点《深入理解Java虚拟机》常量池ConstPool constPool targetCtClass.getClassFile().getConstPool();// 遍历原始类的所有方法逐个拷贝添加 SdkContext 方法参数for (CtMethod sourceCtMethod : methods) {Method sourceMethod openApiInterface.getDeclaredMethod(sourceCtMethod.getName(), getParameterTypes(sourceCtMethod));// 拷贝原始方法注意拷贝得到的方法不带注解CtMethod targetCtMethod CtNewMethod.copy(sourceCtMethod, targetCtClass, null);// 判断是否需要自动注入 SdkContext.classboolean needAutoType needAutoType(sourceMethod);if (needAutoType) {targetCtMethod.addParameter(sdkContext);}// 知识点《深入理解Java虚拟机》Class文件结构中的 method_info 方法表集合MethodInfo methodInfo targetCtMethod.getMethodInfo();// 知识点《深入理解Java虚拟机》Class文件结构中的 attribute_info 属性表集合// Class 文件、字段表、方法表都有自己都属性表集合ListAttributeInfo attributes sourceCtMethod.getMethodInfo().getAttributes();for (AttributeInfo attribute : attributes) {// 运行时可见的注解实际上就是运行时就是进行反射调用可见的// 知识点《深入理解Java虚拟机》属性表的 RuntimeVisibleAnnotationsif (attribute instanceof AnnotationsAttribute) {// 拷贝方法上的注解AttributeInfo methodAnnotation attribute.copy(constPool, null);methodInfo.addAttribute(methodAnnotation);}// Java具有范型擦除范型情况下的方法签名记录了真实的类型// 知识点《深入理解Java虚拟机》属性表的 Signatureif (attribute instanceof SignatureAttribute) {// 范型处理AttributeInfo methodAnnotation attribute.copy(constPool, null);methodInfo.addAttribute(methodAnnotation);}if (attribute instanceof ParameterAnnotationsAttribute) {// 参数注解// 注意因为手动新增了 SdkContext 方法参数不能像方法注解一样直接拷贝会抛出方法参数不匹配的异常EnhanceUtil.copyParameterAnnotationsAttribute(constPool, methodInfo, attribute, needAutoType);}}String newSignature methodInfo.toString();targetKeySourceMethodMap.put(newSignature, sourceMethod);targetCtClass.addMethod(targetCtMethod);}Class? newClass targetCtClass.toClass();this.targetCtClass targetCtClass;return newClass; }AccessorProxyBean 代理对象注册Spring入口 Spring扫描到BeanDefinition时替换了beanClass替换的就是AccessorProxyBean它实现了Spring的FactoryBeangetObject方法触发创建EnhanceProxyInstance最终生成的代理对象被Spring管理。 public class AccessorProxyBeanT implements FactoryBeanT, ApplicationContextAware, InitializingBean,ApplicationListenerApplicationEvent {// 原始 bean classprivate ClassT sourceClass;// 代理 beanprivate T proxyBean;// 生成代理对象的工厂private AccessorFactory accessorFactory;public AccessorProxyBean(ClassT sourceClass) {this.sourceClass sourceClass;}Overridepublic T getObject() throws Exception {if (Objects.isNull(accessorFactory)) {afterPropertiesSet();}if (Objects.isNull(proxyBean)) {// 初始化 open apiproxyBean accessorFactory.create(sourceClass);}return proxyBean;} }AccessorFactory 代理对象生成工厂 ApiSdkAccessorFactory是AccessorFactory的唯一实现同时生成A和B的代理对象A由Spring管理B由EnhanceProxyInstance缓存。 代码如下 public class ApiSdkAccessorFactory implements AccessorFactory {private GlobalConfiguration globalConfiguration;public ApiSdkAccessorFactory(GlobalConfiguration globalConfiguration) {this.globalConfiguration globalConfiguration;}Overridepublic T T create(ClassT openApiInterface) {// javassist 调用入口存储增强类的代理对象EnhanceProxyInstance enhanceProxyInstance new EnhanceProxyInstance(openApiInterface);// 原始接口的包装生成的代理对象由 Spring 管理代理对象的方法之前时会由 Aop 拦截ProxyFactory proxyFactory new ProxyFactory(enhanceProxyInstance);ListAdvice advices globalConfiguration.getAdvices();for (Advice advice : advices) {proxyFactory.addAdvice(advice);}return (T) proxyFactory.getProxy();} }