Spring 当对象在列表中可用时,不会在对象的方法调用上触发 AOP 切入点
Spring AOP pointcut is not triggered on an Object's method call when it is available inside list
我有一个 spring 引导应用程序,其中包含一对 classes、配置 class 和如下方面。下面的例子是为了说明我面临的问题。
我有办公室 class,它有打印机列表作为使用外部 属性 文件配置创建的依赖项。每当调用 Printer.getFilename 方法时,我都想执行一个方面。它不会触发方面 If I
有打印机列表,但当我只有一个没有列表的打印机对象时它可以工作。
package com.example
public class Office {
private final List<Printer> printersList;
public Office(Printer printersList){
this.printersList = printersList;
}
public void printFiles(){
for(Printer printer: printersList)
printer.getFileName();
}
}
package com.example
public class Printer {
private deviceId;
public String getFileName(){
return "fileName";
}
}
@Configuration
public class ApplicationConfiguration{
@Bean
public Office office(){
List<Printer> printerList = new ArrayList<>();
// Adding to the list based on printer id based on some external property file configuration
printerList.add(new Printer());
printerList.add(new Printer());
return new Office(printerList);
}
}
@Aspect
@Component
public class PrinterFileNameAspect {
@Pointcut("execution(* com.example.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) {
return "Modified File Name";
}
}
我发现 beans 列表没有在 Spring 容器中注册。因此我修改了配置 class 来注册 bean
@Configuration
public class ApplicationConfiguration{
@Autowired
private GenericWebApplicationContext context;
@Bean
public Office office(){
List<Printer> printerList = new ArrayList<>();
// Adding to the list based on printer id
Printer colorPrinter = new Printer();
context.registerBean("colorPrinter", Printer.class, () -> colorPrinter);
printerList.add(colorPrinter);
Printer specialPrinter = new Printer();
context.registerBean("specialPrinter", Printer.class, () -> specialPrinter);
printerList.add(specialPrinter);
return new Office(printerList);
}
}
上述配置更改没有帮助。我想我错过了 spring aop 的基础知识。我想用打印机列表实现 spring aop,因为我无法更改列表生成逻辑(列表生成逻辑很复杂,必须是动态的)。
如何将包含Printer
class的包添加到SpringBoot应用程序class中并在@SpringBootApplication
中声明这些
@Aspect
@Component
public class PrinterAspect
{
@Around( "getFileNameJp()" )
private String returnFileName( ProceedingJoinPoint joinPoint ) throws Throwable
{
return "Modified File Name"; // This will always return this name
}
}
最后,为应用程序启用 AspectJAutoproxy
@SpringBootApplication(scanBasePackages = "com.example.*" )
@EnableAspectJAutoProxy( proxyTargetClass = true )
public class Application
{
public static void main( String[] args )
{
SpringApplication.run( Application.class, args );
}
}
您还错过了 Printer
和 Office
class 中的 @Component
。所以总而言之,你的 Office
class 应该是这样的,
@Component
public class Office
{
private final List<Printer> printer;
public Office( List<Printer> printer )
{
this.printer = printer;
}
public void printFiles()
{
// my code logic ...
// Demo logic
for( Printer printer1 : printer )
{
System.out.println( printer1.getFileName() );
}
// my code logic ...
}
}
打印机 class 应该看起来像
@Component
public class Printer
{
private int deviceId;
private String fileName;
public String getFileName()
{
// my code logic here ...
fileName = String.valueOf( System.nanoTime() ); // demo logic
return fileName;
}
}
用法应该是这样的,
@Autowired
private Office office;
@GetMapping( "/demo" )
public List<String> demo()
{
office.printFiles();
return fileNames(); // To be implemented
}
这个基于原型作用域 bean 的简单解决方案怎么样?
package de.scrum_master.spring.q61661740;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class Printer {
public String getFileName() {
return "fileName";
}
public void configureIndividually(String whatever) {
System.out.println("printer being configured individually: " + whatever);
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class Office {
private final List<Printer> printersList = new ArrayList<>();
public void addPrinter(Printer printer) {
printersList.add(printer);
}
public void printFiles() {
for (Printer printer : printersList)
System.out.println(printer.getFileName());
}
}
package de.scrum_master.spring.q61661740;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PrinterFileNameAspect {
// Package name is optional if aspect is in same name as Printer
@Pointcut("execution(* de.scrum_master.spring.q61661740.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) {
return "modified file name";
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Application {
public static void main(String[] args) {
try (ConfigurableApplicationContext appContext = SpringApplication.run(Application.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
Printer colorPrinter = appContext.getBean(Printer.class);
colorPrinter.configureIndividually("my color config");
Printer specialPrinter = appContext.getBean(Printer.class);
specialPrinter.configureIndividually("my special config");
Office office = appContext.getBean(Office.class);
office.addPrinter(colorPrinter);
office.addPrinter(specialPrinter);
office.printFiles();
}
}
现在您可以让容器负责生成 bean 实例,但您仍然可以单独配置它们。我不明白为什么在这种情况下您必须手动注册 bean。
控制台日志为:
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.8.RELEASE)
2020-05-10 15:52:24.817 INFO 10404 --- [ main] d.s.spring.q61661740.Application : Starting Application on Xander-Ultrabook with PID 10404 (C:\Users\alexa\Documents\java-src\spring-aop-playground\target\classes started by alexa in C:\Users\alexa\Documents\java-src\spring-aop-playground)
2020-05-10 15:52:24.821 INFO 10404 --- [ main] d.s.spring.q61661740.Application : No active profile set, falling back to default profiles: default
2020-05-10 15:52:25.895 INFO 10404 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2020-05-10 15:52:25.918 INFO 10404 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 17ms. Found 0 repository interfaces.
2020-05-10 15:52:26.454 INFO 10404 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$7fd151] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-10 15:52:27.148 INFO 10404 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-05-10 15:52:27.189 INFO 10404 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-05-10 15:52:27.190 INFO 10404 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.24]
2020-05-10 15:52:27.375 INFO 10404 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-05-10 15:52:27.376 INFO 10404 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2486 ms
2020-05-10 15:52:27.681 INFO 10404 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-05-10 15:52:28.005 INFO 10404 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-10 15:52:28.007 INFO 10404 --- [ main] d.s.spring.q61661740.Application : Started Application in 3.735 seconds (JVM running for 5.395)
printer being configured individually: my color config
printer being configured individually: my special config
modified file name
modified file name
2020-05-10 15:52:28.135 INFO 10404 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
我正在添加一个备选答案,因为您似乎很想学习如何使用 Spring 中介绍的新方法 GenericApplicationContext.registerBean(..)
5. 由于我不是 Spring 用户,我也想找出那是什么,并想出了这个解决方案。
同样,我提供了完整的 class 定义。它们很相似,但与我的第一个答案略有不同。具体来说,Printer
不再是原型范围的 @Component
,而是一个 POJO。不过,为了方便起见,我仍然将 Office
保留为单例组件。如果你在那里也需要多个实例,你可以随时根据需要调整代码。
现在重要的是可以解决您的问题:以编程方式注册 beans 之后,您应该通过 getBean()
从应用程序上下文中获取它们,而不仅仅是将手动创建的 POJO 实例添加到您的打印机列表中。仅当您从应用程序上下文中获取 bean 时,Spring 才负责在必要时创建 AOP 代理。
package de.scrum_master.spring.q61661740;
public class Printer {
private String deviceId;
public Printer(String deviceId) {
this.deviceId = deviceId;
}
public String getFileName() {
return deviceId + ".pdf";
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class Office {
private final List<Printer> printersList = new ArrayList<>();
public void addPrinter(Printer printer) {
printersList.add(printer);
}
public void printFiles() {
for (Printer printer : printersList)
System.out.println(printer.getFileName());
}
}
package de.scrum_master.spring.q61661740;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PrinterFileNameAspect {
// Package name is optional if aspect is in same name as Printer
@Pointcut("execution(* de.scrum_master.spring.q61661740.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) throws Throwable {
return "modified_" + pjp.proceed();
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.util.stream.Stream;
@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(Application.class)) {
// If you want to get rid of the `@SpringBootApplication` annotation, add this:
// appContext.scan(Application.class.getPackage().getName());
Office office = appContext.getBean(Office.class);
Stream
.of("colorPrinter", "specialPrinter")
.forEach(deviceID -> {
appContext.registerBean(deviceID, Printer.class, () -> new Printer(deviceID));
office.addPrinter(appContext.getBean(deviceID, Printer.class));
});
office.printFiles();
}
}
}
控制台日志如下所示(缩短):
(...)
18:20:54.169 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'office'
18:20:54.177 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'colorPrinter'
18:20:54.178 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'specialPrinter'
colorPrinter.pdf
specialPrinter.pdf
(...)
我有一个 spring 引导应用程序,其中包含一对 classes、配置 class 和如下方面。下面的例子是为了说明我面临的问题。
我有办公室 class,它有打印机列表作为使用外部 属性 文件配置创建的依赖项。每当调用 Printer.getFilename 方法时,我都想执行一个方面。它不会触发方面 If I 有打印机列表,但当我只有一个没有列表的打印机对象时它可以工作。
package com.example
public class Office {
private final List<Printer> printersList;
public Office(Printer printersList){
this.printersList = printersList;
}
public void printFiles(){
for(Printer printer: printersList)
printer.getFileName();
}
}
package com.example
public class Printer {
private deviceId;
public String getFileName(){
return "fileName";
}
}
@Configuration
public class ApplicationConfiguration{
@Bean
public Office office(){
List<Printer> printerList = new ArrayList<>();
// Adding to the list based on printer id based on some external property file configuration
printerList.add(new Printer());
printerList.add(new Printer());
return new Office(printerList);
}
}
@Aspect
@Component
public class PrinterFileNameAspect {
@Pointcut("execution(* com.example.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) {
return "Modified File Name";
}
}
我发现 beans 列表没有在 Spring 容器中注册。因此我修改了配置 class 来注册 bean
@Configuration
public class ApplicationConfiguration{
@Autowired
private GenericWebApplicationContext context;
@Bean
public Office office(){
List<Printer> printerList = new ArrayList<>();
// Adding to the list based on printer id
Printer colorPrinter = new Printer();
context.registerBean("colorPrinter", Printer.class, () -> colorPrinter);
printerList.add(colorPrinter);
Printer specialPrinter = new Printer();
context.registerBean("specialPrinter", Printer.class, () -> specialPrinter);
printerList.add(specialPrinter);
return new Office(printerList);
}
}
上述配置更改没有帮助。我想我错过了 spring aop 的基础知识。我想用打印机列表实现 spring aop,因为我无法更改列表生成逻辑(列表生成逻辑很复杂,必须是动态的)。
如何将包含Printer
class的包添加到SpringBoot应用程序class中并在@SpringBootApplication
@Aspect
@Component
public class PrinterAspect
{
@Around( "getFileNameJp()" )
private String returnFileName( ProceedingJoinPoint joinPoint ) throws Throwable
{
return "Modified File Name"; // This will always return this name
}
}
最后,为应用程序启用 AspectJAutoproxy
@SpringBootApplication(scanBasePackages = "com.example.*" )
@EnableAspectJAutoProxy( proxyTargetClass = true )
public class Application
{
public static void main( String[] args )
{
SpringApplication.run( Application.class, args );
}
}
您还错过了 Printer
和 Office
class 中的 @Component
。所以总而言之,你的 Office
class 应该是这样的,
@Component
public class Office
{
private final List<Printer> printer;
public Office( List<Printer> printer )
{
this.printer = printer;
}
public void printFiles()
{
// my code logic ...
// Demo logic
for( Printer printer1 : printer )
{
System.out.println( printer1.getFileName() );
}
// my code logic ...
}
}
打印机 class 应该看起来像
@Component
public class Printer
{
private int deviceId;
private String fileName;
public String getFileName()
{
// my code logic here ...
fileName = String.valueOf( System.nanoTime() ); // demo logic
return fileName;
}
}
用法应该是这样的,
@Autowired
private Office office;
@GetMapping( "/demo" )
public List<String> demo()
{
office.printFiles();
return fileNames(); // To be implemented
}
这个基于原型作用域 bean 的简单解决方案怎么样?
package de.scrum_master.spring.q61661740;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class Printer {
public String getFileName() {
return "fileName";
}
public void configureIndividually(String whatever) {
System.out.println("printer being configured individually: " + whatever);
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class Office {
private final List<Printer> printersList = new ArrayList<>();
public void addPrinter(Printer printer) {
printersList.add(printer);
}
public void printFiles() {
for (Printer printer : printersList)
System.out.println(printer.getFileName());
}
}
package de.scrum_master.spring.q61661740;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PrinterFileNameAspect {
// Package name is optional if aspect is in same name as Printer
@Pointcut("execution(* de.scrum_master.spring.q61661740.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) {
return "modified file name";
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Application {
public static void main(String[] args) {
try (ConfigurableApplicationContext appContext = SpringApplication.run(Application.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
Printer colorPrinter = appContext.getBean(Printer.class);
colorPrinter.configureIndividually("my color config");
Printer specialPrinter = appContext.getBean(Printer.class);
specialPrinter.configureIndividually("my special config");
Office office = appContext.getBean(Office.class);
office.addPrinter(colorPrinter);
office.addPrinter(specialPrinter);
office.printFiles();
}
}
现在您可以让容器负责生成 bean 实例,但您仍然可以单独配置它们。我不明白为什么在这种情况下您必须手动注册 bean。
控制台日志为:
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.8.RELEASE)
2020-05-10 15:52:24.817 INFO 10404 --- [ main] d.s.spring.q61661740.Application : Starting Application on Xander-Ultrabook with PID 10404 (C:\Users\alexa\Documents\java-src\spring-aop-playground\target\classes started by alexa in C:\Users\alexa\Documents\java-src\spring-aop-playground)
2020-05-10 15:52:24.821 INFO 10404 --- [ main] d.s.spring.q61661740.Application : No active profile set, falling back to default profiles: default
2020-05-10 15:52:25.895 INFO 10404 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2020-05-10 15:52:25.918 INFO 10404 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 17ms. Found 0 repository interfaces.
2020-05-10 15:52:26.454 INFO 10404 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$7fd151] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-10 15:52:27.148 INFO 10404 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-05-10 15:52:27.189 INFO 10404 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-05-10 15:52:27.190 INFO 10404 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.24]
2020-05-10 15:52:27.375 INFO 10404 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-05-10 15:52:27.376 INFO 10404 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2486 ms
2020-05-10 15:52:27.681 INFO 10404 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-05-10 15:52:28.005 INFO 10404 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-10 15:52:28.007 INFO 10404 --- [ main] d.s.spring.q61661740.Application : Started Application in 3.735 seconds (JVM running for 5.395)
printer being configured individually: my color config
printer being configured individually: my special config
modified file name
modified file name
2020-05-10 15:52:28.135 INFO 10404 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
我正在添加一个备选答案,因为您似乎很想学习如何使用 Spring 中介绍的新方法 GenericApplicationContext.registerBean(..)
5. 由于我不是 Spring 用户,我也想找出那是什么,并想出了这个解决方案。
同样,我提供了完整的 class 定义。它们很相似,但与我的第一个答案略有不同。具体来说,Printer
不再是原型范围的 @Component
,而是一个 POJO。不过,为了方便起见,我仍然将 Office
保留为单例组件。如果你在那里也需要多个实例,你可以随时根据需要调整代码。
现在重要的是可以解决您的问题:以编程方式注册 beans 之后,您应该通过 getBean()
从应用程序上下文中获取它们,而不仅仅是将手动创建的 POJO 实例添加到您的打印机列表中。仅当您从应用程序上下文中获取 bean 时,Spring 才负责在必要时创建 AOP 代理。
package de.scrum_master.spring.q61661740;
public class Printer {
private String deviceId;
public Printer(String deviceId) {
this.deviceId = deviceId;
}
public String getFileName() {
return deviceId + ".pdf";
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class Office {
private final List<Printer> printersList = new ArrayList<>();
public void addPrinter(Printer printer) {
printersList.add(printer);
}
public void printFiles() {
for (Printer printer : printersList)
System.out.println(printer.getFileName());
}
}
package de.scrum_master.spring.q61661740;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PrinterFileNameAspect {
// Package name is optional if aspect is in same name as Printer
@Pointcut("execution(* de.scrum_master.spring.q61661740.Printer.getFileName())")
private void getFileNameJp() {}
@Around("getFileNameJp()")
public String returnFileName(ProceedingJoinPoint pjp) throws Throwable {
return "modified_" + pjp.proceed();
}
}
package de.scrum_master.spring.q61661740;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.util.stream.Stream;
@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(Application.class)) {
// If you want to get rid of the `@SpringBootApplication` annotation, add this:
// appContext.scan(Application.class.getPackage().getName());
Office office = appContext.getBean(Office.class);
Stream
.of("colorPrinter", "specialPrinter")
.forEach(deviceID -> {
appContext.registerBean(deviceID, Printer.class, () -> new Printer(deviceID));
office.addPrinter(appContext.getBean(deviceID, Printer.class));
});
office.printFiles();
}
}
}
控制台日志如下所示(缩短):
(...)
18:20:54.169 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'office'
18:20:54.177 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'colorPrinter'
18:20:54.178 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'specialPrinter'
colorPrinter.pdf
specialPrinter.pdf
(...)