为什么@Inject在同一个@Interceptor上调用了3次?

时间:2016-01-08 09:58:11

标签: java-ee cdi interceptor

我试图了解拦截器是如何工作的,我对生命周期有疑问。

我的CacheableInterceptor有一个@Inject注释,用于获取记录器。

在同一个bean实例上调用Logger @Producer方法(类LoggerFactoryImpl)3次(参见日志跟踪)。

这意味着它为每个intercept *方法调用一次(我试图删除interceptPreDestoy方法,并且生成器被调用两次)。

我无法在拦截器规范中找到这个东西。你能解释一下为什么吗?我在@Producer方法中做错了吗?

谢谢

  

拦截器生命周期

     

拦截器类与其关联目标具有相同的生命周期   类。创建目标类实例时,拦截器类   还为每个声明的拦截器类创建了一个实例   目标类。也就是说,如果目标类声明多个   拦截器类,每个类的实例都是在创建时创建的   创建目标类实例。目标类实例和所有   拦截器类实例在任何之前完全实例化   调用@PostConstruct回调,以及任何@PreDestroy回调   在目标类和拦截器类实例之前调用   被毁了。

日志文件

[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

可缓存注释的代码

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

}

CacheableInterceptor拦截器的代码

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

}

MyController类的代码

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

}

LoggerFactoryImpl类的代码

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 个答案:

答案 0 :(得分:0)

与CDI一起使用时的拦截器是依赖范围的bean。这意味着为每次调用创建了一个新的拦截器实例。此外,您的日志生成器也是依赖的,因此您也可以为每个日志生成器获取一个新的记录器。