2012-02-22 33 views
6

Tôi có một lớp trừu tượng AbstractService trong đó có một tham chiếu đến AbstractDAOAutowire phụ thuộc vào lớp con

class AbstractService{ 
    protected AbstractDAO abstractDAO; 
} 

AbstractService sẽ được mở rộng bởi lớp dịch vụ thực tế như ServiceClassA, ServiceClassB vv, và AbstractDAO sẽ được kéo dài thêm DaoClassA, DaoClassB v.v.

Tùy thuộc vào loại nào đang mở rộng AbstractService, abstractDAO phải là một phiên bản DaoClassA, DaoClassB vv

tôi có thể đạt được điều này bằng cách setter abstractDAO trong lớp kéo dài như

class ServiceClassA{  
    @Autowired 
    @Qualifier("daoClassA") 
    public void setAbstractDAO(AbstractDAO abstractDAO) { 
     super.abstractDAO = abstractDAO; 
    } 
} 

Có cách nào để có setter setAbstractDAO trong AbstractService lớp tự và abstractDAO bị Autowired phụ thuộc vào subclass có thể wth SPEL + Qualifier etc

Chúng tôi không muốn sử dụng bất kỳ cấu hình XML nào cho số này

+0

Có bất cứ lý do bạn không thể đưa ví dụ '@Autowired DaoClassA dao' vào' ServiceClassA'? Tại sao trường cần phải được khai báo trong 'AbstractService'? – skaffman

+0

Câu hỏi hay. Tôi đã luôn luôn làm một cái gì đó tương tự như cách tiếp cận bạn mô tả (hơi khác nhau, nhưng ý tưởng cơ bản giống nhau) và tôi đã luôn luôn muốn một cái gì đó tự động hơn một chút. Mong muốn xem liệu có ai có cách tiếp cận tốt hay không. –

+0

@skaffman Trong trường hợp tôi đã có, tôi muốn AbstractService có quyền truy cập vào AbstractDao để tôi có thể viết các phiên bản chung của các hoạt động CRUD, trong số những thứ khác. –

Trả lời

7

Tôi sẽ không làm như thế này. Thật vậy, có một cơ hội tốt mà ServiceClassA phụ thuộc vào một số phương pháp cụ thể của DaoClassA. Trong trường hợp này, bạn sẽ phải truyền AbstractDAO được bảo vệ đến DaoClassA mỗi lần bạn muốn gọi một phương thức cụ thể như vậy.

tôi sẽ làm cho nó chung chung, và đảo ngược những con đường phụ thuộc được tiêm:

public class AbstractService<T extends AbstractDAO> { 
    protected T dao; 

    protected AbstractService(T dao) { 
     this.dao = dao; 
    } 

    // methods common to all the services 
} 

public class ServiceClassA extends AbstractService<DaoClassA> { 
    @Autowired 
    public ServiceClassA(DaoClassA dao) { 
     super(dao); 
    } 

    // methods specific to ServiceClassA 
} 
+0

Điều này tương tự với cách tiếp cận mà tôi đã sử dụng trong quá khứ, và nó là tốt cho lý do bạn lưu ý lớp con. Nhưng nó vẫn có nhược điểm là nó đòi hỏi các điểm tiêm cụ thể kiểu. Có cách nào tốt để tránh điều đó không? (Tôi không nghĩ rằng có, nhưng nếu ai đó có một, tôi muốn biết.) –

+0

Nhưng nó vẫn tương tự như cách tiếp cận ban đầu và tất cả các lớp con sẽ vẫn phải làm công việc –

+0

Bạn có thể đặt một DaoClassA tham chiếu trong ServiceClassA và bây giờ nó sẽ là loại cụ thể (không có đúc). –

0

Không, không có. Bạn không thể truy cập vào lớp hoặc tên bean hiện đang phổ biến AutowiredAnnotationBeanPostProcessor từ SPEL.

Bạn có thể ghi đè AbstractBeanFactory.evaluateBeanDefinitionString và thêm beanDefinition làm biến trong BeanExpressionContext. Sau đó, bạn có thể lấy được Đạo từ Dịch vụ. bằng cách sử dụng SPEL trong chú thích @Value.

2

Tôi đã giải quyết được vấn đề tương tự như bạn đã làm. Tôi tìm thấy một cách khác, bạn không cần phải tạo ra các phương thức setter. Thay vì sử dụng các hàm tạo thường xuyên, nhưng sử dụng tính năng tự động chạy Spring. Dưới đây là mã hoàn chỉnh:

lớp dịch vụ:

public abstract class AbstractService { 

    protected final AbstractDAO dao; 

    // Constructor forces you to inject dao in subclass 
    public AbstractService(final AbstractDAO dao) { 
     this.dao = dao; 
    } 

    public final void service() { 
     // you can do something generic here with 'dao' 
     // no matter which subclass is injected 
     this.dao.doSomething(); 
    } 
} 

@Component 
public class ServiceClassA extends AbstractService { 

    @Autowired 
    public ServiceClassA(@Qualifier("daoClassA") final AbstractDAO dao) { 
     super(dao); 
    } 

} 

@Component 
public class ServiceClassB extends AbstractService { 

    @Autowired 
    public ServiceClassB(@Qualifier("daoClassB") final AbstractDAO dao) { 
     super(dao); 
    } 

} 

Thông báo @Qualifier("daoClassA") trong nhà xây dựng lớp con

lớp Dòng:

public interface AbstractDAO {  
    public void doSomething(); 
} 

@Component 
public class DaoClassA implements AbstractDAO { 

    @Override 
    public void doSomething() { 
     System.out.println("I am DaoClassA"); 
    }  
} 

@Component 
public class DaoClassB implements AbstractDAO { 

    @Override 
    public void doSomething() { 
     System.out.println("I am DaoClassB"); 
    }  
} 

Và cuối cùng, bây giờ bạn có thể gọi dịch vụ chung của bạn với lớp dịch vụ cụ thể và lớp DAO cụ thể: (tất nhiên bạn có thể tự động phát hiện chúng ở đâu đó)

((AbstractService) context.getBean("serviceClassA")).service(); 
((AbstractService) context.getBean("serviceClassB")).service(); 

sẽ in:

I am DaoClassA 
I am DaoClassB 
Các vấn đề liên quan