繁体   English   中英

如何在 Spring Boot 中实现装饰模式

[英]How to implement Decorator pattern in Spring Boot

我知道如何在没有 Spring 的情况下实现和使用装饰器模式。

因为在这种模式中,您自己控制创建组件的过程,并且可以执行动态行为添加。

下面是一个不使用 Spring 的实现示例:

public class SimpleDecoratorApp {
    public static void main(String[] args) {
        SimplePrinter simplePrinter = new SimplePrinter();

        Printer decorated = new UpperCasePrinterDecorator(
                new AddAsterisksPrinterDecorator(simplePrinter)
        );
        decorated.print("hello");   // *** HELLO ***
    }
}

interface Printer {
    void print(String msg);
}

class SimplePrinter implements Printer {
    @Override
    public void print(String msg) {
        System.out.println(msg);
    }
}

abstract class PrinterDecorator implements Printer {
    protected Printer printer;
    public PrinterDecorator(Printer printer) {
        this.printer = printer;
    }
}

class UpperCasePrinterDecorator extends PrinterDecorator {
    public UpperCasePrinterDecorator(Printer printer) {
        super(printer);
    }
    @Override
    public void print(String msg) {
        String s = msg.toUpperCase();
        this.printer.print(s);
    }
}

class AddAsterisksPrinterDecorator extends PrinterDecorator {
    public AddAsterisksPrinterDecorator(Printer printer) {
        super(printer);
    }
    @Override
    public void print(String msg) {
        msg = "*** " + msg + " ***";
        this.printer.print(msg);
    }
}

我对如何在 spring bean 的帮助下实现相同的示例感兴趣。

因为我不太明白如何在简单地包装任意数量的装饰器的能力方面保持灵活性。

因为据我所知 - 它将在一些单独的组件中固定实现,我将不得不使用我需要的装饰器组合创建数十个不同的单独组件。

我还没有真正理解您在这里的实际问题是什么,但无论如何我都会尝试。
假设你有这些课程

UpperCasePrinterDecorator
LowerCasePrinterDecorator
AddAsterisksPrinterDecorator 

每一个都需要一个Printer的实例,假设它是作为 Spring @Component 要将每个装饰器用作 Spring Bean,您需要注册它。

@Bean
@Qualifier("upperCase")
PrinterDecorator upperCasePrinterDecorator(final Printer printer) { // Injected automatically
   return new UpperCasePrinterDecorator(printer);
}

@Bean
@Qualifier("lowerCase")
PrinterDecorator lowerCasePrinterDecorator(final Printer printer) {
   return new LoweCasePrinterDecorator(printer);
}

@Bean
@Qualifier("asterisk")
PrinterDecorator addAsterisksPrinterDecorator(final Printer printer) {
   return new AddAsterisksPrinterDecorator(printer);
}

然后您可以使用@Qualifier批注来获得正确的@Autowired

@Autowired
@Qualifier("lowerCase")
private PrinterDecorator printer;

使用BeanPostProcessor 在这个例子中,我使用P6DataSource作为包装现有DataSource的装饰器。 使用这种方法,您现有的代码不会更改,因为接口保持不变并且包装类的@Autowire按预期工作。

import com.p6spy.engine.spy.P6DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import javax.sql.DataSource;

import static org.springframework.core.Ordered.LOWEST_PRECEDENCE;

@Configuration
@Order(LOWEST_PRECEDENCE)
@Slf4j
public class DataSourceBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DataSource
            && !ScopedProxyUtils.isScopedTarget(beanName)) {
            log.debug("Decorating {} with P6Spy", bean);
            return new P6DataSource((DataSource) bean);
        } else {
            return bean;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM