`
flamezealot
  • 浏览: 20796 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

spring aop的坑

 
阅读更多

       最近在优化一个老系统,这是一个对外提供的dubbo服务,对响应时间要求很高,目前遇到的问题是到业务高峰时段,会有部分响应超时的情况出现。

       既然要优化,第一步是得分析分析时间都消耗在哪里了,于是想在服务内的方法上加切面,使用spring的stopwatch来统计每次请求中每个方法执行的时间。写好了注解和切面,把注解加到方法上,然后本地跑起来测试,启动是成功了,但是dubbo admin上查无此服务,这就尴尬了,为什么呢。

       在dubbo AnnotationBean里打断点跟了下

 

        Service service = bean.getClass().getAnnotation(Service.class);
        if (service != null) {
            ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
            serviceConfig.setRef(bean);
            if (void.class.equals(service.interfaceClass())
                    && "".equals(service.interfaceName())) {
                if (bean.getClass().getInterfaces().length > 0) {
                    serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
                } else {
                    throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
                }
            }

发现这个时候bean.getClass()得到的是xxxFacadeImpl$$EnhancerBySpringCGLIB$$f77b0d54,getInterafaces得到的是[org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised,org.springframework.cglib.proxy.Factory]。大概有些同学就疑惑了,为啥这取到的是动态代理类呢,还不是因为咱用了spring aop来搞切面,人就是用动态代理方式来实现的。。。

 

 

 public void setInterface(String interfaceName) {
        this.interfaceName = interfaceName;
        if (id == null || id.length() == 0) {
            id = interfaceName;
        }
    }

    public void setInterface(Class<?> interfaceClass) {
        if (interfaceClass != null && !interfaceClass.isInterface()) {
            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
        }
        this.interfaceClass = interfaceClass;
        setInterface(interfaceClass == null ? (String) null : interfaceClass.getName());
    }

 setInterface之后,serviceConfig的interfaceName和interfaceClass都变成了org.springframework.aop.SpringProxy,export后url是

dubbo://10.0.75.1:11601/org.springframework.aop.SpringProxy?anyhost=true&dubbo=2.5.7&generic=false&interface=org.springframework.aop.SpringProxy&methods=*&pid=14592

 

莫名喜感哈哈。看代码之后只能把这个if 给绕过去,这样export的时候interfaceName是你指定的那个,也就是在service注解里要么设置interfaceClass,要么设置interfaceName。于是这个问题解决了,服务又在dubbo admin上出现啦。

       试着调用了一下,然后看日志,发现我去,这日志怎么跟想象的不一样,少了很多,折腾了许久,在切面上加断点,发现有些加了注解的方法就是不生效,怎么办,搜索一下找找灵感吧,发现了一篇文章https://www.baeldung.com/spring-aop-vs-aspectj,这文章本来看着也觉得没什么意思,后来一不小心瞄到了一句话It’s also worth noting that in Spring AOP, aspects aren’t applied to the method called within the same class。啊啊啊啊啊,真是一语惊醒梦中人啊,让我想起了以前就有的一个印象,在使用spring框架的工程中,service里a方法调用b方法,如果b上加了事务注解而a没加,那么事务是不生效的。

       当时只是记住了这个结论,但是没有了解为啥,现在想想,动态代理是类似

 

public class proxy(){
   public void a(){
         doSomething(); 
         super.a();
         doSometing();
   }

     所以通过调用a去调用b的时候,实际不是在代理类的对象里,而是在被代理类的对象里了,也就是切面被略过了,咋办,难道我要改写spring aop吗,算了吧,想了想还是直接用aspectj吧,正好刚刚看过了spring-aop-vs-aspectj不是吗哈哈。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics