尝试在 Spring AOP 中使用目标切入点指示符时出错

Getting error when tried to use target pointcut designator in Spring AOP

我正在尝试 target 切入点指示符的简单示例 Spring AOP

但我不确定我在这里遗漏了什么。遇到以下错误。

BeanNotOfRequiredTypeException: Bean named 'fooDao' is expected to be of type 'com.opensource.kms.FooDao' but was actually of type 'com.opensource.kms.$Proxy19'

FooDao Class

package com.opensource.kms;
import org.springframework.stereotype.Component;

interface BarDao {
    String m();
}

@Component
public class FooDao implements BarDao {   
    public String m() {
        System.out.println("implementation of m");
        return "This is return value";
    }
}

看点Class

package com.opensource.kms;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SecurityService {

    @Pointcut("target(com.opensource.kms.FooDao)")
    public void myPointCut() {}

    @Before("myPointCut()")
    public void beforeMethod() {
        System.out.println("beforeMethod");
    }
}

配置Class

package com.opensource.kms;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.opensource.kms")
public class JavaConfig {

}

MainApp Class

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
FooDao ob = ctx.getBean("fooDao", FooDao.class);
System.out.println("data -> "+ob.m());
ctx.close();

有人可以帮我解决这个问题,我不确定我需要在上面的代码中更新哪些步骤才能使用目标指示符。

Spring 默认使用 JDK 目标 class 动态代理。

在 Java 内部使用接口创建代理:

public class DebugProxy implements java.lang.reflect.InvocationHandler {

    private Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(
            obj.getClass().getClassLoader(),
            obj.getClass().getInterfaces(),
            new DebugProxy(obj));
    }

    private DebugProxy(Object obj) {
        this.obj = obj;
    }
}

这里obj是你的目标class == FooDao。它只有一个接口BarDao.

参考:https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html

对于您的 class FooDao 将基于接口 BarDao 创建代理实例,因为它是它拥有的唯一接口。

当你打电话给

FooDao ob = ctx.getBean("fooDao", FooDao.class);

由于aop代理,spring容器中不会有classFooDao的bean。 bean 的名称将相同,因为默认名称取自 class。但该对象将不再是 FooDao。它将是 spring 从您的接口 BarDao 创建的代理对象。

这就是为什么如果你改变 FooDao.class -> BarDao.class 一切都会好的:

BarDao ob = ctx.getBean("fooDao", BarDao.class);

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-understanding-aop-proxies