├── src ├── main │ ├── resources │ │ ├── custom-last.properties │ │ ├── custom-first.properties │ │ ├── arthas command.png │ │ ├── arthas command.xmind │ │ ├── META-INF │ │ │ └── spring.factories │ │ ├── application.properties │ │ ├── data.sql │ │ └── schema.sql │ └── java │ │ └── com │ │ └── wangji92 │ │ └── arthas │ │ └── plugin │ │ └── demo │ │ ├── controller │ │ ├── NotLoaderClass.java │ │ ├── TestGeneratesClazz.java │ │ ├── LoggerDemo.java │ │ ├── User.java │ │ ├── TestEnum.java │ │ ├── CityRestController.java │ │ ├── TestLifeService.java │ │ ├── OuterClass.java │ │ ├── StaticTest.java │ │ └── CommonController.java │ │ ├── service │ │ ├── ArthasTestService.java │ │ └── impl │ │ │ └── ArthasTestServiceImpl.java │ │ ├── ArthasPluginDemoApplication.java │ │ ├── common │ │ ├── config │ │ │ ├── TestLifeConfiguration.java │ │ │ └── WebConfig.java │ │ ├── ApplicationContextProvider.java │ │ ├── environment │ │ │ ├── CustomLastEnvironmentPostProcessor.java │ │ │ ├── CustomFirstEnvironmentPostProcessor.java │ │ │ └── PrintAllSpringEnvironmentPropertiesActuator.java │ │ ├── InvokeStaticCommandLine.java │ │ └── profile │ │ │ └── HotCode.java │ │ ├── mapper │ │ └── CityMapper.java │ │ └── domain │ │ └── City.java └── test │ └── java │ └── com │ └── wangji92 │ └── arthas │ └── plugin │ └── demo │ ├── ArthasPluginDemoApplicationTests.java │ └── SpringAnnotation.java ├── start-async-profile.sh ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── start.sh ├── .gitignore ├── README.md ├── pom.xml ├── mvnw.cmd └── mvnw /src/main/resources/custom-last.properties: -------------------------------------------------------------------------------- 1 | custom.name = Custom Environment Last Name 2 | -------------------------------------------------------------------------------- /src/main/resources/custom-first.properties: -------------------------------------------------------------------------------- 1 | custom.name = Custom Environment first Name 2 | -------------------------------------------------------------------------------- /start-async-profile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | jdb -connect com.sun.jdi.SocketAttach:port=5005,hostname=127.0.0.1 -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJi92/arthas-plugin-demo/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/arthas command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJi92/arthas-plugin-demo/HEAD/src/main/resources/arthas command.png -------------------------------------------------------------------------------- /src/main/resources/arthas command.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJi92/arthas-plugin-demo/HEAD/src/main/resources/arthas command.xmind -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.env.EnvironmentPostProcessor=\ 2 | com.wangji92.arthas.plugin.demo.common.environment.CustomFirstEnvironmentPostProcessor,\ 3 | com.wangji92.arthas.plugin.demo.common.environment.CustomLastEnvironmentPostProcessor -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | dir=$(cd `dirname $0`;pwd) 3 | echo $dir 4 | mvn clean package -Dmaven.test.skip=true && \ 5 | java -agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=y \ 6 | -jar $dir/target/arthas-demo.jar 7 | 8 | 9 | # 参考 http://kail.xyz/Troubleshooting/docs/Arthas/Case/Slow-Start/ -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/NotLoaderClass.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * @author 汪小哥 7 | * @date 15-08-2020 8 | */ 9 | @Slf4j 10 | public class NotLoaderClass { 11 | public static String NO_LOAD = "not load"; 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/wangji92/arthas/plugin/demo/ArthasPluginDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ArthasPluginDemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/service/ArthasTestService.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.service; 2 | 3 | /** 4 | * 测试服务、方便观察多层 trace -E 5 | * @author 汪小哥 6 | * @date 28-03-2020 7 | */ 8 | public interface ArthasTestService { 9 | 10 | /** 11 | * trace -E 效果 12 | * @param name 13 | * @return 14 | */ 15 | String doTraceE(String name); 16 | 17 | /** 18 | * 没有捕获异常 19 | * @param number 20 | */ 21 | void traceException(int number); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/ArthasPluginDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @SpringBootApplication 8 | @EnableScheduling 9 | public class ArthasPluginDemoApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ArthasPluginDemoApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/TestGeneratesClazz.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | *

intro

