Java 如何制作龙眼+;Gson与Spring AOP代理一起工作

Java 如何制作龙眼+;Gson与Spring AOP代理一起工作,java,gson,spring-aop,lombok,cglib,Java,Gson,Spring Aop,Lombok,Cglib,假设有一个简单的类Student @Data @NoArgsConstructor @AllArgsConstructor public class Student { private Integer age; private String name; } 在AOP.xml中使用Spring AOP添加日志方面 <aop:config> <aop:aspect id="log" ref="logging"> <aop:poi

假设有一个简单的类
Student

@Data @NoArgsConstructor @AllArgsConstructor
public class Student {
    private Integer age;
    private String name;
}
在AOP.xml中使用Spring AOP添加日志方面

<aop:config>
    <aop:aspect id="log" ref="logging">
        <aop:pointcut id="selectAll" expression="execution(* com.tutorial.Student.getName(..))"/>
        <aop:before pointcut-ref="selectAll" method="beforeAdvice"/>
        <aop:after pointcut-ref="selectAll" method="afterAdvice"/>
    </aop:aspect>
</aop:config>
<bean id="student" class="com.tutorial.Student">
    <property name="name"  value="Zara" />
    <property name="age"  value="11"/>
</bean>

更新根据接受的答案,
取消固定
对我有效。

您可以使用@Expose annotation忽略aop字段。 例如:

Gson Gson=new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 字符串json=gson.toJson(newbook())


您可以使用@Expose annotation忽略aop字段。 例如:

Gson Gson=new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 字符串json=gson.toJson(newbook())


实施
排除策略
如:

@RequiredArgsConstructor
public class ExcludeListedClasses implements ExclusionStrategy {
    @NonNull
    private Set<Class<?>> classesToExclude;
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return false;
    }
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return classesToExclude.contains(clazz);
    }
}
@RequiredArgsConstructor
公共类ExcludeListedClass实现了排除策略{
@非空

私人设置实施
排除策略
如:

@RequiredArgsConstructor
public class ExcludeListedClasses implements ExclusionStrategy {
    @NonNull
    private Set<Class<?>> classesToExclude;
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return false;
    }
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return classesToExclude.contains(clazz);
    }
}
@RequiredArgsConstructor
公共类ExcludeListedClass实现了排除策略{
@非空

private Set您的代码似乎暗示您的方面正在工作,即在您的配置的建议得到执行之前/之后。如果它们没有工作,您在其他地方会遇到问题。我进一步假设

  • 你的相位按设计工作,你已经检查过了
  • 您使用的是Spring AOP,而不是加载时编织的AspectJ
  • 不知何故,GSON看到的是CGLIB代理,而不是下面的原始对象
那么问题可能是GSON——我对它没有任何经验,以前从未使用过它——使用反射来搜索代理类中的字段。但它不会找到任何字段,因为代理只覆盖方法,但没有字段,因为后者在原始类中(代理的父级)。如果这是真的,则需要将GSON配置为在原始类中搜索,而不是在代理类中搜索。这样,您也不必排除任何内容


更新:

我的猜测是正确的

就因为我对如何从CGLIB代理获取原始对象很好奇,我在调试器中查看了它。似乎每个代理都有一个公共final方法
getTargetSource
,您可以通过反射调用该方法:

package.com.tutorial;
导入org.springframework.aop.TargetSource;
导入org.springframework.context.ApplicationContext;
导入org.springframework.context.support.ClassPathXmlApplicationContext;
导入com.google.gson.gson;
导入com.google.gson.GsonBuilder;
公共类应用程序{
公共静态void main(字符串[]args)引发异常{
Gson Gson=new GsonBuilder().setPrettyPrinting().create();
ApplicationContext上下文=新的ClassPathXmlApplicationContext(“aop.xml”);
学生=(学生)context.getBean(“学生”);
TargetSource TargetSource=(TargetSource)
学生
.getClass()
.getMethod(“getTargetSource”,null)
.invoke(学生,空);
System.out.println(gson.toJson(targetSource.getTarget());
}
}
这对我来说适用于您的代码,但我没有在混合中使用Lombok(您根本没有提到,我只是在尝试编译您的代码时发现的!),而是手动创建构造函数、getter和setter来启动和运行

此外,您不再需要
排除策略

控制台日志:

{
“年龄”:11岁,
“姓名”:“Zara”
}
顺便说一句,由于类命名冲突,Lombok在与AspectJ的连接中会引起麻烦,请参阅。这也可能会影响Spring AOP

我认为你使用的是不健康的(因为不兼容)这里混合了多种技术,如果您找到了一个解决方案,并且不希望最终为每个bean类编写自定义类型适配器,那么这将是一个非常棘手的问题。如果您删除Lombok,至少您可以从Spring AOP切换到,以摆脱代理问题。AspectJ不使用代理,因此GSON可能会更好地使用它


更新2:

我的第一次更新只是在茶歇期间进行的一次快速黑客攻击。我不是Spring用户,我也必须先查找API文档以找到接口。它包含方法
getTargetSource()
,即:

  • 我们可以将springbean(AOP代理)强制转换为
    Advised
    ,从而避免丑陋的反射
  • 更进一步,我们可以动态地确定给定对象是否是(建议的)代理,也就是说,如果更改或停用方面,相同的代码仍然可以工作
package.com.tutorial;
导入org.springframework.aop.framework.Advised;
导入org.springframework.context.support.ClassPathXmlApplicationContext;
导入com.google.gson.gson;
导入com.google.gson.GsonBuilder;
公共类应用程序{
公共静态void main(字符串[]args)引发异常{
try(ClassPathXmlApplicationContext上下文=新的ClassPathXmlApplicationContext(“aop.xml”)){
Gson Gson=new GsonBuilder().setPrettyPrinting().create();
学生=(学生)context.getBean(“学生”);
System.out.println(gson.toJson(unProxy(student));
}
}
公共静态对象取消固定(对象对象)引发异常{
返回已通知的对象实例
((建议)对象)。getTargetSource().getTarget()
:对象;
}
}


更新3:我很好奇,还为我的IDE安装了Lombok。实际上,上面的示例与Gson和我的小
unProxy(对象)相关
方法。所以您可以开始了。
:-)

您的代码似乎暗示您的方面正在工作,即在您的配置的建议得到执行之前/之后。如果没有,您在其他地方会有问题。我进一步假设

  • 你的相位按设计工作,你已经检查过了
  • 您使用的是Spring AOP,而不是加载时编织的AspectJ
  • 不知何故,GSON看到的是CGLIB代理,而不是下面的原始对象
public class book {

    @Expose
    public String name;

    @Expose
    public int some;

    ...
}
@RequiredArgsConstructor
public class ExcludeListedClasses implements ExclusionStrategy {
    @NonNull
    private Set<Class<?>> classesToExclude;
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return false;
    }
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return classesToExclude.contains(clazz);
    }
}
ExclusionStrategy es = new ExcludeListedClasses( new HashSet<Class<?>>() {{
                add(Logging.class);
    }} );

Gson gson = new GsonBuilder().setPrettyPrinting()
                .addSerializationExclusionStrategy(es).create();