我想为当前的Stack创建一个LoggingInterceptor:
这是用于标记拦截方法或类型的注释。
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()
和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");
}
答案 0 :(得分:1)
这是预期的行为。只有从bean外部调用bean的方法才能被拦截,而不是从bean内部调用它自己的方法。
来自weld/CDI 1.0.0 specification
业务方法拦截器适用于bean的客户端对bean的方法的调用。
生命周期回调拦截器适用于容器对生命周期回调的调用。
这意味着您描述的行为是完全有意的。 @AroundInvoke
- 带注释的业务方法拦截器只拦截&#34; normal&#34;从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上的方法被调用&#34;来自外部&#34;,它实际上是在代理上调用的,代理确保在对实际bean对象执行实际方法调用之前调用任何已注册的拦截器。
但是,一旦你进入&#34;内部&#34;在实际bean上的一个方法,你从同一个bean调用任何其他方法,你不使用代理(但直接在同一个对象上调用方法),因此不会发生拦截。
答案 1 :(得分:0)
我之前没有尝试,但我认为你需要这样的问题question或this:
@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);
}
}