Spring Aop ProxyFactoryBean и ProxyFactory и ClassCastException

Когда я использую ProxyFactoryBean чтобы получить прокси-объект, я получаю ClassCastException, но когда я использую ProxyFactory getProxy() чтобы получить объект прокси, он работает правильно. Я использую Spring 4.x.

Определение двух бобов ,WaiterTest и продавец:

public class WaiterTest {
    public void greetTo(String name){
        System.out.println("waiter greet to " + name +"...");
    }
    public void serveTo(String name){
        System.out.println("waiter serving " + name + "...");
    }
}

public class Seller {
    public void greetTo(String name){
        System.out.println("seller greet to " +name + "...");
    }
}

Определение совета:

public class GreetingBeforeAdvice implements MethodBeforeAdvice{

    public void before(Method method, Object[] args, Object obj) throws Throwable{
        System.out.println(obj.getClass().getName() + "." + method.getName());
        String clientName =(String) args[0];
        System.out.println("How are you! Mr." + clientName +".");
    }
}

Определение советника:

public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
    public boolean matches(Method method, Class clazz) {
        return "greetTo".equals(method.getName());
    }

    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class clazz) {
                return WaiterTest.class.isAssignableFrom(clazz);
            }
        };
    }
}

Тестовый класс :

   public class TestGreetingBeforeAdvisor {
        public static void main(String[] args) {
            //method one:  use by ProxyFactory
            WaiterTest targetWaiterTest = new WaiterTest();
            Seller targetSeller = new Seller();

            GreetingBeforeAdvice advice = new GreetingBeforeAdvice();
            GreetingAdvisor advisor = new GreetingAdvisor();
            advisor.setAdvice(advice);

            ProxyFactory pf = new ProxyFactory();
            pf.setTarget(targetWaiterTest);
            pf.addAdvisor(advisor);
            pf.setOptimize(true);
            WaiterTest proxy = (WaiterTest) pf.getProxy();
            proxy.greetTo("John");
            proxy.serveTo("Tom");

            ProxyFactory pf1 = new ProxyFactory();
            pf1.setTarget(targetSeller);
            pf1.addAdvisor(advisor);
            Seller seller = (Seller) pf1.getProxy();
            seller.greetTo("John"); 
            System.out.println("=============");


            //method two:Spring xml,use ProxyFactoryBean
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
                 WaiterTest test = (WaiterTest) ctx.getBean("waiterTest");
        test .greetTo("John");
        test .serveTo("John");
    }
 }

beans.xml:

<bean id="waiterTarget" class="com.xxx.springaop.advisor.WaiterTest"/>
    <bean id="sellerTarget" class="com.xxx.springaop.advisor.Seller"/>
    <bean id="greetingAdvice1" class="com.xxx.springaop.advisor.GreetingBeforeAdvice"/>
    <bean id="greetingAdvisor" class="com.xxx.springaop.advisor.GreetingAdvisor"
        p:advice-ref="greetingAdvice1"/>
    <bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:interceptorNames="greetingAdvisor" 
        p:proxyTargetClass="true"/>

    <bean id="waiterTest" parent="parent" p:target-ref="waiterTarget"/>
    <bean id="seller" parent="parent" p:target-ref="sellerTarget"/>

результат:

com.xxx.springaop.advisor.WaiterTest.greetTo
How are you! Mr.John.
waiter greet to John...
waiter serving Tom...
seller greet to John...
=============
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy12 cannot be cast to com.xxx.springaop.advisor.WaiterTest
    at com.xxx.springaop.advisor.TestGreetingBeforeAdvisor.main(TestGreetingBeforeAdvisor.java:48)

Суммировать:

WaiterTest proxy = (WaiterTest) pf.getProxy(); //success
WaiterTest test = (WaiterTest) ctx.getBean("waiterTest");//fail,ClassCastException

Зачем?

1 ответ

Я бы сказал, что вы не настроили "целевой" объект в своем определении ProxyFactoryBean. Прокси не может быть создан, если у него нет цели.

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

Waiter.java

public class Waiter {
    public void greetTo(String name) {
        System.out.println("waiter greet to " + name + "...");
    }

    public void serveTo(String name) {
        System.out.println("waiter serving " + name + "...");
    }
}

GreetingBeforeAdvice.java

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        String clientName = (String) args[0];
        System.out.println("How are you! Mr." + clientName + ".");
    }
}

GreetingAdvisor.java

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {

    public boolean matches(Method method, Class clazz) {
        return "greetTo".equals(method.getName());
    }

    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class clazz) {
                return Waiter.class.isAssignableFrom(clazz);
            }
        };
    }
}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="waiter" class="Waiter"/>

    <!-- Advisor Configuration -->
    <bean id="greetingAdvice" class="GreetingBeforeAdvice"/>
    <bean id="greetingAdvisor" class="GreetingAdvisor">
        <property name="advice" ref="greetingAdvice"/>
    </bean>

    <bean id="waiterProxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interceptorNames">
            <list>
                <value>greetingAdvisor</value>
            </list>
        </property>
        <property name="target" ref="waiter"/>
    </bean>
</beans>

и, наконец, App.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        final Waiter waiter = (Waiter) ctx.getBean("waiterProxyFactory");
        waiter.greetTo("Koray Tugay");
        waiter.serveTo("Koray Tugay");
    }
}

Для меня вывод с использованием Spring 4.3.12 выглядит следующим образом:

How are you! Mr.Koray Tugay.
waiter greet to Koray Tugay...
waiter serving Koray Tugay...
Другие вопросы по тегам