2010-10-15 32 views
6

Có thể tạo nhà máy hoặc proxy có thể quyết định xem luồng có đang chạy trong (Web) Yêu cầu hoặc quá trình nền (tức là.) và sau đó tùy thuộc vào thông tin đó, nó tạo ra một bean phiên hoặc một bean nguyên mẫu?Mùa xuân: Tiêm đậu phụ thuộc vào ngữ cảnh (phiên/web hoặc quy trình địa lý/nền cục bộ)

Ví dụ (giả mùa xuân cấu hình :)

<bean id="userInfoSession" scope="session" /> 
<bean id="userInfoStatic" scope="prototype" /> 

<bean id="currentUserInfoFactory" /> 

<bean id="someService" class="..."> 
    <property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" /> 
</bean> 

Tôi hy vọng điều này làm cho câu hỏi của tôi dễ dàng hơn để hiểu ...


Giải pháp của tôi

Đó là không bao giờ muộn để cập nhật câu hỏi của riêng mình;). Tôi đã giải quyết nó với hai phiên bản khác nhau của phiên ứng dụng khách, một phiên máy khách SessionScoped và một phiên SingletonScoped. Cả hai đều là đậu bình thường.

<bean id="sessionScopedClientSession" class="com.company.product.session.SessionScopedClientSession" scope="session"> 
    <aop:scoped-proxy /> 
</bean> 

<bean id="singletonScopedClientSession" class="com.company.product.session.SingletonScopedClientSession" /> 

<bean id="clientSession" class="com.company.product.session.ClientSession"> 
    <property name="sessionScopedClientSessionBeanName" value="sessionScopedClientSession" /> 
    <property name="singletonScopedClientSessionBeanName" value="singletonScopedClientSession" /> 
</bean> 

Các ClientSession sau đó sẽ quyết định nếu singleton hoặc phiên phạm vi:

private IClientSession getSessionAwareClientData() { 
    String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName); 
    return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName); 
} 

đâu loại phiên có thể được thu thập thông qua này:

private boolean isInSessionContext() { 
    return RequestContextHolder.getRequestAttributes() != null; 
} 

Tất cả các lớp học thực hiện một giao diện được gọi IClientSession. Cả hai hạt singletonScoped và sessionScoped mở rộng từ một BaseClientSession nơi thực hiện được tìm thấy.

Mỗi dịch vụ sau đó có thể sử dụng tức là phiên client:

@Resource 
private ClientSession clientSession; 

    ... 

public void doSomething() { 
    Long orgId = clientSession.getSomethingFromSession(); 
} 

Bây giờ nếu chúng ta đi thêm một bước nữa chúng ta có thể viết một cái gì đó giống như một Emulator cho phiên. Điều này có thể được thực hiện bằng cách khởi tạo clientSession (không có ngữ cảnh yêu cầu) phiên singleton. Bây giờ tất cả các dịch vụ có thể sử dụng clientSession cùng và chúng tôi vẫn có thể "bắt chước" một ví dụ sử dụng:

 clientSessionEmulator.startEmulateUser(testUser); 
     try { 
      service.doSomething(); 
     } finally { 
      clientSessionEmulator.stopEmulation(); 
     } 

hơn Một lời khuyên: chăm sóc về luồng trong SingletonScoped clientSession dụ! Wouw, tôi nghĩ rằng tôi có thể làm điều đó với ít dòng hơn;) Nếu bạn muốn biết thêm về cách tiếp cận này cảm thấy tự do để liên hệ với tôi.

Trả lời

1

rephrase của bạn thực sự là đáng kể đơn giản hơn :)

bạn currentUserInfoFactory có thể tận dụng RequestContextHolder.getRequestAttributes(). Nếu một phiên có mặt và được kết hợp với chuỗi gọi, thì điều này sẽ trả về một đối tượng không null, và sau đó bạn có thể truy xuất một cách an toàn bean bean có phạm vi phiên từ ngữ cảnh. Nếu nó trả về một giá trị rỗng, thì bạn nên tìm nạp bean nguyên mẫu.

Nó không phải là rất gọn gàng, nhưng nó đơn giản, và nên làm việc.

+0

Tôi sẽ thử. Đôi khi giải pháp đơn giản là tốt nhất và nếu nó hoạt động, tại sao nó không gọn gàng? Một số giải pháp khác? –

