2013-05-05 19 views
8

Tôi có một bộ lọc nơi tôi dinamically lớp servlet mapping:Tiêm một EJB thành một động ánh xạ servlet

@Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
     servletContext = filterConfig.getServletContext(); 

     File directory = getConventionDirectory(); 
     FileSystemInspector fileInspector = new FileSystemInspector(); 
     Set<ActionInfoData> actions = fileInspector.getActions(directory); 

     for (ActionInfoData action : actions) { 
      servletContext 
       .addServlet(action.getServletName(), action.getClassName()) 
       .addMapping(action.getServletMapping()); 
     } 

    } 

Sau đó, khi tôi truy cập vào một định lập bản đồ EJB không tiêm.

@EJB 
    private I18nManager i18nManager; 

    @Override 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException { 
     I18nManager i18n = i18nManager; //null 
    } 

Nếu tôi tự tạo ra một ánh xạ trong web.xml các EJB cho đang làm việc trong servlet đó. Nó làm cho tôi tự hỏi nếu thực tế tôi đang đăng ký các servlet trong thời gian chạy container không xem xét những servlets như quản lý.

Nếu trường hợp đó là cách thích hợp để tiêm các EJB vào các servlet của tôi mà không thay đổi cách chúng được đăng ký thực tế qua bộ lọc?

Có phải thông qua JNDI cách duy nhất để tiêm EJB của tôi không?

EDIT 1: Tôi đã cố gắng thực hiện một lớp ServletContextListener theo đề nghị của "Sẽ" sử dụng đoạn mã sau trong web.xml:

<listener> 
     <listener-class>com.megafone.web.filter.convention.InitServlet</listener-class> 
    </listener> 

Và phần liên quan của việc thực hiện:

... 

@Override 
    public void contextInitialized(ServletContextEvent sce) { 
     ServletContext servletContext = sce.getServletContext(); 

     FileSystemInspector fileInspector = new FileSystemInspector(); 
     Set<ActionInfoData> actions = fileInspector.getActions(getConventionDirectory()); 

     for (ActionInfoData action : actions) { 
      servletContext 
       .addServlet(action.getServletName(), action.getClassName()) 
       .addMapping(action.getServletMapping()); 
     } 
    } 

... 

Thật không may nó không làm cho các container tiêm EJBs và con trỏ null vẫn còn. Tôi hiện đang thực hiện tra cứu JNDI kiểu tùy chỉnh an toàn cho dịch vụ. Rõ ràng đây là tốn kém hơn nhiều so với việc sử dụng tiêm đúng cách (đúng với tôi nếu tôi sai, đã không thực hiện thí nghiệm nào về hiệu suất).

Sử dụng:
Java EE 6
JBoss AS 7.1

+0

Câu hỏi rất hay! – acdcjunior

Trả lời

3

Vấn đề dường như liên quan đến this reported bug mà cho đến nay vẫn chưa được giải quyết. Độ phân giải tài nguyên hoạt động tốt đối với các Managed Beans như được định nghĩa bởi đặc tả JSF, nhưng không hoạt động đối với các Managed Beans CDI. Đơn giản chỉ cần chú thích lớp servlet động của bạn với @javax.faces.bean.ManagedBean nên giải quyết vấn đề (có, một giải pháp của nó khá xấu xí):

@ManagedBean 
public class DynServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    @EJB 
    private LoginService loginService; 

    public DynServlet() { 
     super(); 
    } 

    @Override 
    protected void doGet(HttpServletRequest request, 
      HttpServletResponse response) throws ServletException, IOException { 
     response.getOutputStream().println(
       "Request made to: " + getClass().getSimpleName()); 
     response.getOutputStream().println("Login Service: " + loginService); 

     return; 
    } 
} 

@WebListener 
public class DynamicServletLoadListener implements ServletContextListener { 

    public DynamicServletLoadListener() { 
     super(); 
    } 

    @Override 
    public void contextDestroyed(final ServletContextEvent contextEvent) { 
     return; 
    } 

    @Override 
    public void contextInitialized(final ServletContextEvent contextEvent) { 
     contextEvent.getServletContext().addServlet("dynservlet", DynServlet.class) 
       .addMapping("/services/dynservlet"); 
    } 
} 

Thử nghiệm với JEE6 (OFC) và cả hai JBoss 7.1.1 và 7.2.0 (EAP 6.1. 0 Alpha).

Sửa:

Vấn đề với servlets ánh xạ động thực sự là khá sâu trong cơ sở kiến ​​trúc JBoss. Họ sử dụng JBossWeb (một phiên bản chia tách của Tomcat) như là việc triển khai servlet, và trong sự can đảm của mã quản lý ngữ cảnh của nó, nó quyết định tạo ra các thành phần mới thông qua tiêm hoặc mới mới. Ví dụ, các servlet của bạn cần phải được chú thích trong một số kiểu để chúng được xử lý thông qua việc tiêm: Tôi đã đề cập đến @ManagedBean trong câu trả lời ban đầu của mình nhưng có vẻ như chú thích với @WebServlet cũng hoạt động.

+0

