Java 从默认接口方法进行日志记录
向所有Java大师致敬 由于Java8,我们可以在接口中使用默认实现(耶!)。 然而,当您想从默认方法登录时,问题就出现了Java 从默认接口方法进行日志记录,java,interface,java-8,Java,Interface,Java 8,向所有Java大师致敬 由于Java8,我们可以在接口中使用默认实现(耶!)。 然而,当您想从默认方法登录时,问题就出现了 我觉得每次我想用默认方法记录某些内容时调用.getLogger()是不明智的 是的,可以在接口中定义静态变量-但这对于接口来说不是一个好的做法+它公开了记录器(必须是公共的) 我目前的解决方案是: interface WithTimeout<Action> { default void onTimeout(Action timedOutAction)
我觉得每次我想用默认方法记录某些内容时调用.getLogger()是不明智的 是的,可以在接口中定义静态变量-但这对于接口来说不是一个好的做法+它公开了记录器(必须是公共的) 我目前的解决方案是:
interface WithTimeout<Action> {
default void onTimeout(Action timedOutAction) {
LogHolder.LOGGER.info("Action {} time out ignored.", timedOutAction);
}
static final class LogHolder {
private static final Logger LOGGER = getLogger(WithTimeout.class);
}
}
接口超时{
默认void onTimeout(Action timedOutAction){
LogHolder.LOGGER.info(“忽略动作{}超时。”,timedOutAction);
}
静态最终类日志持有者{
私有静态最终记录器=getLogger(WithTimeout.class);
}
}
LogHolder对每个人都是可见的,这没有任何意义,因为它不提供任何方法,它应该是接口的内部
你们有谁知道更好的解决方案吗?:)
编辑:我使用Logback支持的SLF4J如果您不想将类
日志持有者
公开,请不要将其作为接口的成员类。将其设为成员类没有任何好处,您甚至不保存键入,因为您必须使用holder类的名称限定字段访问,无论它是成员类还是同一包中的类:
public interface WithTimeout<Action> {
default void onTimeout(Action timedOutAction) {
LogHolder.LOGGER.info("Action {} time out ignored.", timedOutAction);
}
}
final class LogHolder { // not public
static final Logger LOGGER = getLogger(WithTimeout.class);
}
带超时的公共接口{
默认void onTimeout(Action timedOutAction){
LogHolder.LOGGER.info(“忽略动作{}超时。”,timedOutAction);
}
}
最终类日志持有者{//非公共
静态最终记录器=getLogger(WithTimeout.class);
}
给你
记录器对于接口是私有的。除了这个接口及其默认方法之外,没有人可以访问Test2内部的任何内容。并且没有任何东西可以扩展Test2类
没有人建议你这么做。。。但它是有效的!
这是一种访问主界面类记录器的好方法,也可能是一种做其他事情的聪明方法,而不是完全疯狂
这实际上与OP问题中的LogHolder相同,只是Test2类也是所有私有方法和构造函数私有的,并且类没有标记为static
作为额外的好处,它保持状态,静态和每个实例。
(请不要在真正的程序中这样做!)
公共类测试运行程序{
公共静态void main(字符串[]args){
测试=新测试(){
};
test.sayHello(“简”);
System.out.println(“再次”);
test.sayHello(“Bob”);
}
}
公共接口测试{
默认的void sayHello(字符串名称){
记录器日志=Test2.log;
Test2 ref=Test2.getMine.apply(这个);
int times=ref.getTimes();
for(int i=0;i{
返回lookup.computeIfAbsent(obj,(it)->newtest2());
};
私有int调用=0;
私有测试2(){
}
私有void集合调用(int调用){
this.calls=调用;
}
private int getCalls(){return calls;}
private int getTimes(){return++calls;}
}
}“我觉得每次我想用默认方法记录某些内容时调用.getLogger()是不明智的。”您是否执行了性能测量以支持这种感觉?如果没有,如果不需要,请不要优化性能。公开一个公共日志持有者
类或一个公共日志记录器
在我看来没有多大区别。我看不出有任何理由这么做!我不明白如果有多个不同的类正在使用此记录器,这会有什么帮助。@Ray在我关闭此选项之前,我读了一些关于.getLogger的内容。每次调用.getLogger都被认为是反模式的:我没有对性能影响进行任何测量,但我希望以其创建者推荐的方式使用该库。是的,但这并不限制同一程序包的其他成员访问记录器本身。也许我太纯粹了。体面的程序员几乎不会使用不同类别的记录器,我想也不会让它通过代码审查。因为没有办法让接口的私有成员,所以没有办法。但是,即使有一种方法可以使LogHolder
成为private
类,也不能阻止其他类调用getLogger(WithTimeout.class)
自己来获取相同的记录器实例,因此不值得付出努力。将类移出接口
是很有用的,以避免用实现工件污染API,但是记录器不应该与安全相关。您可以更进一步,将记录器设置为私有的。然后,即使有人可以从包范围访问LogHolder,他们也无法访问该日志,因为它是私有的。但是您的接口可以使用它。@Saint Hill:这只适用于LogHolder
是嵌套类的情况,但是,它将隐式地public
,这就是这个问题的全部内容。您只能有一个private
LOGGER
字段或一个非public
LogHolder
类。@Holger足够正确。但是该类可以公开显示,并且不允许任何其他人使用它。任何人都能看到其中蕴含着某种神秘。见下面我的答案。现在告诉我这不符合OP的要求:)我不建议这样做,但作为一个LogHolder类,它非常有用。我不是苏尔
public class TestRunner {
public static void main(String[] args) {
Test test = new Test() {
};
test.sayHello("Jane");
System.out.println("Again");
test.sayHello("Bob");
}
}
public interface Test {
default void sayHello(String name) {
Logger log = Test2.log;
Test2 ref = Test2.getMine.apply(this);
int times = ref.getTimes();
for (int i = 0; i < times; i++) {
System.out.println(i + ": Hello " + name);
}
log.info("just said hello {} times :)",times);
}
final class Test2 {
private static final Logger log = LoggerFactory.getLogger(Test.class);
private static final Map lookup = new WeakHashMap();
private static final Function getMine = (obj) -> {
return lookup.computeIfAbsent(obj, (it) -> new Test2());
};
private int calls = 0;
private Test2() {
}
private void setCalls(int calls) {
this.calls = calls;
}
private int getCalls() {return calls;}
private int getTimes() {return ++calls;}
}
}