iis服务器助手广告
返回顶部
首页 > 资讯 > 精选 >SpringCloud问题实例分析
  • 364
分享到

SpringCloud问题实例分析

2023-06-29 01:06:43 364人浏览 独家记忆
摘要

这篇“SpringCloud问题实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springCloud问题实例分析”文

这篇“SpringCloud问题实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springCloud问题实例分析”文章吧。

问题1

某应用发布以后开始报数据库连接池不够用异常,日志如下:

com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 500, maxActive 500, creating 0

很明显这是数据库连接池满了,当时处于业务低峰期,所以很显然并不是由于流量突发造成的,另一种可能性是长事务导致,一般是事务中掺杂了外部网络调用,最终跟业务负责人一起排除了长事务的可能性。

还有什么可能呢?我随即想到了是不是没有释放连接导致,我跟业务负责人说了这个想法,他说这种可能性不大,连接的获取和释放都是由框架完成的,如果这块有问题早反映出来了,我想也是。

框架的确给我们带来了很大的便利性,将业务中一些重复性的工作下沉到框架中,提高了研发效率,不夸张的说有些人脱离了Spring,mybatisspringMVC这些框架,都不会写代码了。

那会是什么原因呢?我又冒出来一个想法,有没有可能是某些功能框架支持不了,所以开发绕过了框架自己实现,进而导致连接没有释放,我跟业务负责人说了这个想法以后,他说:“这个有可能,这次有个功能需要获取到数据库名,所以自己通过Connection对象获取的”,说到这儿答案大概已经出来了,一起看下这段代码:

public String getSchema(String tablename, boolean cached) throws Exception {    return this.getJdbcTemplate(tablename).getDataSource().getConnection().getCatalog();}

代码很简单通过JdbcTemplate获取DataSource,再通过DataSource获取Connection,最终通过Connection获取数据库名,就是这一行简单的代码将数据库连接耗尽,因为这里并没有释放连接的动作,之前的为什么都没有问题呢,因为普通的查询都是委派给JdbcTemplate来实现的,它内部会释放连接,找一个简单的query方法看下:

public <T> T query(PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException {        Assert.notNull(rse, "ResultSetExtractor must not be null");        this.logger.debug("Executing prepared sql query");        return this.execute(psc, new PreparedStatementCallback<T>() {            @Nullable            public T doInPreparedStatement(PreparedStatement ps) throws SQLException {                ResultSet rs = null;                Object var3;                try {                    if (pss != null) {                        pss.setValues(ps);                    }                    rs = ps.executeQuery();                    var3 = rse.extractData(rs);                } finally {                    JdbcUtils.closeResultSet(rs);                    if (pss instanceof ParameterDisposer) {                        ((ParameterDisposer)pss).cleanupParameters();                    }                }                return var3;            }        });    }
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {        Assert.notNull(psc, "PreparedStatementCreator must not be null");        Assert.notNull(action, "Callback object must not be null");        if (this.logger.isDebugEnabled()) {            String sql = getSql(psc);            this.logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));        }        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());        PreparedStatement ps = null;        Object var13;        try {            ps = psc.createPreparedStatement(con);            this.applyStatementSettings(ps);            T result = action.doInPreparedStatement(ps);            this.handleWarnings((Statement)ps);            var13 = result;        } catch (SQLException var10) {            if (psc instanceof ParameterDisposer) {                ((ParameterDisposer)psc).cleanupParameters();            }            String sql = getSql(psc);            psc = null;            JdbcUtils.closeStatement(ps);            ps = null;            DataSourceUtils.releaseConnection(con, this.getDataSource());            con = null;            throw this.translateException("PreparedStatementCallback", sql, var10);        } finally {            if (psc instanceof ParameterDisposer) {                ((ParameterDisposer)psc).cleanupParameters();            }            JdbcUtils.closeStatement(ps);            DataSourceUtils.releaseConnection(con, this.getDataSource());        }        return var13;    }

query方法基于execute这个模板方法实现,在execute内部会通过finally来确保连接的释放

DataSourceUtils.releaseConnection,所以不会有连接耗尽的问题,问题已经很清晰了,改造也很简单,大概有几下几种方法:

显示的关闭连接,这里可以借助jdk的try resource语句,简单明了。

 public String getSchema(String tablename, boolean cached) throws Exception {      try(Connection connection = this.getJdbcTemplate(tablename).getDataSource().getConnection()){                return connection.getCatalog();      }        }

借助于JdbcTemplate的模板方法设计思想来解决,它提供了一个execute方法,用户只要实现ConnectionCallback这个接口就可以获取到Connection对象,在内部执行获取数据库名的逻辑,最终关闭连接由finally完成。

