Подтвердить что ты не робот

Spring сеансовый beans (контроллеры) и ссылки на службы с точки зрения сериализации

  • стандартный случай - у вас есть контроллер (@Controller) с @Scope("session").
  • классы, помещенные в сеанс, как правило, должны реализовывать Serializable, чтобы они могли быть физически сохранены в случае перезапуска сервера, например
  • Если контроллер реализует Serializable, это означает, что все службы (другие spring beans), которые он ссылается, также будут сериализованы. Они часто являются прокси-серверами, со ссылками на операторов транзакций, фабрики менеджеров объектов и т.д.
  • Маловероятно, что какая-либо служба или даже контроллер имеют ссылку на ApplicationContext, реализуя ApplicationContextAware, поэтому это может эффективно означать, что весь контекст сериализуется. И учитывая, что он содержит множество соединений, то есть вещи, которые не могут быть сериализованы по идее, он будет восстановлен в коррумпированном состоянии.

До сих пор я в основном игнорировал эти проблемы. Недавно я подумал о объявлении всех моих зависимостей spring transient и возвращении их в readResolve() статическими классами утилиты WebApplicationContextUtils и таких, которые содержат запрос /ServletContext в ThreadLocal. Это утомительно, но гарантирует, что когда объект будет десериализован, его зависимости будут "обновлены" с текущим контекстом приложения.

Есть ли принятая практика для этого или какие-либо рекомендации по сериализации частей контекста spring.

Обратите внимание, что в JSF управляемые beans (~ контроллеры) имеют состояние (в отличие от основанных на действии веб-фреймворков). Поэтому, возможно, мой вопрос стоит больше для JSF, чем для spring -mvc.

4b9b3361

Ответ 1

В этой презентации (около 1:14) докладчик говорит, что эта проблема разрешена в spring 3.0, предоставляя прокси-сервер, -serializable beans, который получает экземпляр из текущего контекста приложения (при десериализации)

Ответ 2

Я ожидал бы, что контроллеры областей будут "singleton", то есть один раз для приложения, а не в сеансе.

Обследование сеанса обычно используется больше для хранения информации для каждого пользователя или для пользовательских функций.

Обычно я просто храню объект пользователя в сеансе и, возможно, какой-то beans, используемый для аутентификации или такой. Это.

Взгляните на документы spring для настройки некоторых пользовательских данных в области сеанса с использованием прокси-сервера aop:

http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection

Надеюсь, что поможет

Ответ 3

Похоже, что щедрость не привлекла ни одного ответа, поэтому я буду документировать свое ограниченное понимание:

@Configuration
public class SpringConfig {

    @Bean 
    @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 
    MyService myService() {
        return new MyService();
    }

    @Bean
    @Scope("request")
    public IndexBean indexBean() {
        return new IndexBean();
    }

    @Bean
    @Scope("request")
    public DetailBean detailBean() {
        return new DetailBean();
    }
}

public class IndexBean implements Serializable {

    @Inject MyService myService;

    public void doSomething() {
        myService.sayHello();
    }
}

public class MyService {
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

Spring не будет вводить голый MyService в IndexBean, а сериализуемый прокси к нему. (Я тестировал это, и он работал).

Однако документация spring пишет:

Вам не нужно использовать <aop:scoped-proxy/> в сочетании с beans, которые указаны как singletons или prototypes. Если вы попытаетесь создать расширенный прокси-сервер для singleton bean, будет создан BeanCreationException.

По крайней мере, при использовании конфигурации на основе java, bean и его прокси могут быть созданы просто отлично, т.е. не выбрано исключение. Однако похоже, что использование разрешенных прокси для достижения сериализуемости не является предполагаемым использованием таких прокси. Как бы то ни было, я опасаюсь, что spring может исправить эту "ошибку" и предотвратить создание доверенных прокси-серверов через конфигурацию на основе Java.

Кроме того, существует ограничение: Имя класса прокси-сервера отличается после перезапуска веб-приложения (поскольку имя класса прокси-сервера основано на хэш-коде совета, используемого для его создания, что, в свою очередь, зависит от hashCode объекта класса перехватчика. Class.hashCode не переопределяет Object.hashCode, который нестабилен при перезагрузке). Поэтому сериализованные сеансы не могут использоваться другими виртуальными машинами или перезапусками.

Ответ 4

Недавно я объединил JSF с Spring. Я использую RichFaces и функцию @KeepAlive, которая сериализует JSF bean, поддерживая страницу. Есть два способа, с помощью которых я могу работать.

1) Используйте @Component ( "session" ) для поддержки JSF bean

2) Получите bean из ELContext, когда вам это нужно, примерно так:

@SuppressWarnings("unchecked")
public static <T> T  getBean(String beanName) {
    return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
}

Ответ 5

После того, как все различные альтернативы предложили все, что мне нужно было сделать, добавьте aop: scoped-proxy в мое определение bean и он начал работать.

<bean id="securityService"
    class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl">
    <aop:scoped-proxy/>
    <property name="identityService" ref="identityService" />
</bean>

securityService вводится в мою управляемую субу, которая является областью видимости. Кажется, это работает нормально. Согласно документации spring это должно вызывать BeanCreationException, так как securityService является одноэлементным. Однако это не происходит, и все работает нормально. Не уверен, что это ошибка или какие побочные эффекты будут.

Ответ 6

Сериализация Динамических прокси работает хорошо, даже между разными JVM, например. как используется для репликации сеанса.

@Configuration public class SpringConfig {
@Bean 
@Scope(proxyMode = ScopedProxyMode.INTERFACES) 
MyService myService() {
    return new MyService();
}
.....

Вам просто нужно установить идентификатор ApplicationContext до, контекст обновляется (см.: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(String))

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();

Работает нормально на Spring -Version: 4.1.2.RELEASE