Bất kỳ giải pháp nào không có chú thích mọi servlet? = ( –

+0

@ FagnerBrack - không phải là tôi đã tìm thấy cho đến nay.Đó là vấn đề mà bạn không có quyền truy cập vào nguồn servlet? Hoặc rằng có chỉ đơn giản là cách quá nhiều người trong số họ? – Perception

+0

Thực ra tôi đang tạo một quy ước lập bản đồ dinamicaly tạo ra các đường dẫn Http URI theo một vị trí jsp và servlet đã cho (hệ thống tệp) Việc sử dụng chính của Java EE là cho việc quản lý back-end.Trong dự án này tôi không sử dụng JSF do tính chất hạn chế của nó và tận dụng HTML5 Boilerplate, jQuery, requirejs, bootstrap (tùy chỉnh) và tất cả các tính năng front-end JSF không có sẵn. Vấn đề chính khi sử dụng chú thích là tôi nên áp dụng nó trên mọi lớp trong tương lai thay vì ủy nhiệm nhiệm vụ đó cho một quá trình tự động. –

0

Thứ nhất, trong thử nghiệm của tôi, điều này đã làm việc tốt sử dụng một phiên bản của Glassfish V3.

Nhưng, thứ hai, bạn có thể chạy tốt hơn mệnh đề này của đặc tả Servlet 3.0.

Các phương pháp sau được thêm vào ServletContext từ Servlet 3.0 để cho phép định nghĩa chương trình của servlets, bộ lọc và các mẫu url rằng họ ánh xạ. Các phương thức này chỉ có thể được gọi trong quá trình khởi tạo của ứng dụng hoặc từ phương thức contexInitialized của việc triển khai ServletContextListener hoặc từ phương thức onStartup của triển khai ServletContainerInitializer.

Đáng chú ý, các phương pháp này KHÔNG thể được gọi từ phương thức Filter.init(). Ban đầu, tôi đã thử phương pháp này theo phương pháp Servlet.init() và phương pháp init không thành công do ngữ cảnh đã được khởi tạo.

Vì vậy, thử nghiệm của tôi không trùng lặp chính xác thử nghiệm của bạn - tôi đã không sử dụng phương thức Filter.init() cho điều này, thay vì tôi đặt mã trong một ServletContextListener. Và khi tôi làm điều đó, chú thích @EJB của tôi đã được vinh danh.

Chỉnh sửa:

Không hữu ích như âm thanh, tôi cho rằng đây là lỗi trong JBoss. Khi tôi ban đầu đã thử mã ban đầu của bạn bằng cách tiêm từ Bộ lọc, Glassfish đã ném một ngoại lệ, vì bạn không được phép thực hiện thao tác tiêm nơi tôi đã đề cập trước đó. Bây giờ có lẽ đó là một "tính năng bổ sung" của JBoss, nhưng dường như quá trình xử lý tiêm @EJB không hoạt động. Theo spec, điều này sẽ hoạt động như quảng cáo.

+0

Cảm ơn người trả lời. Thật không may nó đã không làm việc khi tải thông qua ServletContextListener. Tôi đã chỉnh sửa câu hỏi trên, bạn có thể cho tôi biết nếu tôi đã làm điều gì sai. –

3

Servlet 3.0 Spec, Sect. 4.4.3.5

Tiêm tài nguyên [ví dụ: @EJB] trên tất cả các thành phần (Servlets, Bộ lọc và Trình nghe) đã thêm theo chương trình hoặc được tạo theo chương trình, trừ các phương thức được thêm vào thông qua các phương pháp lấy một trường hợp, sẽ chỉ được hỗ trợ khi thành phần đó là Managed Bean. Để biết chi tiết về những gì đang một Managed Bean vui lòng tham khảo Managed đặc điểm kỹ thuật Bean được định nghĩa như là một phần của Java EE 6 và JSR 299.

Tuyên bố Bean Managed

Một Java EE 6 quản lý đậu được chú thích @javax.annotation.ManagedBean và có một hàm tạo no-arg. Một bean được quản lý JSR 299 (CDI) chỉ cần một hàm tạo không có arg hoặc một hàm tạo được chú thích là @javax.inject.Inject.

trả lời

Để kích hoạt phun tài nguyên bạn cần phải:

  • nơi @ManagedBean chú thích trên động thêm servlet

    HOẶC

  • phép CDI & bao gồm một trống beans.xml


Sửa

Mặc dù bạn đang tạo servlet động, điều quan trọng là container hiện sáng tạo. Đừng nghĩ rằng việc tạo ra trong ServletContext sẽ hỗ trợ tiêm. Servlet doc rất mơ hồ ở đây.

Với CDI thử:

servletContext.addServlet("your servlet name", @Inject YourServletClass servlet) 
+0

Ok Tôi đã thử chú thích '@ javax.annotation.ManagedBean' trong lớp mở rộng HttpServlet (một lớp đang được ánh xạ theo thực tế). Đậu của tôi không được tiêm. Tôi đã thử bật CDI bằng cách đặt một tệp beans.xml trống trong thư mục META-INF. Vẫn không được tiêm khi sử dụng @Inject. Bất kỳ ý tưởng về những gì có thể được? Tôi sẽ làm một số bài kiểm tra với các thông tin tôi đã nhận được cho đến nay mặc dù. –

+1

Nghĩ rằng có thể xảy ra khi ServletContext tạo Servlet. Buộc container để tạo Servlet- cho CDI, gọi servletContext.addServlet ("tên servlet của bạn", @Inject YourServletClass servlet) –

+0

Chỉ cần làm rõ @GlenBest, "được định nghĩa như một phần của Java EE 6 và JSR 299". JSR 299 định nghĩa Managed Beans, Java EE 6 định nghĩa các lớp khác hỗ trợ tiêm, bao gồm cả servlets (trang 69 của spec). Không cần phải thực hiện thêm một bước nữa để biến Servlet thành ManagedBean. –