【问题标题】:Interceptor Method Not Invoked未调用拦截器方法
【发布时间】:2015-08-14 09:55:02
【问题描述】:

容器是 Glassfish。我在一个简单的 DAO bean 类中实现了一个@PostConstruct 生命周期事件拦截器方法,但似乎由于某种原因它根本没有拦截我的业务方法。我不会在任何地方手动实例化 bean 类。 beans.xml 发现模式是全部,由于我没有注释 DefaultUserDao bean,所以它获得了默认范围。

public class DefaultUserDao implements UserDao {

    private String userName;
    private String password;
    Scanner users = null;
    String[] userNamePasswordPairs = null;

    public DefaultUserDao() {
        try {
            users = new Scanner(Paths.get("/home/NetBeansProjects/EJBInAction/web/users"));
        } 

        catch (IOException ex) {
            Logger.getLogger(DefaultUserDao.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /*The interceptor for this method is defined right below, that 
      interceptor method is not called at all. If I insert a
      System.out.println(userNamePasswordPairs) after the split()
      method below, it prints [userName:password] pair twice and there
      is only one line in the text file from which the pair was read  in the
      form like this admin:admin. Notice that I also insert a System.out.println()
      method in the interceptor method but if I remove the print()
      method from this init() method, I don't see it prints anything
      */
    @PostConstruct
    public void init() {
        while (users.hasNextLine()) {
            String line = users.nextLine();
            userNamePasswordPairs = line.split(":");
            //If I uncomment this, I see it prints [admin:admin] pair
            //twice, but when I comment it out, I don't see it prints  anything
           //System.out.println(Arrays.toString(userNamePasswordPairs));
            userName = userNamePasswordPairs[0];
            password = userNamePasswordPairs[1];
        }
    }

    @AroundConstruct
    private void printUser(InvocationContext ic) {
        //If this interceptor was invoked, it should print at least "Interceptor invoked: "
        //But it does not print this.
        System.out.println("Interceptor invoked: " + Arrays.toString(userNamePasswordPairs));
        try {
            ic.proceed();
        } 

        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

一个收集用户名和密码的简单 JSF 页面

@Named
@RequestScoped
public class LoginBean {

    private String userName;
    private String password;

    @Inject
    private UserDao userDao;

    public LoginBean() {
    }

    public LoginBean(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public String validateUser() {

        if (userDao.getUserName().equals(userName) && userDao.getPassword().equals(password)) {
        }
    
        else {
            userName = "Error";
            password = "Error";
        }
        return "confirmation.xhtml";
    }

    //getter and setter for userName and password

}

【问题讨论】:

  • @PostContruct 不适用于 pojo。仅在 jsf、cdi、ejb 等托管 bean 上。
  • 它是一个豆子。我可以将它注入LoginBean
  • 怎么样?通过xml文件?不是通过注释
  • 是的。 beans.xml 发现模式是全部,由于我没有注释DefaultUserDao,所以它获取默认范围
  • 请在代码前将所有这些添加到问题中

标签: jsf glassfish cdi interceptor


【解决方案1】:

首先,注意@PostContruct 是一个生命周期回调——而不是一个拦截器——而@AroundConstruct 是一个拦截器方法。它们有不同的含义,声明也不同。

另请注意,调用顺序通常如下:

  1. 构造函数拦截器被调用
  2. 构造函数通过拦截器中的proceed()方法调用。
  3. 执行注入(基本上@Inject字段/设置器已设置)
  4. @PostConstruct 生命周期回调被调用。

关于@PostConstruct 生命周期回调,您正确声明它。而且它似乎被调用了,因为它打印了一些文本。


关于拦截器,缺少以下内容:

  • 您的拦截器必须在单独的类中声明,而不是在 bean 中。
  • 您的拦截器类必须在META-INF/beans.xml 文件中的<interceptors> 元素下声明必须使用javax.annotations.Priority 注释指定优先级值。后一个选项使您的拦截器应用程序范围内,基本上:它将适用于整个应用程序,而不仅仅是包含 META-INF/beans.xml 的 jar。首先,我建议您在 META-INF/beans.xml 中声明它。
  • 你的拦截器必须用@Interceptor (javax.interceptor.Interceptor)注解
  • 您必须在拦截器上声明一个拦截器绑定,并声明要使用它拦截的 bean/方法。

总而言之,你必须为你的拦截器创建一个拦截器绑定:

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Greet {

}

然后你必须为你的拦截器创建一个类,使用拦截器绑定:

@Greet
@Interceptor
public class GreetInterceptor {

    @AroundConstruct
    public void aroundConstruct(InvocationContext ic) throws Exception {
        System.out.println("Hello!!");
        ic.proceed();
    }
}

然后在你的META-INF/beans.xml中声明它:

<interceptors>
    <class>com.sandbox.GreetInterceptor</class>
</interceptors>

最后,用拦截器绑定注解你要拦截调用的bean:

@Greet
public class DefaultUserDao implements UserDao {
    ...
}

【讨论】:

    猜你喜欢
    • 2012-08-18
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    • 2012-04-01
    相关资源
    最近更新 更多