我有一个带有大型Spring上下文的应用程序,该应用程序加载了许多开发人员编写的大量bean。
一些bean可能会对它们的初始化代码进行一些重要的处理,这可能需要很长时间。
我正在寻找一种简单的方法来获取每个bean的加载时间。
由于该软件正在大量客户的计算机上运行,因此我需要一种在日志中轻松查找瓶颈bean的方法。
如果我可以注册“ Before loading bean”之前和之后的事件,那将是很好的。
因此,如果我可以有问题地获取此数据,则可以编写如下内容:
if (beanLoadingTime > 2 seconds)
print bean details and loading time to log file
Run Code Online (Sandbox Code Playgroud)
因此,仅启用日志记录或配置文件还不够。
小智 7
不知道我的解决方案是否会对您有所帮助,但这就是我所做的,因为我需要类似的东西。
首先,我们需要记录两件事,实例化时间和初始化时间。首先,我只为包“org.springframework.beans.factory”启用日志记录,使用 %d{mm:ss,SSS} %m%n 作为模式(仅限时间和消息)。Spring 会记录以下消息:Creating instance of bean... 和 Finished creation instance of bean... 对于第二件事,我按照本答案中的建议创建了 LoggerBeanPostProcessor 。代码是:
public class LoggerBeanPostProcessor implements BeanPostProcessor, Ordered {
protected Log logger = LogFactory.getLog("org.springframework.beans.factory.LoggerBeanPostProcessor");
private Map<String, Long> start;
private Map<String, Long> end;
public LoggerBeanPostProcessor() {
start = new HashMap<>();
end = new HashMap<>();
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
start.put(beanName, System.currentTimeMillis());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
end.put(beanName, System.currentTimeMillis());
logger.debug("Init time for " + beanName + ": " + initializationTime(beanName));
return bean;
}
@Override
public int getOrder() {
return Integer.MAX_VALUE;
}
// this method returns initialization time of the bean.
public long initializationTime(String beanName) {
return end.get(beanName) - start.get(beanName);
}
}
Run Code Online (Sandbox Code Playgroud)
我在 log4j 配置中使用文件附加程序。然后我编写了一个简单的代码来解析该信息并获取每件事的毫秒数并将它们相加:
public static void main(String[] argumentos) throws Exception{
File file = new File("C:\\app\\daily.log");
List<String> lines = FileUtils.readLines(file);
Map<String,Long> start = new HashMap();
Map<String,Long> end = new HashMap();
Map<String,Long> init = new HashMap();
List<String> beans = new ArrayList();
int max = 0;
for(String line : lines) {
String time = StringUtils.substring(line, 0, 9);
String msg = StringUtils.substring(line, 10);
if(msg.startsWith("Creating instance")) {
int fi = StringUtils.indexOf(msg, '\'') + 1;
int li = StringUtils.lastIndexOf(msg, '\'');
String bean = StringUtils.substring(msg, fi, li);
if(start.containsKey(bean)) {
continue;
}
start.put(bean, parseTime(time));
beans.add(bean);
max = Math.max(max, bean.length());
} else if(msg.startsWith("Finished creating")) {
int fi = StringUtils.indexOf(msg, '\'') + 1;
int li = StringUtils.lastIndexOf(msg, '\'');
String bean = StringUtils.substring(msg, fi, li);
if(end.containsKey(bean)) {
continue;
}
end.put(bean, parseTime(time));
} else if(msg.startsWith("Init time for")) {
int li = StringUtils.lastIndexOf(msg, ':');
String bean = StringUtils.substring(msg, 14, li);
if(init.containsKey(bean)) {
continue;
}
init.put(bean, Long.parseLong(StringUtils.substring(msg, li+2)));
}
}
for(String bean : beans) {
long s = start.get(bean);
long e = end.get(bean);
long i = init.containsKey(bean) ? init.get(bean) : -1;
System.out.println(StringUtils.leftPad(bean, max) + ": " + StringUtils.leftPad(Long.toString((e-s)+i), 6, ' '));
}
}
Run Code Online (Sandbox Code Playgroud)
结果是这样:
splashScreen: 172
org.springframework.aop.config.internalAutoProxyCreator: 31
loggerBeanPostProcessor: 1137
appContext: 1122
Run Code Online (Sandbox Code Playgroud)
希望这对你的帮助和对我的帮助一样多。