1
votes

I'm trying to understand how interceptors work, and I have a question about life cycle.

My CacheableInterceptor has an @Inject annotation, to obtain a logger.

The Logger @Producer method (class LoggerFactoryImpl) is called 3 times (see in the log trace) on the same bean instance.

This means it is called once for every intercept* method (I tried to remove the interceptPreDestoy method, and the producer is called twice).

I couldn't find this thing in the interceptor specification. Can you explain me why? Have I done an error in the @Producer method?

Thank you

Interceptor Lifecycle

Interceptor classes have the same lifecycle as their associated target class. When a target class instance is created, an interceptor class instance is also created for each declared interceptor class in the target class. That is, if the target class declares multiple interceptor classes, an instance of each class is created when the target class instance is created. The target class instance and all interceptor class instances are fully instantiated before any @PostConstruct callbacks are invoked, and any @PreDestroy callbacks are invoked before the target class and interceptor class instances are destroyed.

LOG FILE

[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger calling @Produces for injection point: [BackedAnnotatedField] @Inject protected it.tecla.utils.cache.CacheableInterceptor.logger, real bean: org.jboss.weld.bean.InterceptorImpl@2,077,555,267
[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger logger name from bean class
[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger name: it.tecla.utils.cache.CacheableInterceptor
[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 getLogger obtaining logger with name: it.tecla.utils.cache.CacheableInterceptor
[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger calling @Produces for injection point: [BackedAnnotatedField] @Inject protected it.tecla.utils.cache.CacheableInterceptor.logger, real bean: org.jboss.weld.bean.InterceptorImpl@2,077,555,267
[1/8/16 10:44:40:379 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger logger name from bean class
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger name: it.tecla.utils.cache.CacheableInterceptor
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 getLogger obtaining logger with name: it.tecla.utils.cache.CacheableInterceptor
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger calling @Produces for injection point: [BackedAnnotatedField] @Inject protected it.tecla.utils.cache.CacheableInterceptor.logger, real bean: org.jboss.weld.bean.InterceptorImpl@2,077,555,267
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger logger name from bean class
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 produceLogger name: it.tecla.utils.cache.CacheableInterceptor
[1/8/16 10:44:40:380 CET] 00000242 id=         it.tecla.utils.logging.impl.LoggerFactoryImpl                1 getLogger obtaining logger with name: it.tecla.utils.cache.CacheableInterceptor

Code for Cacheable annotation

@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Cacheable {

}

code for CacheableInterceptor interceptor

@Interceptor
@Cacheable
public class CacheableInterceptor {

    @Inject
    protected Logger logger;

    @PostConstruct
    protected void interceptPostConstruct(InvocationContext invocationContext) {
        System.out.println("post construct");
    }

    @AroundInvoke
    protected Object interceptAroundInvoke(InvocationContext invocationContext) throws Exception {

        System.out.println("intercepted");

        return invocationContext.proceed();

    }

    @PreDestroy
    protected void interceptPreDestroy(InvocationContext invocationContext) {
        System.out.println("pre destroy");
    }

}

Code for MyController class

@Cacheable
public class MyController {

    @Inject
    protected Logger logger;

    public String add(@NotNull String a, @NotNull String b) {

        logger.logp(Level.FINE, logger.getName(), "add", "a={0}", a);
        logger.logp(Level.FINE, logger.getName(), "add", "b={0}", b);

        BigDecimal bdA = new BigDecimal(a);
        BigDecimal bdB = new BigDecimal(b);
        BigDecimal result = bdA.add(bdB);

        return result.toString();
    }

}

Code for LoggerFactoryImpl class

public class LoggerFactoryImpl implements LoggerFactory {

    protected Logger logger = Logger.getLogger(this.getClass().getName());

    @Produces
    protected Logger produceLogger(InjectionPoint injectionPoint) {

        logger.logp(Level.FINE, logger.getName(), "produceLogger", "calling @Produces for injection point: {0}, real bean: {1}@{2}", new Object[] { injectionPoint, injectionPoint.getBean().getClass().getName(), System.identityHashCode(injectionPoint.getBean()) });

        LoggerConfig loggerConfig = injectionPoint.getAnnotated().getAnnotation(LoggerConfig.class);

        String name = null;
        if (loggerConfig != null) {
            logger.logp(Level.FINE, logger.getName(), "produceLogger", "logger name from annotation @LoggerConfig");
            name = loggerConfig.name();
        }

        if (name == null) {
            logger.logp(Level.FINE, logger.getName(), "produceLogger", "logger name from bean class");
            name = injectionPoint.getBean().getBeanClass().getName();
        }

        logger.logp(Level.FINE, logger.getName(), "produceLogger", "name: {0}", name);

        return this.getLogger(name);
    }

    @Override
    public Logger getLogger(String name) {

        logger.logp(Level.FINE, logger.getName(), "getLogger", "obtaining logger with name: {0}", name);

        Logger logger = Logger.getLogger(name);
        return logger;
    }

}
1
Check if this happens if MyController has scope @RequestScoped or any other than @Dependent.Geinmachi
Yes, it happens with @RequestScopedyelo3

1 Answers

0
votes

Interceptors when used with CDI are dependent scoped beans. This means a new instance of the interceptor is created for each invocation. In addition, your log producer is dependent as well, so you'll get a new logger for each one as well.