7 | *
 8 |  *   {@code
 9 |  *       //code example
10 |  *   }
11 |  *  
12 | * 13 | * @author wangji 14 | * @date 2024/5/19 01:03 15 | */ 16 | @Data 17 | public class TestGeneratesClazz { 18 | 19 | private User user2; 20 | 21 | private Integer integer; 22 | 23 | private String st; 24 | 25 | private T user; 26 | 27 | private B test; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/config/TestLifeConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.config; 2 | 3 | import com.wangji92.arthas.plugin.demo.controller.TestLifeService; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * 生命周期优先级 9 | * @author 汪小哥 10 | * @date 22-06-2020 11 | */ 12 | @Configuration 13 | public class TestLifeConfiguration { 14 | 15 | @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") 16 | public TestLifeService testLifeService() { 17 | return new TestLifeService(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arthas idea plugin 体验demo 2 | 3 | ## 文章地址 4 | * csdn : https://wangji.blog.csdn.net/article/details/105187223 5 | * 语雀 : https://www.yuque.com/docs/share/01217521-2fdb-4261-8904-ef6e20d4f5ea?# 6 | * 掘金 :https://juejin.im/post/5e805213f265da47ee3f4713 7 | 8 | ## 视频地址 9 | **本文视频介绍大约 1hour,最好结合视频+文档学习+实践** 10 | 11 | * 哔哩哔哩:https://www.bilibili.com/video/BV1K7411Q7mW/ 12 | 13 | ## 插件 14 | * 插件下载地址: https://plugins.jetbrains.com/plugin/13581-arthas-idea 15 | * 插件github 地址: https://github.com/WangJi92/arthas-idea-plugin/issues 16 | * 使用文档 :https://www.yuque.com/docs/share/fa77c7b4-c016-4de6-9fa3-58ef25a97948?# 17 | 18 | 19 | > 更多[汪小哥](https://wangji.blog.csdn.net/) 20 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | 3 | 4 | ##配置数据库连接地址 5 | spring.datasource.url=jdbc:h2:mem:testdb 6 | ##配置数据库驱动 7 | spring.datasource.driver-class-name=org.h2.Driver 8 | ##配置数据库用户名 9 | spring.datasource.username=sa 10 | ##配置数据库密码 11 | spring.datasource.password= 12 | ##配置能远程访问 13 | spring.h2.console.settings.web-allow-others=true 14 | ##配置访问地址 15 | spring.h2.console.path=/h2-console 16 | ##配置项目启动 h2就启动 17 | spring.h2.console.enabled=true 18 | ##进行该配置后,每次启动程序,程序都会运行resources/db/schema.sql文件,对数据库的结构进行操作。 19 | spring.datasource.schema=classpath:schema.sql 20 | ##进行该配置后,每次启动程序,程序都会运行resources/db/data.sql文件,对数据库的数据操作。 21 | spring.datasource.data=classpath:data.sql 22 | 23 | logging.level.root=info 24 | logging.level.com.wangji92.arthas.plugin.demo.mapper.CityMapper=info -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/ApplicationContextProvider.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | import org.springframework.context.ApplicationContextAware; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 提供给arthas ognl 获取context的信息 9 | * 10 | * @author 汪小哥 11 | * @date 30-28-2020 12 | */ 13 | @Component 14 | public class ApplicationContextProvider implements ApplicationContextAware { 15 | private static ApplicationContext context; 16 | 17 | public ApplicationContext getApplicationContext() { 18 | return context; 19 | } 20 | 21 | @Override 22 | public void setApplicationContext(ApplicationContext ctx) { 23 | context = ctx; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2015-2019 the original author or authors. 3 | -- 4 | -- Licensed under the Apache License, Version 2.0 (the "License"); 5 | -- you may not use this file except in compliance with the License. 6 | -- You may obtain a copy of the License at 7 | -- 8 | -- http://www.apache.org/licenses/LICENSE-2.0 9 | -- 10 | -- Unless required by applicable law or agreed to in writing, software 11 | -- distributed under the License is distributed on an "AS IS" BASIS, 12 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | -- See the License for the specific language governing permissions and 14 | -- limitations under the License. 15 | -- 16 | 17 | insert into city (name, state, country) values ('San Francisco', 'CA', 'US'); 18 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/LoggerDemo.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.scheduling.annotation.Scheduled; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 体验一下修改logger的等级 9 | * 10 | * @author 汪小哥 11 | * @date 18-04-2020 12 | */ 13 | @Slf4j 14 | @Component 15 | public class LoggerDemo { 16 | 17 | /** 18 | * logger --name com.wangji92.arthas.plugin.demo.controller.LoggerDemo --level trace -c 18b4aac2 19 | */ 20 | @Scheduled(initialDelay = 1000, fixedRate = 5000) 21 | public void sample() { 22 | log.trace("....trace"); 23 | log.debug("......debug"); 24 | log.warn("........info"); 25 | log.info("..........warn "); 26 | log.error("............error"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2015-2019 the original author or authors. 3 | -- 4 | -- Licensed under the Apache License, Version 2.0 (the "License"); 5 | -- you may not use this file except in compliance with the License. 6 | -- You may obtain a copy of the License at 7 | -- 8 | -- http://www.apache.org/licenses/LICENSE-2.0 9 | -- 10 | -- Unless required by applicable law or agreed to in writing, software 11 | -- distributed under the License is distributed on an "AS IS" BASIS, 12 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | -- See the License for the specific language governing permissions and 14 | -- limitations under the License. 15 | -- 16 | 17 | drop table if exists city; 18 | 19 | create table city (id int primary key auto_increment, name varchar, state varchar, country varchar); 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/User.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author jet 7 | * @date 25-12-2019 8 | */ 9 | public class User { 10 | 11 | private String name; 12 | 13 | private Long age; 14 | 15 | public User(String name, Long age) { 16 | this.name = name; 17 | this.age = age; 18 | } 19 | 20 | public User() { 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | 31 | public Long getAge() { 32 | return age; 33 | } 34 | 35 | public void setAge(Long age) { 36 | this.age = age; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "User{" + 42 | "name='" + name + '\'' + 43 | ", age=" + age + 44 | '}'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/TestEnum.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * 测试一下枚举 7 | */ 8 | @Slf4j 9 | public enum TestEnum { 10 | 11 | COMMON_1("common_1", "common"), 12 | COMMON("common", "common"),; 13 | 14 | private String code; 15 | private String name; 16 | 17 | TestEnum(String code, String name){ 18 | this.code = code; 19 | this.name = name; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public void setName(String name) { 35 | this.name = name; 36 | } 37 | 38 | public static final String STATIC_FIELD = "STATIC_FIELD"; 39 | 40 | public static void staticMethod() { 41 | log.info("staticMethod"); 42 | } 43 | 44 | public static class Test { 45 | 46 | public String aa; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/mapper/CityMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2021 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software 5 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 6 | * either express or implied. See the License for the specific language governing permissions and limitations under the 7 | * License. 8 | */ 9 | 10 | package com.wangji92.arthas.plugin.demo.mapper; 11 | 12 | import com.wangji92.arthas.plugin.demo.domain.City; 13 | import org.apache.ibatis.annotations.Mapper; 14 | import org.apache.ibatis.annotations.Param; 15 | import org.apache.ibatis.annotations.Select; 16 | 17 | /** 18 | * @author Eddú Meléndez 19 | */ 20 | @Mapper 21 | public interface CityMapper { 22 | 23 | @Select("select id, name, state, country from city where state = #{state}") 24 | City findByState(@Param("state") String state); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/environment/CustomLastEnvironmentPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.environment; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.env.EnvironmentPostProcessor; 5 | import org.springframework.core.env.ConfigurableEnvironment; 6 | import org.springframework.core.env.PropertiesPropertySource; 7 | import org.springframework.core.io.ClassPathResource; 8 | import org.springframework.core.io.Resource; 9 | 10 | import java.io.IOException; 11 | import java.util.Properties; 12 | 13 | /** 14 | * 环境变量优先级 15 | * @author 汪小哥 16 | * @date 28-03-2020 17 | */ 18 | public class CustomLastEnvironmentPostProcessor implements EnvironmentPostProcessor { 19 | @Override 20 | public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { 21 | Resource resource = new ClassPathResource("custom-last.properties"); 22 | Properties properties = new Properties(); 23 | try { 24 | properties.load(resource.getInputStream()); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | environment.getPropertySources().addLast(new PropertiesPropertySource("customLast",properties)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/environment/CustomFirstEnvironmentPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.environment; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.env.EnvironmentPostProcessor; 5 | import org.springframework.core.env.ConfigurableEnvironment; 6 | import org.springframework.core.env.PropertiesPropertySource; 7 | import org.springframework.core.io.ClassPathResource; 8 | import org.springframework.core.io.Resource; 9 | 10 | import java.io.IOException; 11 | import java.util.Properties; 12 | 13 | /** 14 | * 环境变量优先级 比如nacos 中获取、配置中心获取 等等途径 如何排查优先级? 15 | * @author 汪小哥 16 | * @date 28-03-2020 17 | */ 18 | public class CustomFirstEnvironmentPostProcessor implements EnvironmentPostProcessor { 19 | @Override 20 | public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { 21 | Resource resource = new ClassPathResource("custom-first.properties"); 22 | Properties properties = new Properties(); 23 | try { 24 | properties.load(resource.getInputStream()); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | environment.getPropertySources().addFirst(new PropertiesPropertySource("customFirst",properties)); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/service/impl/ArthasTestServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.service.impl; 2 | 3 | import com.wangji92.arthas.plugin.demo.service.ArthasTestService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.util.StringUtils; 7 | 8 | /** 9 | * @author 汪小哥 10 | * @date 28-03-2020 11 | */ 12 | @Slf4j 13 | @Component 14 | public class ArthasTestServiceImpl implements ArthasTestService { 15 | @Override 16 | public String doTraceE(String name) { 17 | try { 18 | //1、thread 1 s 19 | Thread.sleep(1000); 20 | //2 get a currentTimeMillis 21 | if(StringUtils.isEmpty(name)){ 22 | name = System.currentTimeMillis()+""; 23 | } 24 | //3、use trace -E is very well 25 | return Thread.currentThread().getName() + name; 26 | } catch (InterruptedException e) { 27 | log.error("InterruptedException", e); 28 | } 29 | return ""; 30 | } 31 | 32 | @Override 33 | public void traceException(int number) { 34 | int i = number / 0; 35 | //maybe old code happen before error,but not capture exception,log not found 36 | //use trace is very useful 37 | log.info(i + ""); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/CityRestController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2021 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software 5 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 6 | * either express or implied. See the License for the specific language governing permissions and limitations under the 7 | * License. 8 | */ 9 | package com.wangji92.arthas.plugin.demo.controller; 10 | 11 | import com.wangji92.arthas.plugin.demo.domain.City; 12 | import com.wangji92.arthas.plugin.demo.mapper.CityMapper; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | @RequestMapping("/cities") 19 | @RestController 20 | public class CityRestController { 21 | 22 | 23 | private final CityMapper cityMapper; 24 | 25 | public CityRestController(CityMapper cityMapper){ 26 | this.cityMapper = cityMapper; 27 | } 28 | 29 | @GetMapping("{state}") 30 | City getCity(@PathVariable String state) { 31 | return cityMapper.findByState(state); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/TestLifeService.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.BeansException; 5 | import org.springframework.beans.factory.DisposableBean; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.context.ApplicationContextAware; 9 | 10 | import javax.annotation.PostConstruct; 11 | import javax.annotation.PreDestroy; 12 | 13 | /** 14 | * 生命周期小例子 15 | * 16 | * @author 汪小哥 17 | * @date 22-06-2020 18 | */ 19 | @Slf4j 20 | public class TestLifeService implements InitializingBean, DisposableBean, ApplicationContextAware { 21 | @PostConstruct 22 | public void postConstruct() { 23 | log.info("postConstruct"); 24 | } 25 | 26 | @PreDestroy 27 | public void preDestroy() { 28 | log.info("preDestroy"); 29 | } 30 | 31 | @Override 32 | public void destroy() throws Exception { 33 | log.info("destroy"); 34 | } 35 | 36 | @Override 37 | public void afterPropertiesSet() throws Exception { 38 | log.info("afterPropertiesSet"); 39 | } 40 | 41 | public void initMethod() { 42 | log.info("initMethod"); 43 | } 44 | 45 | public void destroyMethod() { 46 | log.info("destroyMethod"); 47 | } 48 | 49 | @Override 50 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 51 | log.info("applicationContextAware"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/InvokeStaticCommandLine.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.wangji92.arthas.plugin.demo.common.profile.HotCode; 5 | import com.wangji92.arthas.plugin.demo.controller.OuterClass; 6 | import com.wangji92.arthas.plugin.demo.controller.StaticTest; 7 | import com.wangji92.arthas.plugin.demo.controller.TestEnum; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.CommandLineRunner; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * @author 汪小哥 15 | * @date 28-03-2020 16 | */ 17 | @Component 18 | @Slf4j 19 | public class InvokeStaticCommandLine implements CommandLineRunner { 20 | 21 | @Autowired 22 | private HotCode hotCode; 23 | 24 | @Override 25 | public void run(String... args) throws Exception { 26 | //触发调用一下静态方法,不然没有使用,不会被加载 27 | log.info("test" + StaticTest.getInvokeStaticName()); 28 | new Thread(hotCode::hotMethodRun, "hotCode").start(); 29 | 30 | OuterClass.InnerClass innerClass = new OuterClass.InnerClass(); 31 | innerClass.anonymousClassRun(); 32 | OuterClass.InnerClass.InnerInnerClass innerInnerClass = innerClass.new InnerInnerClass(); 33 | innerInnerClass.anonymousInnerInnerClassRun(); 34 | log.info(TestEnum.COMMON.getCode()); 35 | 36 | JSON.toJSON(TestEnum.COMMON); 37 | 38 | 39 | log.info("OuterClass.StaticInnerClass.getStaticInnerName() {}", OuterClass.StaticInnerClass.getStaticInnerName()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.config; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.util.StringUtils; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 10 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 11 | 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | /** 15 | * @author wangji 16 | * @date 2021/12/4 8:48 下午 17 | */ 18 | @Component 19 | @Slf4j 20 | public class WebConfig implements WebMvcConfigurer { 21 | 22 | @Override 23 | public void addInterceptors(InterceptorRegistry registry) { 24 | registry.addInterceptor(new HandlerInterceptor() { 25 | 26 | @Override 27 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 28 | Object handler) throws Exception { 29 | 30 | String reqUri = request.getRequestURI(); 31 | 32 | if (!reqUri.contains("checkHead")) { 33 | return true; 34 | } 35 | 36 | String code = request.getHeader("code"); 37 | if (StringUtils.isEmpty(code)) { 38 | return false; 39 | } 40 | if ("arthas".equals(code)) { 41 | return true; 42 | } 43 | return false; 44 | } 45 | 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/domain/City.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2021 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software 5 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 6 | * either express or implied. See the License for the specific language governing permissions and limitations under the 7 | * License. 8 | */ 9 | package com.wangji92.arthas.plugin.demo.domain; 10 | 11 | import java.io.Serializable; 12 | 13 | /** 14 | * @author Eddú Meléndez 15 | */ 16 | public class City implements Serializable { 17 | 18 | private static final long serialVersionUID = 1L; 19 | 20 | private Long id; 21 | 22 | private String name; 23 | 24 | private String state; 25 | 26 | private String country; 27 | 28 | public Long getId() { 29 | return this.id; 30 | } 31 | 32 | public void setId(Long id) { 33 | this.id = id; 34 | } 35 | 36 | public String getName() { 37 | return this.name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | public String getState() { 45 | return this.state; 46 | } 47 | 48 | public void setState(String state) { 49 | this.state = state; 50 | } 51 | 52 | public String getCountry() { 53 | return this.country; 54 | } 55 | 56 | public void setCountry(String country) { 57 | this.country = country; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return getId() + "," + getName() + "," + getState() + "," + getCountry(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/profile/HotCode.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.profile; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Random; 8 | import java.util.UUID; 9 | 10 | /** 11 | * 12 | * ./profiler.sh -d 10 -e alloc -f output-alloc.svg -t 1786 13 | * ./profiler.sh -d 10 -e cpu -f output-cpu.svg --all-user 1786 14 | * ./profiler.sh -d 10 -f output-cpu.svg --all-user 1786 15 | * ./profiler.sh -d 10 -e com.wangji92.arthas.plugin.demo.common.profile.HotCode.hotMethod1 -f output-method.svg --all-user 1786 16 | * ./profiler.sh -d 10 -f output-cpu.svg --all-user 1786 17 | * ./profiler.sh -d 10 -e itimer -f output-itimer.svg --all-user 1786 18 | * ./profiler.sh -d 10 -e wall -f output-wall.svg -t 1786 19 | * ./profiler.sh list 1786 20 | * ./profiler.sh 21 | * 模拟热点代码 22 | * 参考文章 : https://www.jianshu.com/p/918e1dce61cd 23 | * 24 | * @author 汪小哥 25 | * @date 23-06-2020 26 | */ 27 | @Component 28 | @Slf4j 29 | public class HotCode { 30 | 31 | private static volatile int value; 32 | 33 | public void hotMethodRun() { 34 | while (true) { 35 | //log.info("hotMethodScheduled begin"); 36 | HotCode.hotMethod1(); 37 | HotCode.hotMethod2(); 38 | HotCode.hotMethod3(); 39 | HotCode.allocate(); 40 | //log.info("hotMethodScheduled end"); 41 | } 42 | } 43 | 44 | private static Object array; 45 | 46 | /** 47 | * 生成 大长度的数组 48 | */ 49 | private static void allocate() { 50 | array = new int[6 * 100]; 51 | array = new Integer[6 * 100]; 52 | } 53 | 54 | 55 | /** 56 | * 生成一个UUID 57 | */ 58 | private static void hotMethod3() { 59 | ArrayList list = new ArrayList<>(); 60 | UUID uuid = UUID.randomUUID(); 61 | String str = uuid.toString().replace("-", ""); 62 | list.add(str); 63 | } 64 | 65 | /** 66 | * 数字累加 67 | */ 68 | private static void hotMethod2() { 69 | value++; 70 | } 71 | 72 | /** 73 | * 生成一个随机数 74 | */ 75 | private static void hotMethod1() { 76 | Random random = new Random(); 77 | int anInt = random.nextInt(); 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/common/environment/PrintAllSpringEnvironmentPropertiesActuator.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.common.environment; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.CommandLineRunner; 5 | import org.springframework.context.EnvironmentAware; 6 | import org.springframework.core.env.ConfigurableEnvironment; 7 | import org.springframework.core.env.Environment; 8 | import org.springframework.core.env.PropertySource; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.Iterator; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | /** 17 | *

intro

18 | *
19 |  *   {@code
20 |  *       //code example
21 |  *   }
22 |  *  
23 | * 24 | * @author wangji 25 | * @date 2024/11/15 21:50 26 | */ 27 | @Slf4j 28 | @Component 29 | public class PrintAllSpringEnvironmentPropertiesActuator implements CommandLineRunner, EnvironmentAware { 30 | 31 | private Environment environment; 32 | 33 | @Override 34 | public void run(String... args) throws Exception { 35 | try { 36 | printEnvironmentProperties(); 37 | } catch (Exception e) { 38 | log.error("print env error", e); 39 | } 40 | } 41 | 42 | private void printEnvironmentProperties() { 43 | List springConfigList = new LinkedList(); 44 | Iterator> iterator = ((ConfigurableEnvironment) this.environment).getPropertySources().iterator(); 45 | int order = 1; 46 | while (iterator.hasNext()) { 47 | PropertySource source = iterator.next(); 48 | String name = source.getName(); 49 | springConfigList.add("order=" + order + " --------------------env source name=" + name + ""); 50 | Object o = source.getSource(); 51 | if (o instanceof Map) { 52 | ((Map) o).forEach((key, value) -> springConfigList.add(key + "=" + this.environment.getProperty(key))); 53 | } 54 | order++; 55 | } 56 | String envListInfo = String.join("\n", springConfigList); 57 | log.info("spring current env:\n{}", envListInfo); 58 | } 59 | 60 | 61 | @Override 62 | public void setEnvironment(Environment environment) { 63 | this.environment = environment; 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/OuterClass.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import lombok.Data; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | /** 7 | * @author jet 8 | * @date 10-08-2020 9 | */ 10 | @Slf4j 11 | public class OuterClass { 12 | 13 | private String outerName; 14 | 15 | private int outerAge; 16 | 17 | public enum Type{ 18 | TEST 19 | } 20 | 21 | @Data 22 | public static class InnerClass { 23 | private String innerName; 24 | private int innerAge; 25 | 26 | public void anonymousClassRun(){ 27 | Runnable x = new Runnable() { 28 | private String field; 29 | @Override 30 | public void run() { 31 | log.info(this.getClass().getName()); 32 | } 33 | }; 34 | x.run(); 35 | } 36 | 37 | public int getInnerAge() { 38 | return innerAge; 39 | } 40 | @Data 41 | public class InnerInnerClass { 42 | private String innerInnerName; 43 | private int innerInnerAge; 44 | 45 | public int getInnerInnerAge() { 46 | return innerInnerAge; 47 | } 48 | 49 | public void setInnerInnerAge(int innerInnerAge) { 50 | this.innerInnerAge = innerInnerAge; 51 | } 52 | public void anonymousInnerInnerClassRun(){ 53 | Runnable x = new Runnable() { 54 | @Override 55 | public void run() { 56 | log.info(this.getClass().getName()); 57 | } 58 | }; 59 | x.run(); 60 | } 61 | } 62 | } 63 | 64 | public static class StaticInnerClass { 65 | private static String STATIC_INNER_NAME = "staticInnerName"; 66 | 67 | public static String getStaticInnerName() { 68 | return STATIC_INNER_NAME; 69 | } 70 | 71 | public void anonymousClassRun(){ 72 | Runnable x = new Runnable() { 73 | private String field; 74 | @Override 75 | public void run() { 76 | log.info(this.getClass().getName()); 77 | } 78 | }; 79 | x.run(); 80 | } 81 | 82 | } 83 | 84 | public void main(String[] args) { 85 | InnerClass innerClass = new InnerClass(); 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.wangji92.arthas.plugin 12 | demo 13 | 0.0.1-SNAPSHOT 14 | arthas plugin demo 15 | arthas plugin demo 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.alibaba 24 | fastjson 25 | 1.2.83 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | org.mybatis.spring.boot 33 | mybatis-spring-boot-starter 34 | 2.1.2 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-jdbc 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-devtools 43 | runtime 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-configuration-processor 49 | true 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | true 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-test 59 | test 60 | 61 | 62 | org.junit.vintage 63 | junit-vintage-engine 64 | 65 | 66 | 67 | 68 | junit 69 | junit 70 | test 71 | 72 | 73 | org.springframework 74 | spring-tx 75 | 76 | 77 | com.h2database 78 | h2 79 | runtime 80 | 81 | 82 | org.mybatis.spring.boot 83 | mybatis-spring-boot-starter-test 84 | 2.2.0 85 | test 86 | 87 | 88 | 89 | 90 | arthas-demo 91 | 92 | 93 | org.springframework.boot 94 | spring-boot-maven-plugin 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/wangji92/arthas/plugin/demo/SpringAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | import org.springframework.aop.framework.ProxyFactory; 7 | import org.springframework.aop.support.AopUtils; 8 | import org.springframework.cglib.core.ReflectUtils; 9 | import org.springframework.core.annotation.AnnotatedElementUtils; 10 | import org.springframework.core.annotation.AnnotationUtils; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; 13 | import org.springframework.transaction.annotation.Propagation; 14 | import org.springframework.transaction.annotation.Transactional; 15 | import org.springframework.transaction.interceptor.TransactionAttribute; 16 | import org.springframework.util.ReflectionUtils; 17 | import org.springframework.web.bind.annotation.GetMapping; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | 20 | import java.lang.reflect.Method; 21 | 22 | /** 23 | * @author 汪小哥 24 | * @date 05-07-2020 25 | */ 26 | @Slf4j 27 | public class SpringAnnotation { 28 | public interface AnnotationsServiceInterface { 29 | 30 | @Transactional 31 | void test(); 32 | 33 | } 34 | 35 | public class AnnotationsServiceInterfaceImpl implements AnnotationsServiceInterface { 36 | 37 | @Override 38 | public void test() { 39 | 40 | } 41 | } 42 | 43 | @Test 44 | public void testInterface() throws Exception { 45 | AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(true); 46 | Method test = ReflectionUtils.findMethod(AnnotationsServiceImpl.class, "test"); 47 | TransactionAttribute transactionAttribute = attributeSource.getTransactionAttribute(test, 48 | AnnotationsServiceInterface.class); 49 | 50 | log.info("transactionAttribute={}", transactionAttribute.toString()); 51 | 52 | } 53 | 54 | @Test 55 | public void testInterfaceImpl() throws Exception { 56 | AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(true); 57 | Method test = ReflectionUtils.findMethod(AnnotationsServiceImpl.class, "test"); 58 | TransactionAttribute transactionAttribute = attributeSource.getTransactionAttribute(test, 59 | AnnotationsServiceInterfaceImpl.class); 60 | 61 | log.info("transactionAttribute={}", transactionAttribute.toString()); 62 | 63 | } 64 | 65 | @Transactional(rollbackFor = IndexOutOfBoundsException.class, propagation = Propagation.REQUIRES_NEW) 66 | public class AnnotationsService { 67 | 68 | public void test() { 69 | 70 | } 71 | 72 | } 73 | 74 | @Transactional(propagation = Propagation.REQUIRES_NEW) 75 | public class AnnotationsServiceImpl extends AnnotationsService { 76 | 77 | @Override 78 | public void test() { 79 | 80 | } 81 | } 82 | 83 | @Test 84 | public void testServices() throws Exception { 85 | AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(true); 86 | Method test = ReflectionUtils.findMethod(AnnotationsServiceImpl.class, "test"); 87 | TransactionAttribute transactionAttribute = attributeSource.getTransactionAttribute(test, 88 | AnnotationsService.class); 89 | 90 | log.info("transactionAttribute={}", transactionAttribute.toString()); 91 | 92 | } 93 | 94 | @Test 95 | public void testServicesImpl() throws Exception { 96 | AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(true); 97 | Method test = ReflectionUtils.findMethod(AnnotationsServiceImpl.class, "test"); 98 | TransactionAttribute transactionAttribute = attributeSource.getTransactionAttribute(test, 99 | AnnotationsServiceImpl.class); 100 | 101 | log.info("transactionAttribute={}", transactionAttribute.toString()); 102 | 103 | } 104 | 105 | @Test 106 | @GetMapping(value = "/GetMapping", consumes = MediaType.APPLICATION_JSON_VALUE) 107 | public void test1() throws NoSuchMethodException { 108 | Method method = ReflectUtils.findDeclaredMethod( 109 | SpringAnnotation.class, "test", null); 110 | 111 | // AnnotationUtils 不支持注解属性覆盖 112 | RequestMapping requestMappingAnn1 = AnnotationUtils.getAnnotation(method, RequestMapping.class); 113 | Assert.assertEquals(new String[]{}, requestMappingAnn1.value()); 114 | Assert.assertEquals(new String[]{}, requestMappingAnn1.consumes()); 115 | 116 | // AnnotatedElementUtils 支持注解属性覆盖 117 | RequestMapping requestMappingAnn2 = AnnotatedElementUtils.getMergedAnnotation(method, RequestMapping.class); 118 | Assert.assertEquals(new String[]{"/GetMapping"}, requestMappingAnn2.value()); 119 | Assert.assertEquals(new String[]{MediaType.APPLICATION_JSON_VALUE}, requestMappingAnn2.consumes()); 120 | } 121 | 122 | 123 | @Test 124 | @GetMapping(value = "/GetMapping", consumes = MediaType.APPLICATION_JSON_VALUE) 125 | public void test() throws NoSuchMethodException { 126 | Method method = ReflectUtils.findDeclaredMethod(SpringAnnotation.class, "test", null); 127 | 128 | // AnnotationUtils 不支持注解属性覆盖 129 | RequestMapping requestMappingAnn1 = AnnotationUtils.getAnnotation(method, RequestMapping.class); 130 | 131 | Class targetClass = AopUtils.getTargetClass(requestMappingAnn1); 132 | Assert.assertEquals(new String[]{}, requestMappingAnn1.value()); 133 | Assert.assertEquals(new String[]{}, requestMappingAnn1.consumes()); 134 | 135 | ProxyFactory proxyFactory = new ProxyFactory(); 136 | proxyFactory.setTargetClass(AnnotationsServiceImpl.class); 137 | proxyFactory.setTarget(new AnnotationsServiceImpl()); 138 | Object proxy = proxyFactory.getProxy(); 139 | 140 | Class targetClass1 = AopUtils.getTargetClass(proxy); 141 | 142 | Method test = ReflectionUtils.findMethod(targetClass1, "test"); 143 | 144 | AnnotationTransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(true); 145 | TransactionAttribute transactionAttribute = attributeSource.getTransactionAttribute(test, targetClass1); 146 | 147 | // AnnotatedElementUtils 支持注解属性覆盖 148 | RequestMapping requestMappingAnn2 = AnnotatedElementUtils.getMergedAnnotation(method, RequestMapping.class); 149 | Assert.assertEquals(new String[]{"/GetMapping"}, requestMappingAnn2.value()); 150 | Assert.assertEquals(new String[]{MediaType.APPLICATION_JSON_VALUE}, requestMappingAnn2.consumes()); 151 | 152 | GetMapping getMapping = AnnotationUtils.getAnnotation(method, GetMapping.class); 153 | 154 | GetMapping getMapping1 = AnnotatedElementUtils.getMergedAnnotation(method, GetMapping.class); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/StaticTest.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.util.CollectionUtils; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * @author 汪小哥 13 | * @date 28-03-2020 14 | */ 15 | @Component 16 | public class StaticTest { 17 | 18 | /** 19 | * 20 | * 测试获取 static field 名称 21 | * 22 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_NAME' -c 482503f0 23 | */ 24 | private static String INVOKE_STATIC_NAME = "INVOKE_STATIC_NAME"; 25 | 26 | /** 27 | * 测试 反射设置static 的信息 28 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_FINAL' -c 482503f0 29 | * ognl -x 3 '#field=@com.wangji92.arthas.plugin.demo.controller.StaticTest@class.getDeclaredField("INVOKE_STATIC_FINAL"),#modifiers=#field.getClass().getDeclaredField("modifiers"),#modifiers.setAccessible(true),#modifiers.setInt(#field,#field.getModifiers() & ~@java.lang.reflect.Modifier@FINAL),#field.setAccessible(true),#field.set(null," ")' -c 482503f0 30 | */ 31 | private static final String INVOKE_STATIC_FINAL = "INVOKE_STATIC_FINAL"; 32 | 33 | /** 34 | * 测试 处理 static double or long 35 | * ognl -x 3 '#field=@com.wangji92.arthas.plugin.demo.controller.StaticTest@class.getDeclaredField("INVOKE_STATIC_DOUBLE"),#field.setAccessible(true),#field.set(null,0D)' -c 482503f0 36 | */ 37 | private static Double INVOKE_STATIC_DOUBLE = 111D; 38 | 39 | /** 40 | * 演示watch 获取值 41 | * watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_LONG}' -n 5 -x 3 '1==1' 42 | */ 43 | private static Long INVOKE_STATIC_LONG = 1211L; 44 | 45 | /** 46 | * 演示watch 获取值 47 | * 48 | * watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,target.filedValue}' -n 5 -x 3 'method.initMethod(),method.constructor!=null || !@java.lang.reflect.Modifier@isStatic(method.method.getModifiers())' 49 | */ 50 | private String filedValue = "wangji92"; 51 | 52 | /** 53 | * 调用非静态的方法才可以在watch 的时候获取非静态的字段 54 | * 55 | * watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,target.filedValue}' -n 5 -x 3 'method.initMethod(),method.constructor!=null || !@java.lang.reflect.Modifier@isStatic(method.method.getModifiers())' 56 | * @return 57 | */ 58 | public String getFieldValue(){ 59 | return this.filedValue; 60 | } 61 | 62 | /** 63 | * 调用方法 64 | * 65 | * @return 66 | */ 67 | public static String getInvokeStaticName() { 68 | return INVOKE_STATIC_NAME; 69 | } 70 | 71 | /** 72 | * 调用参数为class = @xxxClass@class 相当于调用静态的方法 73 | *

74 | * 备注插件不支持 ,需要记住小知识点 75 | *

76 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeClass(@com.wangji92.arthas.plugin.demo.controller.StaticTest@class)' -c 482503f0 77 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeClass(@java.lang.Object@class)' -c 316bc132 78 | * 79 | * @param classN 80 | * @return 81 | */ 82 | public static String invokeClass(Class classN) { 83 | if (classN == null) { 84 | return ""; 85 | } 86 | return classN.getName(); 87 | } 88 | 89 | /** 90 | * 对于class类型的参数进行了增强处理 91 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeClass1(@com.wangji92.arthas.plugin.demo.controller.User@class)' -c 316bc132 92 | * @param classN 93 | * @return 94 | */ 95 | public static String invokeClass1(Class classN) { 96 | if (classN == null) { 97 | return ""; 98 | } 99 | return classN.getName(); 100 | } 101 | 102 | 103 | /** 104 | * array 场景 参考:https://blog.csdn.net/u010634066/article/details/101013479 105 | * 如何使用ognl传递方法?ognl按照表达式逗号分割顺序执行命令,支持链式调用,#开头在ognl 里面是变量全局的,可以传递。 106 | * 复杂的参数场景 #listObject={} ,#mapObject= #{"key","value"} #array=new java.lang.String[]{"1"} 107 | *

108 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodArray(new java.lang.String[]{"wangji"})' -c 316bc132 109 | * ognl -x 3 '#array=new java.lang.String[]{"wangji"},@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodArray(#array)' -c 316bc132 110 | * 111 | * @param arrays 112 | * @return 113 | */ 114 | public static String invokeStaticMethodArray(String[] arrays) { 115 | if (arrays == null) { 116 | return ""; 117 | } 118 | return Arrays.toString(arrays); 119 | } 120 | 121 | 122 | /** 123 | * 调用静态方法 参数为list 124 | * 复杂的参数场景 #listObject={} ,#mapObject= #{"key","value"} #array=new java.lang.String[]{"1"} 125 | *

126 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodParamList({"wangji"})' -c 316bc132 127 | * 128 | * @param list 129 | * @return 130 | */ 131 | public static String invokeStaticMethodParamList(List list) { 132 | if (CollectionUtils.isEmpty(list)) { 133 | return "EMPTY"; 134 | } 135 | return list.toString(); 136 | } 137 | 138 | /** 139 | * 调用静态方法 参数为map 140 | * 复杂的参数场景 #listObject={} ,#mapObject= #{"key","value"} #array=new java.lang.String[]{"1"} 141 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodParamMap(#{"name":"wangji"})' -c 316bc132 142 | * 143 | * @param map 144 | * @return 145 | */ 146 | public static String invokeStaticMethodParamMap(Map map) { 147 | if (map == null) { 148 | return "EMPTY"; 149 | } 150 | return map.toString(); 151 | } 152 | 153 | /** 154 | * 参考:https://blog.csdn.net/u010634066/article/details/101013479 155 | * 如何使用ognl传递方法?ognl按照表达式逗号分割顺序执行命令,支持链式调用,#开头在ognl 里面是变量全局的,可以传递。 156 | *

157 | * ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodParamObjUser(new com.wangji92.arthas.plugin.demo.controller.User("wangji",27L))' -c e374b99 158 | * ognl -x 3 '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodParamObjUser(#user)' -c e374b99 159 | * 调用静态方法 是一个对象 160 | * 161 | * @param user 162 | * @return 163 | */ 164 | public static String invokeStaticMethodParamObjUser(User user) { 165 | if (user == null) { 166 | return "EMPTY"; 167 | } 168 | return user.toString(); 169 | } 170 | 171 | /** 172 | * 复杂的参数场景 #listObject={} ,#mapObject= #{"key","value"} #array=new java.lang.String[]{"1"} 173 | *

174 | * ognl -x 3 '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),@com.wangji92.arthas.plugin.demo.controller.StaticTest@invokeStaticMethodParamObjListUser(0,{#user,#user})' -c e374b99 175 | * 176 | * @param number 177 | * @param names 178 | * @return 179 | */ 180 | public static String invokeStaticMethodParamObjListUser(Integer number, List names) { 181 | if (number == null) { 182 | number = 1; 183 | } 184 | if (names == null) { 185 | names = Collections.EMPTY_LIST; 186 | } 187 | return number + names.toString(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /src/main/java/com/wangji92/arthas/plugin/demo/controller/CommonController.java: -------------------------------------------------------------------------------- 1 | package com.wangji92.arthas.plugin.demo.controller; 2 | 3 | import com.wangji92.arthas.plugin.demo.service.ArthasTestService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.util.StringUtils; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.ResponseBody; 13 | 14 | import java.time.MonthDay; 15 | import java.util.*; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | import java.util.concurrent.CopyOnWriteArrayList; 18 | import java.util.concurrent.atomic.AtomicLong; 19 | import java.util.regex.Pattern; 20 | 21 | /** 22 | * arthas 体验demo 23 | * 24 | * @author 汪小哥 25 | * @date 28-03-2020 26 | */ 27 | @Controller 28 | @RequestMapping("/") 29 | @Slf4j 30 | public class CommonController { 31 | 32 | public CommonController() { 33 | } 34 | 35 | @Autowired 36 | private ArthasTestService arthasTestService; 37 | 38 | @Autowired 39 | private ApplicationContext applicationContext; 40 | 41 | @Autowired 42 | private StaticTest staticTest; 43 | 44 | public static final String WATCH_STATIC_VALUE = "wangji"; 45 | 46 | private String watchValue = "wangji"; 47 | 48 | /** 49 | * https://github.com/alibaba/arthas/issues/71 fastjson 转换复杂对象进行调用 50 | * https://github.com/WangJi92/arthas-idea-plugin/issues/127 复杂类型参数的支持 51 | * @param param 52 | * 处理基本类型参数、没有泛型 53 | * {@code 54 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam(@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class))' -c 6f54e410 55 | * } 56 | * @return 57 | */ 58 | public Object testParam(User param) { 59 | return param; 60 | } 61 | 62 | /** 63 | * 处理基本集合 Map 参数 64 | * {@code 65 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((#{"_AR_": @com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)}))' -c 6f54e410 66 | * } 67 | * @param param 68 | * @return 69 | */ 70 | public Object testParam(Map param) { 71 | return param; 72 | } 73 | 74 | /** 75 | * 处理基本集合List 参数 76 | * {@code 77 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam({@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)})' -c 6f54e410 78 | * } 79 | * @param param 80 | * @return 81 | */ 82 | public Object testParam(List param) { 83 | return param; 84 | } 85 | 86 | /** 87 | * 泛型内部有通配符 88 | * {@code 89 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam2({@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)})' -c c212d8b 90 | * } 91 | * @param param 92 | * @return 93 | */ 94 | public Object testParam2(List param) { 95 | return param; 96 | } 97 | 98 | public Object testParam2(Map param) { 99 | return param; 100 | } 101 | 102 | /** 103 | * 处理基本集合Set参数 104 | * {@code 105 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((#set=new java.util.HashSet(),#set.add(@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)),#set))' -c 6f54e410 106 | * } 107 | * @param param 108 | * @return 109 | */ 110 | public Object testParam(Set param) { 111 | return param; 112 | } 113 | 114 | /** 115 | * 处理特殊JDK Map 116 | * {@code 117 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((#@java.util.concurrent.ConcurrentHashMap@{"_AR_": @com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)}))' -c 6f54e410 118 | * } 119 | * @param param 120 | * @return 121 | */ 122 | public Object testParam(ConcurrentHashMap param) { 123 | return param; 124 | } 125 | 126 | /** 127 | * 出来特殊JDK List 128 | * {@code 129 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((#list=new java.util.concurrent.CopyOnWriteArrayList(),#list.add(@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)),#list))' -c 6f54e410 130 | * } 131 | * @param param 132 | * @return 133 | */ 134 | public Object testParam(CopyOnWriteArrayList param) { 135 | return param; 136 | } 137 | 138 | /** 139 | * 处理特殊JDK 参数 140 | * {@code 141 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam(@com.alibaba.fastjson.JSON@parseObject("\"2024-05-26 00:31:23 +0800\"",@java.util.Calendar@class))' -c 6f54e410 142 | * } 143 | * @param param 144 | * @return 145 | */ 146 | public Object testParam(Calendar param) { 147 | return param; 148 | } 149 | 150 | 151 | /** 152 | * 处理内部类数组 153 | *{@code 154 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((new com.wangji92.arthas.plugin.demo.controller.OuterClass$InnerClass[]{@com.alibaba.fastjson.JSON@parseObject("{\"innerName\":\" \",\"innerAge\":0}",@com.wangji92.arthas.plugin.demo.controller.OuterClass$InnerClass@class)}))' -c 6f54e410 155 | *} 156 | * @param param 157 | * @return 158 | */ 159 | public Object testParam(OuterClass.InnerClass[] param) { 160 | return param; 161 | } 162 | 163 | /** 164 | * 处理 CLazz 类型内部类 165 | * {@code 166 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((@com.wangji92.arthas.plugin.demo.controller.OuterClass$InnerClass@class))' -c 6f54e410 167 | * } 168 | * @param param 169 | * @return 170 | */ 171 | public Object testParam(Class param) { 172 | return param; 173 | } 174 | 175 | 176 | /** 177 | * 处理内部类枚举参数 178 | * {@code 179 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam(@com.wangji92.arthas.plugin.demo.controller.OuterClass$Type@TEST)' -c 6f54e410 180 | * } 181 | * @param param 182 | * @return 183 | */ 184 | public Object testParam(OuterClass.Type param) { 185 | return param; 186 | } 187 | 188 | 189 | /** 190 | * 处理基本数组 191 | * {@code 192 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((new java.lang.Integer[]{0}))' -c 6f54e410 193 | * } 194 | * @param param 195 | * @return 196 | */ 197 | public Object testParam(Integer[] param) { 198 | return param; 199 | } 200 | 201 | 202 | /** 203 | * 处理这种泛型复杂参数 TestGeneratesClazz> test 204 | * 1、ognl 本身不支持泛型参数 205 | * 2、通过Json 构建外层对象 TestGeneratesClazz 206 | * 3、获取TestGeneratesClazz所有泛型参数 207 | * 4、遍历TestGeneratesClazz 所有字段 包含了泛型参数 且非基本类型,通过判断是否有set方法进行赋值 同理赋值使用json 构造 208 | * 5、构建脚本 差异化解决无法处理泛型的问题.. 209 | * {@code 210 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController --express 'instances[0].testParam((#p=@com.alibaba.fastjson.JSON@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class),(#p.setUser(@com.alibaba.fastjson.JSON@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class))),(#p.setTest(@com.alibaba.fastjson.JSON@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class))),#p))' -c 6f54e410 211 | * } 212 | * @param param 213 | * @return 214 | */ 215 | public Object testParam(TestGeneratesClazz> param) { 216 | return param; 217 | } 218 | 219 | 220 | 221 | /** 222 | * tt 测试 or 通过ognl 调用spring context getBean 调用处理 ognl -x 3 223 | * '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()' 224 | * -c e374b99 225 | *

226 | * 记录时间隧道,重新触发一次 tt -t com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5 tt -p -i 227 | * 1000 228 | * 229 | * @return 230 | */ 231 | @RequestMapping("/getRandomInteger") 232 | @ResponseBody 233 | public Integer getRandomInteger() { 234 | return new Random().nextInt(1000); 235 | 236 | } 237 | 238 | /** 239 | * use trace -E trace -E 240 | * com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService 241 | * traceE|doTraceE -n 5 242 | *

243 | * ##包含jdk的调用 trace -E 244 | * com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService 245 | * traceE|doTraceE -n 5 --skipJDKMethod false 246 | * 247 | * @param name 248 | * @return 249 | */ 250 | @RequestMapping("/trace/{name}") 251 | @ResponseBody 252 | public String traceE(@PathVariable String name) { 253 | if (StringUtils.isEmpty(name)) { 254 | name = "汪小哥"; 255 | } else { 256 | name = name + "汪小哥"; 257 | } 258 | return arthasTestService.doTraceE(name); 259 | } 260 | 261 | /** 262 | * 排查异常场景 trace com.wangji92.arthas.plugin.demo.controller.CommonController traceException -n 5 watch 263 | * com.wangji92.arthas.plugin.demo.controller.CommonController traceException '{params,returnObj,throwExp}' -n 5 -x 264 | * 3 265 | * 266 | * @return 267 | */ 268 | @RequestMapping("traceException") 269 | @ResponseBody 270 | public String traceException() { 271 | arthasTestService.traceException(1); 272 | return "ok"; 273 | } 274 | 275 | /** 276 | * 环境变量优先级问题排查 目前只支持获取静态static spring context 获取所有的环境变量 按照优先级排序 ognl -x 3 277 | * '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#allProperties={},#standardServletEnvironment=#propertySourceIterator=#springContext.getEnvironment(),#propertySourceIterator=#standardServletEnvironment.getPropertySources().iterator(),#propertySourceIterator.{#key=#this.getName(),#allProperties.add(" 278 | * "),#allProperties.add("------------------------- name:"+#key),#this.getSource() instanceof java.util.Map 279 | * ?#this.getSource().entrySet().iterator.{#key=#this.key,#allProperties.add(#key+"="+#standardServletEnvironment.getProperty(#key))}:#{}},#allProperties' 280 | * -c e374b99 281 | *

282 | * 选中 custom.name 获取当前的变量的信息 ognl -x 3 283 | * '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")' 284 | * -c e374b99 285 | * 286 | * @return 287 | */ 288 | @RequestMapping("environmentPriority") 289 | @ResponseBody 290 | public String environmentPriority() { 291 | return applicationContext.getEnvironment().getProperty("custom.name"); 292 | } 293 | 294 | /** 295 | * 复杂参数调用 场景 static spring context ognl -x 3 '#user=new 296 | * com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").complexParameterCall(#{"wangji":#user})' 297 | * -c e374b99 298 | *

299 | * watch get spring context 备注 需要调用一次方法 watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch 300 | * '#user=new 301 | * com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").complexParameterCall(#{"wangji":#user})' 302 | *

303 | * tt get spring context ,only first get time index ok tt -w '#user=new 304 | * com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),target.getApplicationContext().getBean("commonController").complexParameterCall(#{"wangji":#user})' 305 | * -x 3 -i 1000 306 | * 307 | * @return 308 | */ 309 | @RequestMapping("complexParameterCall") 310 | @ResponseBody 311 | public String complexParameterCall(@RequestBody Map names) { 312 | if (names == null) { 313 | return "EMPTY"; 314 | } 315 | return names.toString(); 316 | } 317 | 318 | /** 319 | * 1、将光标放置在需要观察的值的字段上面 比如下面的这个获取静态字段的值,无论是静态字段还是实例字段都是可以支持的! watch 320 | * com.wangji92.arthas.plugin.demo.controller.StaticTest * 321 | * '{params,returnObj,throwExp,@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_LONG}' -n 5 -x 3 322 | * '1==1' 323 | *

324 | * watch com.wangji92.arthas.plugin.demo.controller.CommonController * 325 | * '{params,returnObj,throwExp,target.arthasTestService}' -n 5 -x 3 '1==1' 326 | *

327 | * 2、触发一下这个类的某个方法的调用 eg: 比如这里调用这个 http://localhost:8080/watchField 3、即可查看到具体的信息 328 | * 329 | * @return 330 | */ 331 | @RequestMapping("watchField") 332 | @ResponseBody 333 | public String watchField() { 334 | return StaticTest.getInvokeStaticName(); 335 | } 336 | 337 | /** 338 | * 调用非静态的方法才可以在watch 的时候获取非静态的字段 watch com.wangji92.arthas.plugin.demo.controller.StaticTest * 339 | * '{params,returnObj,throwExp,target.filedValue}' -n 5 -x 3 'method.initMethod(),method.constructor!=null || 340 | * !@java.lang.reflect.Modifier@isStatic(method.method.getModifiers())' 341 | * 342 | * @return 343 | */ 344 | @RequestMapping("watchNoStaticField") 345 | @ResponseBody 346 | public String watchNoStaticField() { 347 | return staticTest.getFieldValue(); 348 | } 349 | 350 | @RequestMapping("AnonymousClass") 351 | @ResponseBody 352 | public String anonymousClass() { 353 | Runnable x = new Runnable() { 354 | 355 | @Override 356 | public void run() { 357 | log.info(this.getClass().getName()); 358 | } 359 | }; 360 | x.run(); 361 | return "ok"; 362 | } 363 | 364 | @RequestMapping("innerAnonymousClass") 365 | @ResponseBody 366 | public String innerAnonymousClass() { 367 | OuterClass.InnerClass innerClass = new OuterClass.InnerClass(); 368 | innerClass.anonymousClassRun(); 369 | innerClass.getInnerAge(); 370 | OuterClass.InnerClass.InnerInnerClass innerInnerClass = innerClass.new InnerInnerClass(); 371 | innerInnerClass.getInnerInnerAge(); 372 | innerInnerClass.anonymousInnerInnerClassRun(); 373 | return "ok"; 374 | } 375 | 376 | /** 377 | * vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController 378 | * --express 'instances[0].testEnum(@com.wangji92.arthas.plugin.demo.controller.TestEnum@COMMON_1)' -c 59a6bc53 379 | * 先测试一下枚举 380 | * 381 | * @param testEnum 382 | * @return 383 | */ 384 | @RequestMapping("testEnum") 385 | @ResponseBody 386 | public String testEnum(TestEnum testEnum) { 387 | if (testEnum != null) { 388 | return testEnum.getName(); 389 | } 390 | return "ok"; 391 | } 392 | 393 | /** 394 | * check head 395 | * @return 396 | */ 397 | @RequestMapping("checkHead") 398 | @ResponseBody 399 | public String checkHead() { 400 | 401 | return "ok"; 402 | } 403 | 404 | public Object testParam(MonthDay param){ 405 | return param; 406 | } 407 | 408 | public Object testParam2(Pattern param){ 409 | return param; 410 | } 411 | 412 | public Object testParam3(Date param){ 413 | return param; 414 | } 415 | public Object testParam3(AtomicLong param){ 416 | return param; 417 | } 418 | 419 | 420 | } 421 | --------------------------------------------------------------------------------