java - 在 Spring 中通过代理创建和初始化惰性类实例

标签 java spring proxy lazy-initialization

Spring 中是否有现成的开箱即用解决方案来代理类,以便在调用该类的方法时创建(新实例)和初始化(调用 setter)?

我发现并尝试使用 org.springframework.aop.target.LazyInitTargetSource。

也许我做错了什么,但在下面的场景中,我的类实例创建了两次。一旦从上下文中检索到 bean,然后在调用方法时再次调用一次:

我的代理类:

public class NewClass {

    private Integer i;

    public NewClass() {
        System.out.println("NewClass()");
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }

    public Integer add() {
        return i + 1;
    }
}

Spring 配置:

<bean id="newClassTarget" class="com.mycompany.spring.NewClass" lazy-init="true">
    <property name="i" value="1"/>
</bean>

<bean id="newClass" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource">
        <bean class="org.springframework.aop.target.LazyInitTargetSource">
            <property name="targetBeanName">
                <idref local="newClassTarget"/>
            </property>
        </bean>
    </property>
</bean>

运行代码:

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("lazy.xml");
    System.out.println("Context initialized");
    System.out.println("before getting bean");
    NewClass newClass = (NewClass) applicationContext.getBean("newClass");
    System.out.println("after getting bean");
    System.out.println("calling add()...");
    System.out.println(newClass.add());
}

产生:

Context initialized
before getting bean
NewClass()
after getting bean
calling add()...
NewClass()
setI(): 1
2

因此,当从 Spring 上下文获取 bean 并调用 add() 方法时,将调用 NewClass 构造函数。我觉得这不太好,我是不是搞砸了什么?

无论如何,第一个调用来自Cglib2AopProxy.getProxy()中的enhancer.create()。似乎代理在请求 bean 时创建代理类的实例,而不是在第一个方法调用发生时。这不是我想要的。

我可以创建自己的 java.lang.reflect.Proxy 作为我的 NewClass 的持有者,并在第一次调用方法时在处理程序的 invoke() 中创建 NewClass 的实例。不过,我会先尝试调用 setter。

Spring 中是否有现成的解决方案可以用来实现:

Context initialized
before getting bean
after getting bean
calling add()...
NewClass()
setI(): 1
2

?

最佳答案

我能够复制您的行为 - 我的解决方法是简单地为您的 NewClass 定义一个接口(interface),这样就创建了 Java 动态代理而不是 CGLIB 增强代理。然后它按预期工作 - 在调用方法时实例化 NewClass。

public interface NewInterface {
    public void setI(Integer i);
    public Integer add() ;
}

public class NewClass implements NewInterface{

    private Integer i;

    public NewClass() {
        System.out.println("NewClass()");
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }

    public Integer add() {
        return i + 1;
    }
}

关于java - 在 Spring 中通过代理创建和初始化惰性类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11097369/

相关文章:

java - 按 BACKSPACE 时返回上一个控件

java - 使用另一个类的compareTo方法

java - Spring Data - MongoDb 聚合 $ifNull

Spring getBean 与类型验证

function - Scala 是否提供了一种在不重复参数列表的情况下实现 "proxy"或 "decorate"函数的方法?

自定义 DNS 答案

java - 比较 Java 中的二维数组并打印差异

java - 在 Android 中保存应用程序状态

在服务器上部署后,java spring web 应用程序不起作用

google-app-engine - 谷歌应用程序的反向代理?