Ответ 1
Вам нужно будет понять, что каждая из этих аннотаций выбирает для себя. Смотрите Javadoc, здесь. Продолжайте для более подробного объяснения.
Первый
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
создает
динамический прокси JDK, реализующий все интерфейсы, предоставляемые классом целевого объекта
Другими словами, прокси будет подтипом интерфейсов, которые реализует класс целевого объекта, но не будет подклассом самого класса целевого объекта.
По сути, Spring делает следующее
public class Example {
public static void main(String[] args) throws Exception {
Foo target = new Foo();
InvocationHandler proxyHandler = ... // some proxy specific logic, likely referencing the 'target'
// works fine
Printable proxy = (Printable) Proxy.newProxyInstance(Example.class.getClassLoader(),
target.getClass().getInterfaces(), proxyHandler);
// not possible, ClassCastException
Foo foo = (Foo) proxy;
}
public static class Foo implements Printable {
@Override
public void print() {
}
}
public interface Printable {
void print();
}
}
Возвращаемый прокси не будет иметь тип Foo
и поэтому вы не можете внедрить его в какие-либо цели этого типа. Например, Spring не сможет ввести его в поле, подобное
@Autowired
private Foo foo;
но успешно введет прокси в поле, подобное
@Autowired
private Printable printable;
Все вызовы прокси-сервера будут обрабатываться InvocationHandler
(который обычно выполняет некоторую логику для конкретного случая использования, а затем делегирует целевому объекту).
Вторая аннотация
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )
создает
основанный на классе прокси (использует CGLIB).
Помимо интерфейсов, с помощью CGLIB Spring сможет создавать прокси, класс которого является подклассом целевого класса. По сути, это делает следующее
Foo target = new Foo();
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setInterfaces(target.getClass().getInterfaces());
enhancer.setSuperclass(target.getClass());
net.sf.cglib.proxy.MethodInterceptor interceptor = ... // some proxy specific logic, likely referencing the 'target'
enhancer.setCallback(interceptor);
// works fine
Foo proxy = (Foo) enhancer.create();
CGLIB создает новый класс, который является подклассом Foo
и создает его экземпляр (вызывая конструктор Foo
). Все вызовы прокси будут перехвачены предоставленным обратным вызовом (который обычно выполняет некоторую логику для конкретного случая использования, а затем делегирует объекту назначения).
Поскольку прокси-класс расширяет Foo
, Spring может внедрить прокси в поле (или параметр конструктора/метода), например
@Autowired
private Foo injectMe;
Все это говорит о том, что если вы программируете для интерфейсов, то ScopedProxyMode.INTERFACES
будет достаточно. Если нет, используйте ScopedProxyMode.TARGET_CLASS
.
Что касается использования @SessionAttributes
, это не альтернатива сессионным bean-объектам. Атрибуты сессий - это просто объекты, а не бины. Они не обладают полным жизненным циклом, возможностями инъекции, поведением прокси, которое может иметь бин.