2012-07-09 21 views
17

Đây là một dự án Spring MVC với Hibernate. Tôi đang cố gắng tạo một lớp Logger, chịu trách nhiệm nhập các bản ghi vào cơ sở dữ liệu. Các lớp khác chỉ gọi các phương thức thích hợp với một số thuộc tính và lớp này nên làm tất cả các phép thuật. Bởi bản chất nó phải là một lớp với các phương pháp tĩnh, nhưng điều đó gây ra vấn đề với đối tượng dao autowiering.@autowired trong các lớp tĩnh

public class StatisticLogger { 
    @Autowired 
    static Dao dao; 
    public static void AddLoginEvent(LogStatisticBean user){ 
     //TODO code it god damn it 
    } 
    public static void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){ 
     //TODO code it god damn it 
    } 
    public static void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){ 
     ExceptionLogBean elb=new ExceptionLogBean(); 
     elb.setStuntDescription(e); 
     elb.setSourcePage(page); 
     elb.setParameters(parameters); 
     if(dao!=null){ //BUT DAO IS NULL 
      dao.saveOrUpdateEntity(elb); 
    } 
} 

Làm cách nào để làm đúng? Tôi nên làm gì để không làm cho đối tượng dao rỗng? Tôi biết rằng tôi có thể vượt qua nó như là một tham số phương pháp, nhưng điều đó không phải là rất tốt. Tôi đoán rằng autowired không thể làm việc trên các đối tượng tĩnh, bởi vì chúng được tạo ra sớm để autowiering cơ chế chưa được tạo ra.

Trả lời

38

Bạn không thể @Autowired trường tĩnh. Nhưng có một kỹ năng khó khăn để đối phó với điều này:

@Component 
public class StatisticLogger { 

    private static Dao dao; 

    @Autowired 
    private Dao dao0; 

    @PostConstruct  
    private void initStaticDao() { 
    dao = this.dao0; 
    } 

} 

Trong một từ, @Autowired một instance field, và gán các giá trị cho các tĩnh nộp khi đối tượng của bạn được xây dựng. BTW, đối tượng StatisticLogger cũng phải được Spring quản lý.

+0

Thú vị lừa. Tôi sẽ ghi nhớ điều đó trong tương lai :) –

+0

Kiểu trả về của phương thức PHẢI bị vô hiệu. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html –

+1

Lâu sau trận chiến, tôi đã sử dụng giải pháp này hoạt động tốt nhất. Nhưng công ty Sonar đã nhanh chóng đưa ra một cảnh báo về nó: 'Cập nhật chính xác một trường tĩnh từ một phương thức không tĩnh là khó để có được quyền và có thể dễ dàng dẫn đến lỗi nếu có nhiều phiên bản lớp và/hoặc nhiều luồng trong khi chơi. Lý tưởng nhất, các trường tĩnh chỉ được cập nhật từ các phương thức tĩnh được đồng bộ hóa. ”Tôi nghĩ rằng nó xứng đáng đề cập đến nó. – MaxouMask

14

Tự động hóa cổ điển có thể không hoạt động, bởi vì lớp tĩnh không phải là Bean và do đó Spring không thể quản lý. Có nhiều cách xung quanh việc này, ví dụ bằng cách sử dụng the factory-method aproach in XML hoặc bằng cách tải hạt từ ngữ cảnh mùa xuân trong khối khởi tạo tĩnh, nhưng những gì tôi đề nghị là thay đổi thiết kế của bạn:

Không sử dụng phương pháp tĩnh, sử dụng các dịch vụ mà bạn tiêm vào nơi bạn cần chúng. Nếu bạn sử dụng Spring, bạn cũng có thể sử dụng nó một cách chính xác. Dependency Injection là một kỹ thuật hướng đối tượng, và nó chỉ có ý nghĩa nếu bạn thực sự nắm lấy OOP.

+0

Nice, cảm ơn bạn –

0

Tôi biết đây là một câu hỏi cũ nhưng chỉ muốn chia sẻ những gì tôi đã làm, giải pháp bởi @Weibo Li là ok nhưng vấn đề nó làm tăng Sonar cảnh báo quan trọng về giao biến phi tĩnh để một biến tĩnh

cách tôi giải quyết nó không có cảnh báo sóng siêu âm như sau

  1. tôi thay đổi StatisticLogger để singlton lớp (không còn tĩnh) như thế này

    public class Statisti cLogger { cá thể tĩnh StatisticLogger tĩnh = null; Dao đào riêng;

    public static StatisticLogger getInstance() { 
        if (instance == null) { 
         instance = new StatisticLogger(); 
        } 
        return instance; 
    } 
    
    protected StatisticLogger() { 
    } 
    
    public void setDao(Dao dao) { 
        this.dao = dao; 
    } 
    public void AddLoginEvent(LogStatisticBean user){ 
        //TODO code it god damn it 
    } 
    public void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){ 
        //TODO code it god damn it 
    } 
    public void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){ 
        ExceptionLogBean elb=new ExceptionLogBean(); 
        elb.setStuntDescription(e); 
        elb.setSourcePage(page); 
        elb.setParameters(parameters); 
        if(dao!=null){ 
         dao.saveOrUpdateEntity(elb); 
    } 
    

    }

  2. Tôi tạo ra một dịch vụ (hoặc Component) mà autowire dịch vụ mà tôi muốn và đặt nó trong lớp singlton này là an toàn vì trong mùa xuân nó sẽ khởi tạo tất cả các hạt cà phê được quản lý trước làm bất cứ điều gì khác và điều đó có nghĩa là các phương pháp dưới đây PostConstruct luôn gọi trước khi bất cứ điều gì có thể truy cập vào một cái gì đó StatisticLogger như

    @Component public class DaoSetterService này {

    @Autowired 
    private Dao dao0; 
    
    @PostConstruct  
    private void setDaoValue() { 
        StatisticLogger.getInstance().setDao(dao0); 
    } 
    

    }

  3. Thay vì sử dụng StatisticLogger như lớp tĩnh tôi chỉ sử dụng nó như là StatisticLogger.getInstance() và tôi có thể truy cập vào tất cả các phương pháp bên trong nó