【问题标题】:Unable to apply aspects to String class无法将方面应用于 String 类
【发布时间】:2018-05-27 11:05:11
【问题描述】:

我正在试验AspectJ。我试图在 String 类上应用方面。我将 Spring 配置文件创建为:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

    <!-- Enable @AspectJ annotation support -->
    <aop:aspectj-autoproxy />

    <!-- Employee manager -->
    <bean id="employeeManager" class="com.test.advice.EmployeeManager" />

    <!-- Logging Aspect -->
    <bean id="loggingAspect" class="com.test.advice.LoggingAspect" />

    <bean id="bean1" class="java.lang.String">
        <constructor-arg value="abx" />
    </bean>

</beans>

然后是一个 Aspect 类,

package com.test.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LoggingAspect
{

    @Around("execution(* java.lang.String.*(..))")
    public void logAroundGetEmployee(ProceedingJoinPoint joinPoint) throws Throwable
    {
        System.out.println("works");
    }
}

之后创建了一个带有 main 方法的类,例如:

package com.test.advice;

package com.test.advice;

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

public class AspectJAutoProxyTest
{
    public static void main(String[] args)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Customer.xml");

        String pqr = (String) context.getBean("bean1");

        pqr.trim();

    }
}

在运行时它应该向控制台输出“works”。但它没有说,

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy5 cannot be cast to java.lang.String
    at com.test.advice.AspectJAutoProxyTest.main(AspectJAutoProxyTest.java:13)

有什么问题?我们不能将代理应用于 java.lang 对象吗?请帮忙。

【问题讨论】:

    标签: java spring aspectj aspect


    【解决方案1】:

    要使用代理对象代替真实对象,代理对象必须是真实对象的子类。 Stringfinal,JVM 不允许创建这样的子类。

    (请注意,spring 有两种代理模式;一种创建一个实际的子类,另一种只实现所有公共接口。您可能正在使用后者,但如果您更改为前者,您会在代理处看到异常创建时间)

    【讨论】:

    • 这只是问题的一小部分,并不是真正的答案。即使 String 不是最终的,它 (a) 也不是 Spring bean,因此 Spring AOP 不会注意到,(b) 即使您切换到 AspectJ 以消除此限制,您也不能通过加载时间编织到 JDK 类中weaving 因为这些类在编织代理启动之前已经加载。但是使用 AspectJ,您至少可以使用 call(* java.lang.String.*(..)) 并因此在您自己的或加载时编织的 3rd 方类中拦截调用站点。
    • 实际上,OP 确实将 String 声明为 Spring bean:&lt;bean id="bean1" class="java.lang.String"&gt;.
    • 是的。不过这并不重要,因为 execution(* java.lang.String.*(..)) 是 Spring AOP 的禁区。是的,理论上如果它不是最终的,它可以被动态代理。但这无济于事。
    • 您有什么证据表明该切入点是“禁区”?问题中显示的异常表明 Spring AOP 已决定代理 bean - Spring AOP 仅代理与切入点匹配的 bean。 (是的,我知道加载时编织不能装饰 JDK 类,但是只要它们不是最终的 JDK 类的 Spring bean,代理创建就可以正常工作)
    • 感谢您质疑我的论点并让我重新思考。关于动态代理(即 Spring AOP),您是对的。理论上,如果 String 不是最终的,它可以被代理为 String 的子类并转换回其父类。如果你运行上面的程序,你甚至有一个工作代理,它也有来自实现接口SerializableCharSequenceComparable&lt;String&gt;的所有字符串方法。 IE。如果你做((CharSequence) appContext.getBean("bean1")).subSequence(1, 3) ,这个方面就会发挥作用。所以在这种情况下,“禁区”实际上只适用于 AspectJ。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-27
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    相关资源
    最近更新 更多