0

在日志文件中记录方法进出的CDI拦截器不是被容器为单例类调用了吗?

@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logit {
}

这是拦截器:

@Interceptor
@Logit
public class RecordIntereceptor implements Serializable {
    private static final long serialVersionUID = -2230122751970857900L;
    public RecordIntereceptor() {
    }
    @AroundInvoke
    public Object logEntryExit(InvocationContext ctx)throws Exception{
        String methodName = ctx.getMethod().getName();
        String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
        Logger logger = Logger.getLogger(declaringClass);
        logger.entering("List Service Intereceptor "+declaringClass, methodName);
        Object result = ctx.proceed();
        logger.exiting("List Service Intereceptor "+declaringClass, methodName);
        return result;
    }
}

这是一个使用拦截器的单例类:

@Logit
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DataLoaderSessionBean {
 @PostConstruct
    public void createData() {
        removeStartupData();
        loadUsers();
        loadParts();
    }
...........
...........
}

最后是 beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="annotated">
    <interceptors>
        <class>org.me.jsfproject.intereceptor.RecordIntereceptor</class>
    </interceptors>
</beans>

DataLoaderSessionBean.createData()日志文件中没有方法的方法进入或退出日志。使用调试器,我单步执行代码并且容器没有调用拦截器。虽然拦截器对非单例类工作正常?知道为什么会这样吗?


具有生命周期方法的拦截器似乎存在限制(即@postConstruct它们必须具有),@Target({TYPE})因此我仅为 Singleton 类创建了一个额外的新拦截器接口和一个新拦截器,如下所示:

@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE})
public @interface LifeCycleLogger {
}

@Interceptor
@LifeCycleLogger

public class LifeCycleIntereceptor implements Serializable {
    private static final long serialVersionUID = -2230122753370857601L;
    public LifeCycleIntereceptor() {
    }
   
    @PostConstruct
    public void logPostConstruct(InvocationContext ctx){
        String methodName = ctx.getMethod().getName();
        String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
        Logger logger = Logger.getLogger(declaringClass);
        logger.entering("Life Cycle Intereceptor "+declaringClass, methodName);
        try {
            ctx.proceed();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "LifeCycle Interceptor Post Construct caught an exception: {0}", e.getMessage());
        }
        
        logger.exiting("Life Cycle Intereceptor "+declaringClass, methodName);
    }
}

我将单例更改如下:

@LifeCycleLogger
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DataLoaderSessionBean{

................
    public DataLoaderSessionBean(){
        
    }

    @PostConstruct
    public void createData() {
        ........
        
    }
............
}

但是,该方法没有进入或退出日志createData()吗?

4

1 回答 1

0

因为createData()它的生命周期方法DataLoaderSessionBean不会被@AroundInvoke注释捕获。

要在拦截器中声明一个捕获@PostConstruct生命周期调用的方法,您必须使用相同的注释对其进行注释:

@PostConstruct
public void logPostConstruct(InvocationContext ctx) throws Exception{
    String methodName = ctx.getMethod().getName();
    String declaringClass= ctx.getMethod().getDeclaringClass().getCanonicalName();
    Logger logger = Logger.getLogger(declaringClass);
    logger.entering("List Service Intereceptor "+declaringClass, methodName);
    ctx.proceed();
    logger.exiting("List Service Intereceptor "+declaringClass, methodName);
}
于 2021-01-26T20:59:40.727 回答