@Nullablepublic <T> T execute(ConnectionCallback<T> action) throws DataAccessException {    Assert.notNull(action, "Callback object must not be null");    Connection con = DataSourceUtils.getConnection(this.obtainDataSource());    Object var10;    try {        Connection conToUse = this.createConnectionProxy(con);        var10 = action.doInConnection(conToUse);    } catch (SQLException var8) {        String sql = getSql(action);        DataSourceUtils.releaseConnection(con, this.getDataSource());        con = null;        throw this.translateException("ConnectionCallback", sql, var8);    } finally {        DataSourceUtils.releaseConnection(con, this.getDataSource());    }        return var10; }
jdbcTemplate.execute(new ConnectionCallback<Object>() {      @Override      public Object doInConnection(Connection connection) throws SQLException, DataAccessException {          return connection.getCatalog();      }});

虽然两种都能解决问题,但我还是更推崇第二种方式,因为这种更贴合框架的设计思想,将一些重复性的逻辑继续交给框架去实现,这里也体现出框架很重要的一个特点,就是对使用者提供扩展。

问题2

前几天写了一个Spring aop的拦截功能,发现怎么也进不到拦截逻辑中,表达式确定没问题,让我百思不得其解,最终冷静下来逐步排错。

第一个很明显的错误是被拦截的对象并没有纳入Spring管理,所以当即把对象交由Spring管理,问题依然没有解决,我开始回想代理的原理。

Spring代理提供了两种实现方式,一种是jdk的动态代理,另一种是cglib代理,这两种方式分别适用于代理类实现了接口和代理类未实现接口的情况,其内部思想都是基于某种规约(接口或者父类)来生成一个Proxy对象,在Proxy对象方法调用时先调用InvocationHandler的invoke方法,在invoke方法内部先执行代理逻辑,再执行被代理对象的真实逻辑,这里贴一段jdk动态代理生成的Proxy对象的源文件供大家阅读:

