Получение ошибки при попытке использовать целевое обозначение точки в Spring AOP - PullRequest
1 голос
/ 02 мая 2020

Я пробую простой пример target указателя pointcut в Spring AOP

Но я не уверен, чего мне здесь не хватает. Столкнувшись с ошибкой ниже.

BeanNotOfRequiredTypeException: ожидается, что bean-компонент с именем 'fooDao' имеет тип 'com.opensource.kms.FooDao', но на самом деле имеет тип 'com.opensource.kms. $ Proxy19 '

Класс FooDao

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";
    }
}

Класс аспектов

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");
    }
}

Класс конфигурации

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();

Может ли кто-нибудь помочь мне здесь, не уверен, какие шаги мне нужно обновить в приведенном выше коде, чтобы используйте целевой указатель.

1 Ответ

3 голосов
/ 02 мая 2020

Spring по умолчанию использует JDK Dynami c прокси для целевых классов.

Внутри 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 - ваш целевой класс == FooDao. У него только один интерфейс BarDao.

Ссылка: https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html

Для вашего класса FooDao будет создан экземпляр прокси на основе интерфейса BarDao, поскольку он является единственным интерфейс у него есть.

Когда вы вызываете

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

В контейнере пружины не будет bean-компонента класса FooDao из-за aop proxy. Имя компонента будет таким же, потому что по умолчанию имя берется из класса. Но объект больше не будет FooDao. Это будет Spring прокси-объект, созданный из вашего интерфейса BarDao.

Поэтому, если вы измените FooDao.class -> BarDao.class, все будет в порядке:

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

Ref: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop -understanding-aop-прокси

enter image description here

...