+1

@Frank: Mã sử ​​dụng 'RequestContextHolder' thường khó kiểm tra. Vì lý do đó, nó nên được nản lòng. – skaffman

1

Tạo hai bộ tải bối cảnh tùy chỉnh mà ràng buộc phạm vi defintion cùng để triển khai khác nhau:

public final class SessionScopeContextLoader extends GenericXmlContextLoader { 

    protected void customizeContext(final GenericApplicationContext context) { 
    final SessionScope testSessionScope = new SessionScope(); 
    context.getBeanFactory().registerScope("superscope", testSessionScope); 
    } 
    ... 
} 

Sau đó, bạn thực hiện một tương ứng cho singleton (chắc phạm vi riêng của bạn chỉ với tĩnh học)

Sau đó, bạn chỉ chỉ định trình tải ngữ cảnh thích hợp trong khởi động xml cho mỗi một trong hai ngữ cảnh.

+0

Tôi nên chỉ định trình tải ngữ cảnh thích hợp trong WebContext ở đâu? Tôi không thực sự nhận được điểm về phạm vi tùy chỉnh, xin lỗi. Tôi tìm thấy chuyển đổi của bạn ở đây http://stackoverflow.com/questions/450557/custom-spring-scopes nhưng nó đã không giúp tôi đạt được ... –

2

Tôi đã tạo cách giải quyết phổ dụng nhỏ để chèn hạt phụ thuộc vào ngữ cảnh.

Guess chúng ta có hai đậu:

<bean class="xyz.UserInfo" id="userInfo" scope="session" /> 
<bean class="xyz.UserInfo" id="userInfoSessionLess" /> 

Chúng tôi muốn sử dụng "UserInfo" đậu cho hành động người dùng web và "userInfoSessionLess" đậu cho các dịch vụ nền ví dụ. Wa cũng muốn viết mã và không muốn nghĩ về bối cảnh, ví dụ:

@Autowired 
//You will get "java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request?" for session less services. 
//We can fix it and autowire "userInfo" or "userInfoSessionLess" depends on context... 
private UserInfo userInfo; 

public save(Document superSecureDocument) { 
    ... 
    superSecureDocument.lastModifier = userInfo.getUser(); 
    ... 
} 

Bây giờ chúng ta cần tạo ra phạm vi phiên tùy chỉnh để làm cho nó làm việc:

public class MYSessionScope extends SessionScope implements ApplicationContextAware { 
    private static final String SESSION_LESS_POSTFIX = "SessionLess"; 
    private ApplicationContext applicationContext; 
    public Object get(String name, ObjectFactory objectFactory) { 
    if (isInSessionContext()) { 
     log.debug("Return session Bean... name = " + name); 
     return super.get(name, objectFactory); 
    } else { 
     log.debug("Trying to access session Bean outside of Request Context... name = " + name + " return bean with name = " + name + SESSION_LESS_POSTFIX); 
     return applicationContext.getBean(name.replace("scopedTarget.", "") + SESSION_LESS_POSTFIX); 
    } 
    } 
    private boolean isInSessionContext() { 
    return RequestContextHolder.getRequestAttributes() != null; 
    } 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
    this.applicationContext = applicationContext; 
    } 
} 

Đăng ký phạm vi mới:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> 
    <property name="scopes"> 
     <map> 
      <entry key="mySession"> 
       <bean class="com.galantis.gbf.web.MYSessionScope" /> 
      </entry> 
     </map> 
    </property> 
</bean> 

Bây giờ chúng ta cần phải sửa đổi đậu definions như thế này:

<bean class="xyz.UserInfo" id="userInfo" scope="mySession" autowire-candidate="true"/> 
<bean class="xyz.UserInfo" id="userInfoSessionLess" autowire-candidate="false"/> 

Đó là tất cả. Bean có tên "SessionLess" sẽ được sử dụng cho tất cả các hạt tạp "mySession" nếu chúng ta sử dụng bean bên ngoài chuỗi yêu cầu web thực tế.

+0

Chưa thử giải pháp của bạn nhưng có vẻ rất dễ thương với tôi . Cảm ơn bạn đã chia sẻ nó! –

Các vấn đề liên quan