public class ProxyTest {       public interface ProxyT{        void hello();    }        public static class ProxyTImpl implements ProxyT{        @Override        public void hello() {            System.out.println("aaaa");        }    }    public static void main(String[] args) {        //设置生成Proxy对象的源文件        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");        ProxyT proxyT1 = (ProxyT)Proxy.newProxyInstance(ProxyT.class.getClassLoader(),new Class[]{ProxyT.class}, new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                System.out.println("invoke");                return method.invoke(proxyT,args);            }        });        proxyT1.hello();    }}

最终生成的Proxy源文件如下:

package com.sun.proxy;import coding4fun.ProxyTest.ProxyT;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements ProxyT {    private static Method m1;    private static Method m3;    private static Method m2;    private static Method m0;    public $Proxy0(InvocationHandler var1) throws  {        super(var1);    }    public final boolean equals(Object var1) throws  {        try {            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }    //hello方法将调用权交给了InvocationHandler    public final void hello() throws  {        try {            super.h.invoke(this, m3, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    public final String toString() throws  {        try {            return (String)super.h.invoke(this, m2, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    public final int hashCode() throws  {        try {            return (Integer)super.h.invoke(this, m0, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));            m3 = Class.forName("coding4fun.ProxyTest$ProxyT").getMethod("hello");            m2 = Class.forName("java.lang.Object").getMethod("toString");            m0 = Class.forName("java.lang.Object").getMethod("hashCode");        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}

到这里其实我已经有了答案,是我给Spring的规约(接口或者父类)出现了问题,首先我要代理的类并没有实现接口,所以这里的规约不是接口,而是我这个类本身,从cglib的原理来讲,它是将要代理的类作为父类来生成一个Proxy类,重写要代理的方法,进而添加代理逻辑,问题就在于我那个类的方法是static的,而static方法是没法重写的,所以导致一直没有进拦截逻辑,将static方法改为实例方法就解决了问题,这里贴一段cglib动态代理生成的Proxy对象的源文件供大家阅读:

public class cglibtest {    //定义被代理的类ProxyT,内部有一个hello方法    public static class ProxyT{        public void hello() {            System.out.println("aaaa");        }    }    //定义一个方法拦截器,和jdk的InvocationHandler类似    public static class Interceptor implements MethodInterceptor {        @Override        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {            //简单的打印            System.out.println("before invoke hello");            //执行被代理类的方法(hello)            return methodProxy.invokeSuper(o,objects);        }    }    public static void main(String[] args) {        // 设置CGLib代理类的生成位置        System.setProperty(DebugginGClassWriter.DEBUG_LOCATION_PROPERTY, "./cg");        // 设置JDK代理类的输出        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");        MethodInterceptor methodInterceptor = new Interceptor();        Enhancer enhancer = new Enhancer();        //设置父类        enhancer.setSuperclass(ProxyT.class);        //设置方法回调        enhancer.setCallback(methodInterceptor);        ProxyT proxy = (ProxyT)enhancer.create();        proxy.hello();    }}

最终生成的Proxy源文件如下(删除了部分代码,只保留了重写hello方法逻辑):

//继承ProxyTpublic class cglibtest$ProxyT$$EnhancerByCGLIB$$8b3109a3 extends ProxyT implements Factory {   final void CGLIB$hello$0() {        super.hello();    }    //重写hello方法    public final void hello() {        //方法拦截器        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }        if (var10000 != null) {            //执行方法拦截器            var10000.intercept(this, CGLIB$hello$0$Method, CGLIB$emptyArgs, CGLIB$hello$0$Proxy);        } else {            super.hello();        }    }}

以上就是关于“SpringCloud问题实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: SpringCloud问题实例分析

本文链接: https://www.lsjlt.com/news/321830.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringCloud问题实例分析
    这篇“SpringCloud问题实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“SpringCloud问题实例分析”文...
    99+
    2023-06-29
  • Oracle连接问题实例分析
    今天小编给大家分享一下Oracle连接问题实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2024-04-02
  • CSS继承问题实例分析
    本篇内容介绍了“CSS继承问题实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 根据 CSS目前的...
    99+
    2024-04-02
  • SpringCloud Alibaba框架实例应用分析
    这篇“SpringCloud Alibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spri...
    99+
    2023-07-06
  • Java算法题输入问题实例分析
    本篇内容介绍了“Java算法题输入问题实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.给定范围,确定输入几个数据直接使用普通的Sc...
    99+
    2023-06-29
  • Hibernate3.1问题举例分析
    本篇内容主要讲解“Hibernate3.1问题举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Hibernate3.1问题举例分析”吧!今天在运行一个很简单的save()方法报:Excep...
    99+
    2023-06-17
  • dom4j的XMLWrtier输出问题实例分析
    这篇文章主要介绍“dom4j的XMLWrtier输出问题实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“dom4j的XMLWrtier输出问题实例分析”文章能帮助大家解决问题。首先先说一下现象...
    99+
    2023-06-17
  • Java线程同步问题实例分析
    这篇文章主要讲解了“Java线程同步问题实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java线程同步问题实例分析”吧!1.场景有五位沉默的哲学家围坐在一张圆桌旁,他们一生都在吃东西...
    99+
    2023-06-29
  • SpringBoot循环依赖问题实例分析
    本文小编为大家详细介绍“SpringBoot循环依赖问题实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot循环依赖问题实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。简介说明本文介...
    99+
    2023-07-02
  • CRM Opportunity的删除问题实例分析
    这篇文章主要介绍“CRM Opportunity的删除问题实例分析”,在日常操作中,相信很多人在CRM Opportunity的删除问题实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CRM Oppor...
    99+
    2023-06-04
  • Java内存泄露问题实例分析
    本篇内容介绍了“Java内存泄露问题实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java内存泄露问题所谓内存泄露就是指一个不再被程...
    99+
    2023-06-29
  • mysqldump问题的示例分析
    mysqldump问题的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。导出:mysqldump数据库[表]>/t...
    99+
    2024-04-02
  • SpringCloud-Spring Boot Starter使用测试实例分析
    这篇文章主要介绍了SpringCloud-Spring Boot Starter使用测试实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud-Spring ...
    99+
    2023-07-02
  • Java表达式相关问题实例分析
    本篇内容介绍了“Java表达式相关问题实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Code Golf中的一位挑战者在比赛中写了下面...
    99+
    2023-06-02
  • SpringCloud微服务的示例分析
    这篇文章给大家分享的是有关SpringCloud微服务的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Maven规范所有项目必须要有一个统一的parent模块所有微服务工程都依赖这个parent,pare...
    99+
    2023-06-20
  • Java之springcloud Sentinel的示例分析
    小编给大家分享一下Java之springcloud Sentinel的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、Sentinel是什么?Senti...
    99+
    2023-06-20
  • Spring Boot数据响应问题实例分析
    本文小编为大家详细介绍“Spring Boot数据响应问题实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Boot数据响应问题实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习...
    99+
    2023-06-29
  • ASCII、Unicode、UTF-8编码问题实例分析
    本篇内容介绍了“ASCII、Unicode、UTF-8编码问题实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!关于编码验证以往我们可能...
    99+
    2023-06-02
  • SQL权限设置的问题实例分析
    这篇文章主要讲解了“SQL权限设置的问题实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SQL权限设置的问题实例分析”吧! 第一个是对于一个用户的操...
    99+
    2024-04-02
  • SpringCloud服务的发现与调用实例分析
    这篇文章主要介绍“SpringCloud服务的发现与调用实例分析”,在日常操作中,相信很多人在SpringCloud服务的发现与调用实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringCloud...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作