Java 添加测微计相关性会导致奇怪的Spring代理问题
我有一个带有private@Scheduled方法的简单Spring引导应用程序:Java 添加测微计相关性会导致奇怪的Spring代理问题,java,spring,proxy,aspectj,micrometer,Java,Spring,Proxy,Aspectj,Micrometer,我有一个带有private@Scheduled方法的简单Spring引导应用程序: @SpringBootApplication @EnableScheduling public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Scheduled(fixedRat
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Scheduled(fixedRate = 1000)
private void scheduledTask() {
System.out.println("Scheduled task");
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-spring-legacy</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.1.1</version>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
有人知道下面发生了什么吗
编辑:
我认为mictometer和aspectJ依赖项之间存在某种冲突,只有当两者都存在于类路径上时才会出现问题。Spring建议通常在可能的情况下使用JDK代理实现,这需要一个接口来动态实现(它执行有趣的逻辑,然后委托给您的业务代码)。在这种情况下,您有一个实际的类,因此Spring所能做的最好的事情就是将其子类化 然而,这里有两个相互冲突的需求:Spring希望应用捕获代码度量的建议,但是由于该方法是
private
,因此无法从子类访问它。(实际上,我有点惊讶于它用私有方法检测并调用您的计划任务。)
将方法更改为protected
允许Spring在运行时执行此操作(不是实际的Java代码,而是等效生成的字节码):
是的,存在冲突,或者您尝试过将私有方法的可见性更改为受保护的或公共的,但没有对依赖项进行注释。是的,更改方法可见性是可行的,但我希望避免。有可能吗?谢谢你的回复。如果我将访问级别更改为package private,它也可以正常工作-Spring是否使用与我的类相同的包创建代理类?@tutnhamon确定这一点的最佳方法是将
System.err.println(this.getClass())
放在任务方法中。我的猜测是肯定的,但关键因素是,当一个方法是私有的时,编译器知道一个事实,即它将“永远”不会从正在编译的类之外被使用,因此它可以以可能干扰子类化的特殊方式处理它。默认访问和更新意味着外部类可能需要与之交互。没错,控制台上打印的类名是“class com.example.demo.DemoApplication$$EnhancerBySpringCGLIB$$ee930494”。你能告诉我为什么在没有micrometer或aspectJ依赖项的情况下,它可以工作,Spring可以运行这个私有方法吗?@tutnhamon因为和许多Java框架一样,Spring欺骗:它使用setAccessible
来操作它不应该访问的东西,比如@PostConstruct
方法和@Autowired
字段(不要使用这些)。在Java 9及更高版本上,您通常在控制台上看到的第一件事是关于非法反射访问的警告,如果您使用严格的安全管理器,您的应用程序将无法启动。@tutnhamon这是我最好的猜测。您自己试试,看看在这种情况下是否会报告。
Caused by: java.lang.IllegalStateException: Need to invoke method 'scheduledTask' found on proxy for target class 'DemoApplication' but cannot be delegated to target bean. Switch its visibility to package or protected.
at org.springframework.aop.support.AopUtils.selectInvocableMethod(AopUtils.java:133) ~[spring-aop-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.processScheduled(ScheduledAnnotationBeanPostProcessor.java:343) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization(ScheduledAnnotationBeanPostProcessor.java:326) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:423) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1633) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
... 15 common frames omitted
class DemoApplicationWithAdvice extends DemoApplication {
@Override
protected void scheduledTask() {
// record start time
super.scheduledTask();
// write metric with execution time
}
}