未调用拦截器方法

Interceptor Method Not Invoked

容器是 Glassfish。我已经在一个简单的 DAO bean class 中实现了一个 @PostConstruct 生命周期事件拦截器方法,但似乎由于某种原因它根本没有拦截我的业务方法。我没有在任何地方手动实例化 bean classes。 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 是生命周期回调 - 而不是拦截器 - 而 @AroundConstruct 是拦截器方法。它们的含义不同,声明也不同。

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

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

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


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

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

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

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

}

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

@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 {
    ...
}