「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
ognl 动态执行线上的代码
能够调用线上的代码,是不是很神奇了。感觉哪段代码执行有问题,但是又没有日志,就可以使用这个方法动态调用目标方法了。
我们下面的案例都是基于这段代码执行,User类:
public class User {
private int id;
private String name;
public User() {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
DeadLockTest类:
public class DeadLockTest {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
private static List<String> names = new ArrayList<>();
private List<String> citys = new ArrayList<>();
public static String add() {
names.add("zhangsan");
names.add("lisi");
names.add("wangwu");
names.add("zhaoliu");
return "123456";
}
public List<String> getCitys() {
DeadLockTest deadLockTest = new DeadLockTest();
deadLockTest.citys.add("北京");
return deadLockTest.citys;
}
public static List<User> addUsers(Integer id, String name) {
List<User> users = new ArrayList<>();
User user = new User(id, name);
users.add(user);
return users;
}
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
try {
System.out.println("thread1 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock2) {
System.out.println("thread1 end");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
try {
System.out.println("thread2 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock1) {
System.out.println("thread2 end");
}
}
}).start();
}
}
1)获取静态函数
> 返回值是字符串
ognl '@全路径类名@静态方法名("参数")'
示例1:在DeadLockTest类中有一个add静态方法,我们来看看通过ognl怎么执行这个静态方法。执行命令
ognl '@com.lxl.jvm.DeadLockTest@add()'
其中,第一个@后面跟的是类的全名称;第二个@跟的是属性或者方法名,如果属性是一个对象,想要获取属性里面的属性或者方法,直接打.属性名/方法名 即可。
运行效果:
我们看到了这个对象的返回值是123456
> 返回值是对象
ognl '@全路径类名@静态方法名("参数")' -x 2
这里我们可以尝试一下替换-x 2 为 -x 1 ;-x 3;
* 案例1:返回对象的地址。不加 -x 或者是-x 1
ognl '@com.lxl.jvm.DeadLockTest@addUsers(1,"zhangsan")'
或
ognl '@com.lxl.jvm.DeadLockTest@addUsers(1,"zhangsan")' -x 1
返回值
* 案例2:返回对象中具体参数的值。加 -x 2
ognl '@com.lxl.jvm.DeadLockTest@addUsers(1,"zhangsan")' -x 2
返回值
* 案例3:返回对象中有其他对象
- 命令:
ognl '@com.lxl.jvm.DeadLockTest@addUsers(1,"zhangsan")' -x 2
执行结果:
-x 2 获取的是对象的值,List返回的是数组信息,数组长度。
- 命令:
ognl '@com.lxl.jvm.DeadLockTest@addUsers(1,"zhangsan")' -x 3
执行结果:
-x 3 打印出对象的值,对象中List列表中的值。
* 案例4:方法A的返回值当做方法B的入参
ognl '#value1=@com.lxl.jvm.DeadLockTest@getCitys(), #value2=@com.lxl.jvm.DeadLockTest@generatorUser(1,"lisi",#value1), {#value1,#value2}' -x 2
> 方法入参是简单类型的列表
ognl '@com.lxl.jvm.DeadLockTest@returnCitys({"beijing","shanghai","guangdong"})'
> 方法入参是一个复杂对象
ognl '#value1=new com.lxl.jvm.User(1,"zhangsan"),#value1.setName("aaa"), #value1.setCitys({"bj", "sh"}), #value2=@com.lxl.jvm.DeadLockTest@addUsers(#value1), #value2' -x 3
> 方法入参是一个map对象
ognl '#value1=new com.lxl.jvm.User(1,"zhangsan"), #value1.setCitys({"bj", "sh"}), #value2=#{"mum":"zhangnvshi","dad":"wangxiansheng"}, #value1.setFamily(#value2), #value1' -x 2
2)获取静态字段
ognl '@全路径类名@静态属性名'
示例:在DeadLockTest类中有一个names静态属性,下面来看看如何获取这个静态属性。执行命令:
ognl '@com.lxl.jvm.DeadLockTest@names'
其中,第一个@后面跟的是类的全名称;第二个@跟的是属性或者方法名,如果属性是一个对象,想要获取属性里面的属性或者方法,直接打.属性名/方法名 即可。
运行效果:
第一次执行获取属性命令,返回的属性是一个空集合;然后执行add方法,往names集合中添加了属性;再次请求names集合,发现有4个属性返回。
3) 获取实例对象
ognl '#value1=new com.lxl.jvm.User(1,"zhangsan"),#value1.setName("aaa"), #value1.setCitys({"bj", "sh"}), {#value1}' -x 2
获取实例对象,使用new关键字,执行结果:
\