Spring5 使用 lookup-method 实现单例类注入非单例类

大多数的 bean 在应用场景中都是单例的。当这个单例的 bean 需要和非单例的 bean 联合使用时,有可能会因为不同 bean 的生命周期而产生问题。

大多数的 bean 在应用场景中都是单例的。当这个单例的 bean 需要和非单例的 bean 联合使用时,有可能会因为不同 bean 的生命周期而产生问题。假设单例的 bean A 在每个方法调用中使用了非单例的 bean B,由于容器只会创建 bean A 一次,而只有一次机会来配置属性。那么容器就无法给 bean A 每次都提供新的 bean B 的示例。下面将通过 lookup-method 注入来解决这个问题。

依赖

引入 Spring5 依赖,如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.29</version>
</dependency>

服务

打印器服务

打印器服务拥有一个简单的 print() 方法,向控制台输出一个字符串,同时,使用 @Scope 设置 Bean 的范围是 prototype 的,每次都会创建一个新的示例。

代码如下:

package com.hxstrive.spring5.lookup_method;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * 打印器
 * @author hxstrive.com
 */
@Component
@Scope(value = "prototype")
public class Printer {

    public void print() {
        System.out.println(this + " >> " + getClass().getName());
    }

}

打印器管理服务

打印器服务类用于管理所有的打印器,调用打印器的 print() 方法打印信息,注意,每次调用 PrinterManager 类的 show() 方法都会调用 createPrinter() 抽象方法,创建一个新的 Printer 打印器实例。

代码如下:

package com.hxstrive.spring5.lookup_method;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

/**
 * Printer 管理器
 * @author hxstrive.com
 */
@Component
public abstract class PrinterManager {

    public void show() {
        Printer printer = createPrinter();
        printer.print();
    }

    //使用 CGLIB 库,重新生成子类,重写配置的方法和返回对象
    @Lookup("printer")
    protected abstract Printer createPrinter();

}

注意:由于采用了 CGLIB 生成子类方式,因此需要用来动态注入的类不能是 final 修饰的;需要动态注入的方法也不能是 final 修饰的。同时,还需要注意,Printer 类的 scope 配置需要时 prototype。

启动类

Application 类是一个典型的 Java Application 类,其中 main 方法就是应用执行的入口。下面示例中,AnnotationConfigApplicationContext 类是 Spring 上下文的一种实现,实现了基于 Java 配置类的加载,主要用于管理 Spring bean。Application 类上的 @ComponentScan 注解会自动扫描指定包下全部标有 @Component 的类,并自动注册为 bean,当然也包含 @Component 下的子注解 @Service、@Repository、@Controller 等。

代码如下:

package com.hxstrive.spring5.lookup_method;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * lookup-method 注入示例
 * @author hxstrive.com
 */
@ComponentScan
public class LookupMethodApp {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(LookupMethodApp.class);
        PrinterManager printerManager = context.getBean(PrinterManager.class);
        printerManager.show();
        printerManager.show();
        printerManager.show();
    }

}

运行服务,输出如下:

com.hxstrive.spring5.lookup_method.Printer@5db45159 >> com.hxstrive.spring5.lookup_method.Printer
com.hxstrive.spring5.lookup_method.Printer@6107227e >> com.hxstrive.spring5.lookup_method.Printer
com.hxstrive.spring5.lookup_method.Printer@7c417213 >> com.hxstrive.spring5.lookup_method.Printer

从上面的输出可知,调用三次 PrinterManager 的 show() 方法创建了三个新的 Printer 对象,每次都创建了一个新的 Printer 实例。

学习从来无捷径,循序渐进登高峰。 —— 高永祚
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号