繁体   English   中英

CDI日志记录拦截器在@PostConstruct中不起作用

[英]CDI Logging Interceptor not working in @PostConstruct

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

  • 的Tomcat 8.5.24
  • 焊接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视图中按下按钮调用doSomething()方法时doSomething()调用,则我的业务方法拦截器的作用就像一个超级按钮。 doSomething()setEntityList()方法都将被记录。

但是@PostConstruct方法中调用的所有方法都不会记录。 这意味着在@PostConstruct方法中调用setEntityList()方法时不会对其进行记录。

我可以做些什么来获取从@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内部对其自身方法的调用。

焊接/ CDI 1.0.0规范开始

业务方法拦截器适用于Bean的客户对Bean的方法的调用。

生命周期回调拦截器适用于容器对生命周期回调的调用。

这意味着您描述的行为是完全有意的。 @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
    }
}

在其他一些类中,您注入了这个bean,实际上是在注入一个代理到bean:

@Inject
private SimpleBean simpleBeanProxy;

当您调用simpleBeanProxy.methodA(); ,那methodA调用被截获的,但不是调用methodB从内部methodA 当您调用simpleBeanProxy.methodB(); ,那调用methodB被截获。

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

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

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

我以前没有尝试过,但是我认为您需要在这个问题这个 问题中问类似的内容:

@PostConstruct
    public void postConstruct(InvocationContext ctx) {
        try {
            System.out.println(PREFIX + " postConstruct");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    @PreDestroy
    public void preDestroy(InvocationContext ctx) {
        try {
            System.out.println(PREFIX + " predestroy");
            System.out.println(PREFIX + "ctx.preceed=" + ctx.proceed());
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM