select * from user
where id in (1001,1001, 1002, 1003, 1004, 1005, 1006, 1007)
and name in(
select name from whitelist
where name in('a','b','c','d','e','f','g','h','i','j','k','l','m')
)
缩略下印如下:
select * from user
where id in (1001,1001, 1002, 1003, 1004,...)
and name in(
select name from whitelist
where name in('a','b','c','d','e',...)
)
@Bean
@Primary
public DataSource spyDataSource(@Autowired DataSource dataSource) {
// wrap a datasource using P6SpyDataSource
return new P6DataSource(dataSource);
}
log4jdbc
public DataSource spyDataSource(DataSource dataSource) {
// wrap the provided dataSource
return new DataSource() {
@Override
public Connection getConnection() throws SQLException {
// wrap the connection with log4jdbc
return new ConnectionSpy(dataSource.getConnection());
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// wrap the connection with log4jdbc
return new ConnectionSpy(dataSource.getConnection(username, password));
}
//...
};
}
public final enum class AdDataSources private constructor(forTest: AdDataSources? = COMPILED_CODE, usingNewZk: kotlin.Boolean = COMPILED_CODE, bizDef: BizDef = COMPILED_CODE) : kotlin.Enum<AdDataSources>, DataSourceConfig {
adFansTopProfileDashboardTest,
adFansTopProfileDashboard,
adChargeTest,
adCharge,
adChargeReadOnly,
adDspReadOnlyTest,
adDspReadOnly,
//more datasource
public companion object {
private final val map: Map<kotlin.String, AdDataSources> /* compiled code */
public final fun fromBizName(bizName: kotlin.String):AdDataSources? { /* compiled code */ }
}
private final val bizDef: BizDef /* compiled code */
private final val forTest: AdDataSources? /* compiled code */
private final val usingNewZk: kotlin.Boolean /* compiled code */
public open fun bizDef(): BizDef { /* compiled code */ }
public open fun bizName(): kotlin.String { /* compiled code */ }
public open fun usingNewZk(): kotlin.Boolean { /* compiled code */ }
}
Note that starting with Java 9, there is the Launcher-Agent-Class manifest attribute for jar files that can specify the class of a Java Agent to start before the class specified with the Main-Class is launched. That way, you can easily have your Agent collaborating with your application code in your JVM, without the need for any additional command line options. The Agent can be as simple as having an agentmain method in your main class storing the Instrumentation reference in a static variable.
However, recent JVMs forbid self-attaching unless -Djdk.attach.allowAttachSelf=true has been specified at startup, but I suppose, taking additional steps at startup time, is precisely what you don’t want to do. One way to circumvent this, is to use another process. All this process has to to, is to attach to your original process and tell the JVM to start the Agent. Then, it may already terminate and everything else works the same way as before the introduction of this restriction.
字节码工具对比
使用bytebuddy修改字节码
在实现代码之前,我们回过头来再看一下快手的数据源生成:
new ListenableDataSource<>(bizName, new HikariDataSource(config), ds -> i.toString());
Getting hands on an Instrumentation instance when the JVM has not been started with Agents is trickier. It must support launching Agents after startup in general, e.g. via the Attach API. demonstrates at its end such a self-attach to get hands on the Instrumentation. When you have the necessary manifest attribute in your application jar file, you could even use that as agent jar and omit the creation of a temporary stub file.
As mentioned in , Byte-Buddy has already implemented those necessary steps and the stripped-down Byte-Buddy-Agent contains that logic only, so you can use it to build your own logic atop it.