gpt4 book ai didi

java - CDI 日志拦截器在 @PostConstruct 中不起作用

转载 作者:行者123 更新时间:2023-12-02 11:34:47 29 4
gpt4 key购买 nike

我想为我当前的堆栈创建一个 LoggingInterceptor:

  • Tomcat 8.5.24
  • Weld 2.4.5-最终
  • JSF 2.3.3

这是标记要拦截的方法或类型的注释。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.enterprise.util.Nonbinding;
import javax.interceptor.InterceptorBinding;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
public @interface Logging {

@Nonbinding
Level value() default Level.TRACE;

public enum Level {
NONE, ALL, TRACE, DEBUG, INFO, WARN, ERROR;
}
}

这是拦截器逻辑:

import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

@Interceptor
@Logging
public class LoggingInterceptor {

@AroundInvoke
public Object interceptBusiness(final InvocationContext invocationContext) throws Exception {
Logger log = LoggerFactory.getLogger(invocationContext.getMethod().getDeclaringClass().getName());
log.trace("LOG start of method");
Object result = invocationContext.proceed();
log.trace("LOG end of method");
return result;
}
}

简化的 Bean:

import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.inject.Inject;
import javax.faces.view.ViewScoped;

@Named
@ViewScoped
@Logging(Level.DEBUG)
public class ListController implements Serializable {

private static final long serialVersionUID = 1L;

@Inject
EntityService entityService;

private List<Entity> entityList;

public List<Entity> getEntityList() {
return this.entityList;
}

public void setEntityList(final List<Entity> entityList) {
this.entityList= entityList;
}

public String doSomething(){
List<Entity> entityList = new ArrayList<>();
this.setEntityList(entityList);
return "";
}

@PostConstruct
public void setUp() {
this.setEntityList(this.entityService.findAll());
}
}

如果在运行时调用,我的业务方法拦截器就像一个魅力,例如在 jsf View 中按下一个按钮时调用 doSomething()方法。两者都是doSomething()setEntityList()方法将被记录。

但是在 @PostConstruct 中调用的所有方法方法根本没有记录。这意味着setEntityList()@PostConstruct 中调用时不会记录方法方法。

我能做些什么来获取从 @PostConstruct 调用的方法吗?要记录的方法。我希望得到一些帮助。提前致谢。

根据 HRgiger 的回答进行更新:

我还尝试了 @PostConstruct方法在我的拦截器逻辑中,但使用此方法我只能记录 @PostConstruct 的调用本身,而是 @PostConstruct 中调用的方法方法未记录,这仍然是我的主要问题。

@PostConstruct
public void interceptLifecycle(final InvocationContext invocationContext) throws Exception {
Logger log = LoggerFactory.getLogger(invocationContext.getTarget().getClass().getSimpleName());

log.info("LOG start of POSTCONSTRUCT");
invocationContext.proceed();
log.info("LOG end of POSTCONSTRUCT");
}

最佳答案

这是预期的行为。只有从 bean 外部对 bean 方法的调用才会被拦截,而不会从 bean 内部对其自身方法的调用被拦截。

来自weld/CDI 1.0.0 specification

A business method interceptor applies to invocations of methods of the bean by clients of the bean.

A lifecycle callback interceptor applies to invocations of lifecycle callbacks by the container.

这意味着您所描述的行为完全是有意为之。 @AroundInvoke带注释的业务方法拦截器仅拦截从 bean 外部对 bean 调用的“正常”方法。这也意味着如果您的 bean 有方法 methodA()methodB() ,和methodA来电 methodB ,当 methodA仅从外部调用methodA被记录,而不是 methodB 的调用.

假设您有以下内容:

@Named
@ViewScoped
@Logging(Level.DEBUG)
public class SimpleBean {

public void methodA() {
methodB();
}

public void methodB() {
// do something
}
}

在其他一些类中,您注入(inject)这个 bean,实际上是向该 bean 注入(inject)代理:

@Inject
private SimpleBean simpleBeanProxy;

当您调用simpleBeanProxy.methodA();时,即methodA调用被拦截,但 methodB 的调用未被拦截从内部methodA 。当您调用simpleBeanProxy.methodB();时,调用methodB被拦截。

生命周期回调也会发生类似的情况,拦截器拦截从外部(容器)对生命周期方法的调用,但不会拦截从该 postconstruct 方法内调用的同一 bean 上的任何方法。

这都是因为这些拦截器所做的拦截是由代理处理的。如果“从外部”调用 bean 上的方法,则实际上是在代理上调用该方法,并且代理确保在对实际 bean 对象执行实际方法调用之前调用任何已注册的拦截器。

但是,一旦您进入实际 bean 的“内部”方法并且从同一 bean 调用任何其他方法,您就不会使用代理(而是直接在同一对象上调用方法),因此不会发生拦截.

关于java - CDI 日志拦截器在 @PostConstruct 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49025452/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com