为什么Glassfish 5.1容器不调用单例中注入的CDI拦截器

Why CDI interceptor injected in a singleton is not called by the Glassfish 5.1 container

在日志文件中记录方法进入和退出的CDI拦截器没有被容器为单例class调用?

@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;
    }
}

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

@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() 的方法进入或退出日志。使用调试器,我单步执行代码,容器没有调用拦截器。虽然拦截器对非单例工作正常classes?知道为什么会这样吗?


似乎对具有生命周期方法(即@postConstruct)的拦截器有限制,它们必须属于@Target({TYPE}),所以我创建了一个额外的新拦截器接口和一个新的拦截器,仅用于单例class如下:

@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() 方法没有进入或退出日志?

因为 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);
}