为什么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);
}
在日志文件中记录方法进入和退出的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);
}