Spring's IoC container manages not only the instantiation of your objects (beans), but also the binding of interacting objects (or dependencies). If you need to inject (for example) a bean that is in scope of an HTTP-request into another bean with a longer-term scope, you can inject an AOP proxy instead of the bean that is in scope. That is, you need to implement a proxy object that exposes the same public interface as the in-scope object, but which can also retrieve the real target object from the corresponding scope (eg HTTP-request) and delegate method calls to the real object.

You can also use <aop:scoped-proxy/> between beans that are defined as singleton, with the reference passing through an intermediate proxy that is serializable and is therefore able to re-obtain the target singleton bean upon deserialization.

When you declare <aop:scoped-proxy/> for a visibility scope bean prototype, each method call on the shared proxy results in the creation of a new target instance, which then the call is transferred.

Also, scoped proxies are not the only way to access beans from shorter scopes in a lifecycle-safe manner. It is also possible to declare the injection point (that is, a constructor or setter argument or automatically bound field) as ObjectFactory<MyTargetBean>, which allows the getObject() call to retrieve the current instance on demand each time when needed - without having to hold onto the instance or store it separately.

As an extended option, you can declare an ObjectProvider<MyTargetBean>, which provides several additional access options, including getIfAvailable and getIfUnique.

The JSR-330 option is called Provider and is used with a Provider<MyTargetBean> declaration and a corresponding get() call for each get attempt.

The configuration in the following example is just one line, but it's important to understand why and how it works:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- HTTP Session-scoped bean exposed as a proxy -->
    <bean id="userPreferences" class="com.something.UserPreferences" scope="session">
        <!-- instructs the container to proxy the surrounding bean -->
        <aop:scoped-proxy/>
    </bean>
    <!-- a bean in the scope of a singleton, injected by proxy to the above bean -->
    <bean id="userService" class="com.something.SimpleUserService">
        <!-- link to the proxied bean userPreferences -->
        <property name="userPreferences" ref="userPreferences"/>
    </bean>
</beans>
  1. String defining the proxy.

To create such a proxy, you need to insert a <aop:scoped-proxy/> child element into the in-scope bean definition. Why do definitions of beans that are in scope at the request, session, or special scope levels require a <aop:scoped-proxy/> element? Consider the following definition of a singleton bean and compare it to what you need to define for the above scopes (note that the following definition of the userPreferences bean as it stands is incomplete):

<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
<bean id="userManager" class="com.something.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

In the previous example, the single bean (userManager) is implemented using a reference to the bean (userPreferences), located in the visibility area of the HTTP Session. The important point here is that the userManager bean is a singleton object: it is instantiated exactly once for each container, and its dependencies (in this case only one, the userPreferences bean) are also implemented only once. This means that the userManager bean only works with the same userPreferences object (that is, the one with which it was originally implemented).

This is not the behavior that is appropriate when injecting a bean with a shorter lifecycle that is in scope into a bean with a longer lifecycle that is in scope (for example, injecting an interoperating bean that is in scope in HTTP Session, as a dependency in a single bean). Rather, it requires one userManager object, and for the duration of the HTTP Session, a userPreferences object specific to that HTTP Session. So the container creates an object that exposes exactly the same public interface as the UserPreferences class (ideally an object that is an instance of UserPreferences) that can receive the real UserPreferences object. UserPreferences from the definition mechanism (HTTP request, Session and so on). The container injects this proxy object into the userManager bean, which does not know that this UserPreferences reference is a proxy. In this example, when a UserManager instance initiates a method on a UserPreferences object with an injected dependency, it actually calls a method on the proxy. The proxy then fetches the real UserPreferences object from (in this case) the HTTP Session and delegates the method call to the resulting real UserPreferences object.

The following (correct and complete) configuration is therefore required when injecting beans within the scope of request and session into collaborating objects, as shown in the following example:

<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

Selecting the type of proxy to create

By default, when a Spring container creates a proxy for a bean marked with the <aop:scoped-proxy/> element, a CGLIB-based class proxy is created.

CGLIB proxies only intercept calls to public methods! Do not call non-public methods on such a proxy. They are not delegated to the actual target object that is in scope.

Alternatively, you can configure the Spring container to create standard JDK-based proxies for such in-scope beans by specifying false for the proxy-target-class attribute value element <aop:scoped-proxy/>. Using a proxy based on the JDK interface means that you will not need additional libraries in your application's class path to affect such proxying. However, this also means that the class of a scoped bean must implement at least one interface, and that all communicating objects into which the scoped bean is embedded must refer to it through one of its interfaces. The following example shows an interface-based proxy:

<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.stuff.DefaultUserPreferences" scope="session">
    <aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.stuff.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>