定义swagger通用接口文档
我们用的swagger版本为
12345678910111213141516171819202122232425262728<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version></dependency><dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version></dependency><dependency> <groupId>com.spring4all</groupId ...
java-agent
简介
什么是java-agent、作用是什么、怎么用、原理是什么?java-agent可以理解为是一个代理程序,非主程序,代理程序可以做的事情就很多了,取决于你想写什么逻辑比如说Alibaba开源的Java诊断工具也可以动态的替换字节码,实现代码热更新的效果
原理通过java-agent程序我们可以获取到Instrumentation实例,得到此实例之后可以干的事情就很多了,比如说aop字节码增强,或者重新定义class等
具体原理可参考1:美团的技术分享-agent原理2:美团的技术分享-字节码增强原理
agent程序可以在主程序启动之前启动,做你想做的操作,需要编写逻辑代码并封装成Jar包,并在jvm 启动命令添加 -[javaagent|agentlib]:agentJar包的路径,jdk1.5之后才可以jar包中的class方法signature必须为 public static void premain(String agentArgs, Instrumentation inst)
也可以在主程序运行过程中启动,通过jdk自带的方法VirtualMachi ...
踩坑发现bug之解决springRemoteRestart不起作用
springDevTools提供了热部署的工具,按照网上的教程本地可以完美的支持热部署,但是一用到远程热部署(remoteRestart)就失效,热部署失败,抛ClassCastException异常为了解决这个问题,咱们今天分析一下他的原理,为什么本地可以热部署,远程热部署就会抛异常
技术栈:springBoot + MVC + DUBBO + NACOS + maven打包插件spring-boot-maven-plugin
热部署原理分析当我们修改class时,springDevTools利用了不同的classLoader重新加载class,并重新启动spring,使其生效优点就是已经加载过的class并不会重新加载以便节省性能,只针对动态修改的class重新加载即可
已加载的class无法在线卸载,只能用新的classLoader去加载,这样就起到了热部署的效果旧的classLoader以及对应加载过的class会被GC回收
在springBoot启动的时候,监听启动时的事件,然后用自己的热部署classLoader去重新启动spring(通过反射再次 ...
spring事务和aop的原理
AOPspringAop大体分为两种技术方式,一种是基于动态代理的,一种是基于字节码增强的
动态代理的有基于
jdk的
基于CGLIB的
字节码增强的有
在编译时做增强的
class加载的时候做增强的
12345678910111213public enum AdviceMode { /** * JDK proxy-based advice. */ PROXY, /** * AspectJ weaving-based advice. */ ASPECTJ}
基于动态代理-PROXYAbstractAutoProxyCreator它是个抽象类,并且是bean的后置处理器,在bean创建的时候拦截,并寻找合适的切入点返回对应的proxy其中有3个实现类
InfrastructureAdvisorAutoProxyCreator如果只是开启事务则会用到此实现AOP生效规则:bean必须是Advisor类型,且role为BeanDefinition.ROLE_INFRASTRUCTURE才会生效
AspectJAwareAdviso ...
java实例化的几种方式
直接new调用了构造
通过反射调用了构造
clone没有调用构造,但必须实现Cloneable接口,java通过native方法实现
反序列化没有调用构造,通过调用MethodAccessorGenerator#generateSerializationConstructor生成一个新的构造对象,该构造对象不会调用构造方法
通过Unsafe类的allocateInstance()方法没有调用构造,只分配内存空间
beanPostProcessor的调用流程及各种实现
在beanFactory初始化阶段会注册beanPostProcessor,它的作用就是在bean实例化前、后,初始化前、后进行拦截操作
BeanPostProcessor为最顶层的接口共有5种类型不同作用的间接接口(包含自己)
如图
InstantiationAwareBeanPostProcessor
postProcessBeforeInstantiation可以拦截bean实例化之前(不包含factoryBean#getObject),如果返回不为空,则直接调用BeanPostProcessor的后置方法并直接返回,此时bean已创建完毕(很少用)
postProcessAfterInstantiation返回值为Boolean类型,如果返回为false则不允许自动装配(很少用)
postProcessProperties自动装配,最重要的实现AutowiredAnnotationBeanPostProcessor实现自动装配
postProcessPropertyValues如果postProcessProperties返回值为null,则会调用此方法
自动装 ...
spring对bean实例化-初始化-流程
前言获取一个bean时AbstractBeanFactory#doGetBean,除非bean已经存在,否则会通过beanDefinition自动创建
创建时,如果没有beanDefinition就会报错,所以beanDefinition是一个很重要的存在
创建流程很复杂,必须要先了解bean的各种后置处理器BeanPostProcessor
spring获取bean时,底层是通过beanName获取的,如果是根据类型,那么他会先根据类型先获取name,然后根据name在获取bean
beanName可以自定义,如果非自定义默认则是classSimpleName,且第一个字母小写FactoryBean类型的beanName也是同上,如果要获取FactoryBean类型的实例话,则beanName要以"&"为前缀。否则获取的就是factoryBean对应的实际bean
以下为获取(创建)bean的大体流程
通过class类型或注解类型获取beanName不管怎样,spring底层是通过name获取对应的bean如果是根据注解获取bean,底层 ...
解析spring是如何向beanFactory注册bean的
背景ConfigurationClassPostProcessor该类是一个BeanFactoryPostProcessor后置处理程序,其主要功能就是扫描beanFactory已注册的bean上的注解进而处理注解对应的职责在spring的refresh阶段调用beanFactoryPostProcessors时该类才开始工作
在springContext初始化的时候通过AnnotationConfigUtils#registerAnnotationConfigProcessors向beanFactory注册该类
工作流程1. 挨个挨个扫描beanFactory中的未扫描的bean该类开始工作时,main方法所在的类已注册到beanFactory中先开始扫描main方法所在的类,并执行以下全部步骤,执行过程中会有新的bean注册到beanFactory中然后再从beanFactory获取所有beanNamesgetBeanDefinitionNames,过滤未扫描的bean继续扫描,直到扫完为止
每扫一个bean执行完全部步骤之后都会
执行在扫描期间扫描到的注解@I ...
JVM所有的参数配置详解
启动时输出jvm所有的配置
-XX:+PrintFlagsFinal
启动时输出非默认的jvm参数(人为配置的)
-XX:+PrintCommandLineFlags
循环放置安全点
-XX:+UseCountedLoopSafepoints
设置默认的hashcode
-XX:hashCode=0此类方案返回一个Park-Miller伪随机数生成器生成的随机数
-XX:hashCode=1此类方案将对象的内存地址,做移位运算后与一个随机数进行异或得到结果
-XX:hashCode=2永远返回固定值1
-XX:hashCode=3此类方案返回一个自增序列的当前值
-XX:hashCode=4此类方案返回当前对象的内存地址
内存1. -Xms1024m 最小堆内存大小(memory start)
2. -Mmx2048m 最大堆内存大小(memory max)
3. -XX:+UseCompressedOops 开启普通对象的指针压缩,此参数也会默认开启UseCompressedClassPointers 一个对象的指针默认为8字节(64bit) ...
打印日志引起的oom的解决方案
场景电商促销的逻辑,由于算价过程涉及的逻辑较多,所以有关算价的过程及结果数据都会打印下来,一旦有问题较容易排查满减赠折是促销模块比较复杂的逻辑,这次出现问题的原因是因为建了一个满减赠折的活动,满1元送一个赠品以及100个积分,几十万元送几十w个赠品,导致在打印日志的时候出现了问题
问题分析好在运维人员配置了自动dumpMemory
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/applicationNameHeapdump.hprof 在JVM内存溢出的时候自动dump内存快照,HeapDumpPath指定dump的路径,不指定的话默认输出路径为项目的根路径 经本地main方法测验,只要dump过一次,之后多次出现的oom不会dump第二次(删除dump的文件也不行)
用jProfiler分析之后发现果然是日志打印过多,就是因为送赠品送了几十w个,会产生几十w个对象,显然这是不正确的,实际应该用数值表示有多少个即可。所以几十w个对象再用日志输出的时候显然就成为了一个系统瓶颈毕竟在写完磁盘之前,这些对象一直贮存在 ...