NutzCN Logo
问答 javassist 动态代理,如何增加aop拦截器,不生效。应该如何增加拦截器?
发布于 2274天前 作者 qq_e25320ed 3439 次浏览 复制 上一个帖子 下一个帖子
标签:

场景:
dubbo客户端调用服务端的时候使用自定义的代理tccJavassist。我在生成动态方法的地方,增加拦截器。
期望在调用该代理方法的时候,两个拦截器能生效。代码效果如同在方法中增加注解:@Aop({"compensableTransactionForNutzInterceptor","resourceCoordinatorForNutzInterceptor"})

                            Annotation nutzAopAnnot = new Annotation("org.nutz.ioc.aop.Aop", constpool);
                            ArrayMemberValue listenerArray = new ArrayMemberValue(constpool);
                            StringMemberValue stringMemberValue1 = new StringMemberValue("compensableTransactionForNutzInterceptor",constpool);
                            StringMemberValue stringMemberValue2 = new StringMemberValue("resourceCoordinatorForNutzInterceptor",constpool);
                            MemberValue[] members = new MemberValue[2];
                            members[0] = stringMemberValue1;
                            members[1] = stringMemberValue2;
                            listenerArray.setValue(members);
                            nutzAopAnnot.addMemberValue("value", listenerArray);
                            attr.addAnnotation(nutzAopAnnot);

实际上调用该方法并没有调用该拦截器。
仔细捋了一下:
dubbo调用远程客户端,是使用懒加载的方式。实际上javassist的这段代码是在远程调用的时候才执行。nutz容器和扫描早就结束。可能无法生效。
有没有办法能在该方法动态加入拦截器?

tcc-transaction 是利用spring aop:
dubbo在启动的时候会生成客户端的引用,并把它放到容器,因为tcc-transaction能正常执行拦截器。
附上生成的代理类:

public class proxy2
  implements TccClassGenerator.DC, EchoService, CapitalTradeOrderService
{
  public static Method[] methods;
  private InvocationHandler handler;

  @Aop({"compensableTransactionForNutzInterceptor", "resourceCoordinatorForNutzInterceptor"})
  @Compensable(propagation=Propagation.SUPPORTS, confirmMethod="record", cancelMethod="record", transactionContextEditor=DubboTransactionContextEditor.class)
  public String record(CapitalTradeOrderDto paramCapitalTradeOrderDto)
  {
    Object[] arrayOfObject = new Object[1];
    arrayOfObject[0] = paramCapitalTradeOrderDto;
    Object localObject = this.jdField_handler_of_type_JavaLangReflectInvocationHandler.invoke(this, jdField_methods_of_type_ArrayOfJavaLangReflectMethod[0], arrayOfObject);
    return (String)localObject;
  }

  public Object $echo(Object paramObject)
  {
    Object[] arrayOfObject = new Object[1];
    arrayOfObject[0] = paramObject;
    Object localObject = this.jdField_handler_of_type_JavaLangReflectInvocationHandler.invoke(this, jdField_methods_of_type_ArrayOfJavaLangReflectMethod[1], arrayOfObject);
    return (Object)localObject;
  }

  public proxy2()
  {
  }

  public proxy2(InvocationHandler paramInvocationHandler)
  {
    this.jdField_handler_of_type_JavaLangReflectInvocationHandler = paramInvocationHandler;
  }
}

问题:
有什么办法能让方法动态地加入nutz的拦截器?

20 回复

@Aop是否生效,取决于对象是谁创建的

这个对象很明显不是nutz创建,是dubbo创建的一个代理类。
看来这样走不通。

嗯嗯,加油^+^

nutz-integration-dubbo 插件是不是把dubbo的代码类变成nutz的一个bean?
如果使用nutz-integration-dubbo,有没有可能让动态@aop生效?

这是最后一道关了,其他问题都解决。
简单来说,就是需要在dubbo调用一个代理方法前,希望能动态添加两个拦截器。
代理类是动态生成,是生成dubbo客户端引用的时候生成。
不知道还有没有别的办法?

dubbo插件是这样操作, 首先读取配置, 生成一个工厂类, 然后再返回生成的对象

com.alibaba.dubbo.config.ReferenceConfig.createProxy(Map<String, String>)

假设createProxy 有nutz的aop能解析吗?

并不能的样子,那个是根据接口创建对象, 可以试试在org.nutz.integration.dubbo.ReferenceBean.get() 再包装一层

get就是最终生成对象的地方,可以深入看看哪里能动动手脚

ReferenceBean 是dubbo 客户端spring真正实现使用注解把dubbo的实例加入bean容器的实现类。
然后aspectj扫描到,交给spring aop,最终执行拦截器。
ReferenceBean实现FactoryBean,并实现getObject()来实现获取bean。

spring 为什么可以做到代理的方法也能被aspectj扫描到?

这两个拦截器必须要在调代理方法前调到,否则这个功能实现不了。所以还是得好好想想。
纠结,解决一个问题,另外一个又来了.

是不是spring也包了两层,因为是接口,代理起来也很容易

可能没包两层。
我想spring能实现,可能是因为bean是在spring创建bean的时候就去创建。
这个时间是在spring容器渲染完之前,而扫描可能在之后?
这个有待思考。

试一试?BeanFactory返回对象,需要aop的话只能再封装一层吧

我把这个思路试试看,也许可行

在获取到对象后使用AsmClassAgent包裹一层出现问题。
1、如果类型传接口类型报错,不支持接口。

Class<? extends T> agentClass = agent.define(cd,interfaceClazz);

2、如果获取类对象t.getClass(),handle属性在代理完后为空,远程调用的时候会报空指针。

/**
	 * 获取补偿事务代理类
	 * @author liangcz
	 * @date   2018年8月26日 下午5:33:49
	 * @return T
	 */
	public static <T> T getCompensableObj(T t,Class<? extends T> clazz){
		try {
			if(t == null){
				return null;
			}
			
		    Ioc ioc = getIoc();
		    CompensableTransactionForNutzInterceptor compensableTransactionForNutzInterceptor = ioc.get(CompensableTransactionForNutzInterceptor.class,"compensableTransactionForNutzInterceptor");
		    ResourceCoordinatorForNutzInterceptor resourceCoordinatorForNutzInterceptor = ioc.get(ResourceCoordinatorForNutzInterceptor.class,"resourceCoordinatorForNutzInterceptor");
		    if(compensableTransactionForNutzInterceptor == null || resourceCoordinatorForNutzInterceptor == null){
		    	return t;
		    }
		    
		    ClassDefiner cd = DefaultClassDefiner.defaultOne();
		    ClassAgent agent = new AsmClassAgent();
		    agent.addInterceptor(new CompensableMethodMatcher(), compensableTransactionForNutzInterceptor);
		    agent.addInterceptor(new CompensableMethodMatcher(), resourceCoordinatorForNutzInterceptor);
		   /* Class<? extends T> agentClass = agent.define(cd,clazz);
		    T agentObj = agentClass.newInstance();*/
		    Class<? extends Object> agentClass = agent.define(cd, t.getClass());
		    T agentObj = (T) agentClass.newInstance();
		    return agentObj;
		} catch (Exception e) {
			throw new RuntimeException("获取代理类失败",e);
		}
	}

@wendal 请教一下应该怎么包裹

用jdk的Proxy类来做,不需要管nutz aop了

好,我想想看怎么做

tcc-transaction nutz容器插件改好了,感谢兽兽@wendal。调试没问题后,到时候再提交上去,给其他小伙伴参考。

good,期待你的pr

添加回复
请先登陆
回到顶部