<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.6.2">Jekyll</generator><link href="https://liuxiong21.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://liuxiong21.github.io/" rel="alternate" type="text/html" /><updated>2018-03-10T18:28:53+08:00</updated><id>https://liuxiong21.github.io/</id><title type="html">CodeMinner</title><subtitle>刘雄的个人博客</subtitle><author><name>Xiong Liu</name></author><entry><title type="html">AtomicXX VS. AtomicXXFieldUpdater</title><link href="https://liuxiong21.github.io/2018/03/10/atmicXX-vs-AtomicXXFieldUpdater/" rel="alternate" type="text/html" title="AtomicXX VS. AtomicXXFieldUpdater" /><published>2018-03-10T00:00:00+08:00</published><updated>2018-03-10T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2018/03/10/atmicXX-vs-AtomicXXFieldUpdater</id><content type="html" xml:base="https://liuxiong21.github.io/2018/03/10/atmicXX-vs-AtomicXXFieldUpdater/">&lt;p&gt;看Netty源代码或者Druid连接池代码发现有很多地方都使用到了AtomicLongFieldUpdater这个类，如Druid里面的JdbcSqlStat，Netty里面的DefaultChannelHandlerContext。&lt;/p&gt;

&lt;p&gt;先看下面两段代码：&lt;/p&gt;

&lt;p&gt;DefaultChannelHandlerContext部分代码&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    private static final AtomicIntegerFieldUpdater&amp;lt;AbstractChannelHandlerContext&amp;gt; HANDLER_STATE_UPDATER =
           AtomicIntegerFieldUpdater.newUpdater(AbstractChannelHandlerContext.class, &quot;handlerState&quot;);

    private static final int INIT = 0;

    private volatile int handlerState = INIT;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;JdbcSqlStat类部分代码&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    private volatile long                               executeBatchSizeTotal;
    private volatile int                                executeBatchSizeMax;

    private volatile long                               executeSuccessCount;
    private volatile long                               executeSpanNanoTotal;
    private volatile long                               executeSpanNanoMax;
    private volatile int                                runningCount;
    private volatile int                                concurrentMax;
    private volatile long                               resultSetHoldTimeNano;
    private volatile long                               executeAndResultSetHoldTime;

    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    executeBatchSizeTotalUpdater                    = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;executeBatchSizeTotal&quot;);
    final static AtomicIntegerFieldUpdater&amp;lt;JdbcSqlStat&amp;gt; executeBatchSizeMaxUpdater                      = AtomicIntegerFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                               &quot;executeBatchSizeMax&quot;);

    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    executeSuccessCountUpdater                      = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;executeSuccessCount&quot;);
    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    executeSpanNanoTotalUpdater                     = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;executeSpanNanoTotal&quot;);
    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    executeSpanNanoMaxUpdater                       = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;executeSpanNanoMax&quot;);
    final static AtomicIntegerFieldUpdater&amp;lt;JdbcSqlStat&amp;gt; runningCountUpdater                             = AtomicIntegerFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                               &quot;runningCount&quot;);
    final static AtomicIntegerFieldUpdater&amp;lt;JdbcSqlStat&amp;gt; concurrentMaxUpdater                            = AtomicIntegerFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                               &quot;concurrentMax&quot;);
    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    resultSetHoldTimeNanoUpdater                    = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;resultSetHoldTimeNano&quot;);
    final static AtomicLongFieldUpdater&amp;lt;JdbcSqlStat&amp;gt;    executeAndResultSetHoldTimeUpdater              = AtomicLongFieldUpdater.newUpdater(JdbcSqlStat.class,
                                                                                                                                            &quot;executeAndResultSetHoldTime&quot;);

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对于AtomicXXFieldUpdater这种类的作用及用法不多做解释。就是为了实现对volatile字段原子操作，那么实现原子操作我们为什么不选择AtomicInteger、AtomicLong、AtomicReference这种更好理解的类呢？&lt;/p&gt;

&lt;h2 id=&quot;主要使用场景&quot;&gt;主要使用场景&lt;/h2&gt;
&lt;p&gt;大家考虑下在Netty这种系统里面会有大量的并发连接，而每一个并发连接都需要创建一个Channel,每一个Channel对应一个 ChannelPipeline，而一个ChannelPipeline对应由多个ChannelHandlerContext组成的链。这个时候就会有大量的ChannelHandlerContext实例存在，并且是长时间存活着的对象。这个时候使用AtomicXXFieldUpdater就比AtomicXX合适了。&lt;/p&gt;

&lt;h2 id=&quot;为什么&quot;&gt;为什么&lt;/h2&gt;
&lt;p&gt;因为这里多创建了一个AtomicXX对象，而在64位平台上每创建一个对象至少要花费16个Byte，如果这个数量特别大内存消耗可不小。&lt;/p&gt;</content><author><name>Xiong Liu</name></author><summary type="html">看Netty源代码或者Druid连接池代码发现有很多地方都使用到了AtomicLongFieldUpdater这个类，如Druid里面的JdbcSqlStat，Netty里面的DefaultChannelHandlerContext。</summary></entry><entry><title type="html">关于Thread的ContextClassLoader</title><link href="https://liuxiong21.github.io/2018/03/01/thread-context-classloader/" rel="alternate" type="text/html" title="关于Thread的ContextClassLoader" /><published>2018-03-01T00:00:00+08:00</published><updated>2018-03-01T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2018/03/01/thread-context-classloader</id><content type="html" xml:base="https://liuxiong21.github.io/2018/03/01/thread-context-classloader/">&lt;p&gt;看springframework源码，看到很多获取ClassLoader的地方都会使用到Thread.currentThread().getContextClassLoader()这段代码的存在，那么到底它和class.getClassLoader()有什么不一样的地方呢？&lt;/p&gt;

&lt;p&gt;先看下下面这段代码：&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  @Nullable
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}
		if (cl == null) {
			// No thread context class loader -&amp;gt; use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				try {
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
				}
			}
		}
		return cl;
	}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过上面的代码，我们可以看到Spring在获取ClassLoader的时候，会进行三次尝试，分别为当前线程的Context、当前Class以及系统的ClassLoader。那么这三种方式获取到的ClassLoader有什么不一样呢？为什么要首先从线程的上下文中获取？&lt;/p&gt;

&lt;h2 id=&quot;首先来说说java的类加载机制&quot;&gt;首先来说说Java的类加载机制&lt;/h2&gt;
&lt;p&gt;Java中的类加载器分为两种，一种是系统提供的，一种是开发人员自己提供的。&lt;br /&gt;
系统提供了三种类加载器：&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;引导类加载器（bootstrap class loader）：它用来加载 Java 的核心库，是用原生代码来实现的，并不继承自 java.lang.ClassLoader。&lt;/li&gt;
  &lt;li&gt;扩展类加载器（extensions class loader）：它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。&lt;/li&gt;
  &lt;li&gt;系统类加载器（system class loader）：它根据 Java 应用的类路径（CLASSPATH）来加载 Java 类。一般来说，Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。上面代码中最后就是采用的这个。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;大家都知道Java采用代理模式来加载class的字节码，也就是当类加载器在尝试自己去查找某个类的字节代码并定义它时，会先代理给其父类加载器，由父类加载器先去尝试加载这个类，依次类推。这种机制在大多数时候是没有问题，但是在一些特殊情况下就失效了。&lt;/p&gt;

&lt;h2 id=&quot;会遇到什么问题&quot;&gt;会遇到什么问题&lt;/h2&gt;

&lt;p&gt;比如Java提供了很多SPI，允许第三方类库定义其实现。然后这些SPI的接口都是由核心类库提供的，也就是这些类的加载是由引导类加载器加载的，而实现是由第三方实现的，引导类是无法加载到第三方库里面的类的，这个时候线程Context ClassLoader就能够解决这个问题。&lt;/p&gt;

&lt;h2 id=&quot;安全问题&quot;&gt;安全问题&lt;/h2&gt;
&lt;p&gt;除了从本地加载类以外我们还可以从网络上下载class字节数据来实现类的加载，如果不采用代理委派的方式来加载类就有可能造成Jdk里面的类被恶意修改的情况。&lt;/p&gt;

&lt;p&gt;另外默认如果不设置线程的Context ClassLoader，那么将继承其父线程的类加载器，而Java应用运行的初始线程的上下文类加载器是系统类加载器。&lt;/p&gt;</content><author><name>Xiong Liu</name></author><summary type="html">看springframework源码，看到很多获取ClassLoader的地方都会使用到Thread.currentThread().getContextClassLoader()这段代码的存在，那么到底它和class.getClassLoader()有什么不一样的地方呢？</summary></entry><entry><title type="html">SOA vs. Microservices</title><link href="https://liuxiong21.github.io/2018/02/27/soa-vs-microservices/" rel="alternate" type="text/html" title="SOA vs. Microservices" /><published>2018-02-27T00:00:00+08:00</published><updated>2018-02-27T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2018/02/27/soa-vs-microservices</id><content type="html" xml:base="https://liuxiong21.github.io/2018/02/27/soa-vs-microservices/">&lt;p&gt;大家有没有想过SOA和微服务有什么区别？它们又有什么联系吗？
答案是他们是有点相似又有很多不相似的地方，微服务其实是SOA架构的一种演变，SOA是微服务的SuperSet。&lt;/p&gt;

&lt;h2 id=&quot;什么是soa&quot;&gt;什么是SOA&lt;/h2&gt;

&lt;p&gt;Service Oriented Architecture是一种软件架构，应用组件通过通信协议为其他组件提供服务。&lt;/p&gt;

&lt;h2 id=&quot;什么是microservices&quot;&gt;什么是Microservices&lt;/h2&gt;

&lt;p&gt;微服务架构风格是把单个应用拆分成一系列小服务来开发，而一个个服务单独运行并且使用轻量级机制来通信如HTTP，REST。&lt;/p&gt;

&lt;h2 id=&quot;它们之间的区别&quot;&gt;它们之间的区别&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;关注点不同：&lt;/p&gt;

    &lt;p&gt;SOA主要关注于业务功能重用而微服务主要关注于上下文边界，也就是说在一个SOA服务里面可能包含多个不同的业务功能，而微服务风格更倾向于把一个个业务功能拆分成单独的服务。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;架构方式不一样：&lt;/p&gt;

    &lt;p&gt;微服务倾向于把一个大的单体应用按模块拆分成一个个独立的服务，而SOA架构的组成单元是一个个独立的单体应用。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;运维方式：&lt;/p&gt;

    &lt;p&gt;SOA很少关注Devops，而微服务强调Devops和持续交付。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name>Xiong Liu</name></author><summary type="html">大家有没有想过SOA和微服务有什么区别？它们又有什么联系吗？ 答案是他们是有点相似又有很多不相似的地方，微服务其实是SOA架构的一种演变，SOA是微服务的SuperSet。</summary></entry><entry><title type="html">怎样阅读一个大型项目的源代码</title><link href="https://liuxiong21.github.io/2018/02/27/how-to-read-source-code/" rel="alternate" type="text/html" title="怎样阅读一个大型项目的源代码" /><published>2018-02-27T00:00:00+08:00</published><updated>2018-02-27T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2018/02/27/how-to-read-source-code</id><content type="html" xml:base="https://liuxiong21.github.io/2018/02/27/how-to-read-source-code/">&lt;p&gt;对于像springframework这种级别的项目，怎么样才能阅读得下去它的源代码呢？有什么突破点？&lt;/p&gt;

&lt;h2 id=&quot;怎么寻找突破点&quot;&gt;怎么寻找突破点&lt;/h2&gt;

&lt;p&gt;刚工作的时候也想过要阅读一些著名项目的源代码，多次尝试都被巨量的代码给吓退。正好最近一段时间一直在阅读一些开源项目的源代码，说下我自己的体会吧。&lt;/p&gt;

&lt;p&gt;其实项目的代码量多并不可怕，只要掌握了方法其实并不难，我的阅读习惯一般是：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;首先从github上下载下来一个开源项目把开发环境准备好，保证在eclipse里面能把单元测试跑起来。&lt;/li&gt;
  &lt;li&gt;当然在阅读代码之前需要知道这个项目能干嘛，然后基于自己的好奇心寻找下手点，如对于Spring，到底ClasspathXmlApplicationContext是怎么初始化的，怎么去解析占位符、Bean怎么实例化的等等。&lt;/li&gt;
  &lt;li&gt;其实每个开源项目都有测试用例，像netty还有一个单独的maven module里面都是example，这就是下手点了，一个个单元测试或者use case跑起来，打断点调下去，当然你需要花点时间去粗略的看下相关类及源代码，最好能把class 的UML图给画出来。&lt;/li&gt;
  &lt;li&gt;最后就是要坚持下来并多想这段代码为什么要这样。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;为什么有的代码会看不下去&quot;&gt;为什么有的代码会看不下去&lt;/h2&gt;

&lt;p&gt;其实很简单，就是因为知识储备还不够，如果有了一定的知识储备在看代码过程中遇到不明白的地方，去网上查一下其实都是能搞明白的，越到后面阅读起来就越顺畅了。&lt;/p&gt;</content><author><name>Xiong Liu</name></author><summary type="html">对于像springframework这种级别的项目，怎么样才能阅读得下去它的源代码呢？有什么突破点？</summary></entry><entry><title type="html">2017年总结</title><link href="https://liuxiong21.github.io/2018/01/01/2017-summary/" rel="alternate" type="text/html" title="2017年总结" /><published>2018-01-01T00:00:00+08:00</published><updated>2018-01-01T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2018/01/01/2017-summary</id><content type="html" xml:base="https://liuxiong21.github.io/2018/01/01/2017-summary/">&lt;p&gt;由于之前自己买的Linode服务器到期后就没有继续续费也就把之前自己基于wordpress搭建的个人博客给废弃了，博客数据也丢失了，而github pages早两年前自己就配过一个，但是对于theme一直不太满意，所以搭好后写过几篇文章后就没有继续维护过。在经历了2017年一整年后对于自己的职业规划及发展想得越来越清楚了，所以我又重新开始了写博客之旅，希望能够记录下我一路走来的所思所想同时也记录下技术方面的成长轨迹。&lt;/p&gt;

&lt;h2 id=&quot;2017年经历及总结&quot;&gt;2017年经历及总结&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;过完年回来马上从YY珠海分公司提了离职，直奔深圳。离入职两年还差两个月，在YY这段时间确实学到了很多东西，单独做过系统架构，深度参与过云平台运维组的PAAS项目。也解开了之前一直在小公司里面好奇的关于大公司大型项目从系统架构开发到运维的整个过程的疑惑。之所以离开YY是我觉得我不能一直留着珠海要趁早重新回到深圳扎稳脚跟。&lt;/li&gt;
  &lt;li&gt;找了家B轮的小公司入职，待了一个月被朋友怂恿去了一家刚刚成立的公司做技术负责人。我觉得这也是一个机会吧，之前顶多就是做个组长、负责个系统架构。对于组建团队从零开始一个项目还没有参与过，觉得是个挑战也是一个不错的机会加上这边B轮的公司业务发展方向也一直在变在尝试有点看不到希望并且自己也看不太清楚公司的发展。&lt;/li&gt;
  &lt;li&gt;入职新公司技术部就我一个人，开始组建团队讨论产品，由于之前没有深度参与过APP的开发，所以恶补了下APP开发相关知识。从入职前的忐忑和不安到后来一步步组建起来了由iOS、Android、服务器、前端、数据、测试组成的技术部。一路走来也还挺顺利的。对于团队建设及用人选人方面自己之前也有过想法，并且自己也在一步步实现了自己的想法。结果还行吧，给自己打75分。&lt;/li&gt;
  &lt;li&gt;我觉得今年最大的收获当属终于找到了自己的另一半，见了双方家长，确定了结婚日期。刚工作前面几年总觉得自己年纪还小不应该这么快找个女朋友（PS:其实是在逃避对自己没信心能找到合适的女朋友），后面年龄越来越大越觉得孤单越想早点找到真爱成家，以至于导致无法全身心投入到工作及技术研究中。&lt;/li&gt;
  &lt;li&gt;个人发展由之前的看书为主变成了看开源项目为主，今年半年时间看了大大小小开源项目不少大的包括Netty、Spring。以至于后面自己对于一些开源库有疑惑的就直接拿起源代码就看了，刚工作前几年自己也尝试过看Spring的源代码，就是一直没看下去，现在想想主要还是方法问题吧，找到了方法其实发现还是挺简单的。对于2018年我还是会继续去研究一些开源项目的代码，希望到年底能够参与到一个开源项目中去。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;2018年规划&quot;&gt;2018年规划&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;领证结婚&lt;/li&gt;
  &lt;li&gt;继续深入研究一些开源项目，如Dubbo、Spring Cloud。&lt;/li&gt;
  &lt;li&gt;深入研究下分布式系统，并选择一个开源项目研究。&lt;/li&gt;
  &lt;li&gt;学习C++，开始JVM源代码的研究。&lt;/li&gt;
  &lt;li&gt;坚持写博客文章，记录关于生活、关于技术的所思所想。&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Xiong Liu</name></author><summary type="html">由于之前自己买的Linode服务器到期后就没有继续续费也就把之前自己基于wordpress搭建的个人博客给废弃了，博客数据也丢失了，而github pages早两年前自己就配过一个，但是对于theme一直不太满意，所以搭好后写过几篇文章后就没有继续维护过。在经历了2017年一整年后对于自己的职业规划及发展想得越来越清楚了，所以我又重新开始了写博客之旅，希望能够记录下我一路走来的所思所想同时也记录下技术方面的成长轨迹。</summary></entry><entry><title type="html">java里面的bridge method</title><link href="https://liuxiong21.github.io/2017/07/11/java-bridge-method/" rel="alternate" type="text/html" title="java里面的bridge method" /><published>2017-07-11T00:00:00+08:00</published><updated>2017-07-11T00:00:00+08:00</updated><id>https://liuxiong21.github.io/2017/07/11/java-bridge-method</id><content type="html" xml:base="https://liuxiong21.github.io/2017/07/11/java-bridge-method/">&lt;p&gt;看springframework源码中关于ConfigurationClassParser在解析一个配置类的时候需要扫描某一配置类申明的带有@Bean注解所有方法，然后过滤掉bridge method，然后再继续解析。之前在看Java的泛型机制的时候有看到过关于bridge method，下面来介绍下相关概念。&lt;/p&gt;

&lt;p&gt;先看下面这段代码：&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class Node&amp;lt;T&amp;gt; {

  public T data;

  public Node(T data) {
    this.data = data;
  }

  public void setData(T data) {
      System.out.println(&quot;Node.setData&quot;);
      this.data = data;
  }
}

public class MyNode extends Node&amp;lt;Integer&amp;gt; {

    public MyNode(Integer data) {
      super(data);
    }

    public void setData(Integer data) {
        System.out.println(&quot;MyNode.setData&quot;);
        super.setData(data);
    }

    public static void main(String[] args){
    		MyNode mn = new MyNode(5);
    		Node n = mn;
    		n.setData(&quot;dddd&quot;);
    		String dd = (String)n.data;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面的代码编译不会出现问题，但是当运行时n.setData(“dddd”)这行会报错，为什么呢？熟悉Java泛型的都知道Java里面泛型只是一种语法糖，编译后其实会把泛型给擦除掉，擦除后的代码相当于下面这样：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class Node {

    public Object data;

    public Node(Object data) { this.data = data; }

    public void setData(Object data) {
        System.out.println(&quot;Node.setData&quot;);
        this.data = data;
    }
}

public class MyNode extends Node {

    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println(&quot;MyNode.setData&quot;);
        super.setData(data);
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;观察发现擦除后的代码会导致MyNode的setData方法没有对Node的setData方法形成覆盖。&lt;/p&gt;

&lt;h2 id=&quot;为什么需要bridge-method&quot;&gt;为什么需要bridge method&lt;/h2&gt;
&lt;p&gt;所以对于上面这种情况，为了解决泛型擦除后保留多态的特性，Java编译器会生成synthetic方法也就是bridge method。如下：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class MyNode extends Node {

    // Bridge method generated by the compiler
    //
    public void setData(Object data) {
        setData((Integer) data);
    }

    public void setData(Integer data) {
        System.out.println(&quot;MyNode.setData&quot;);
        super.setData(data);
    }

    // ...
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;针对于上面第一段代码运行时n.setData(“dddd”)报错，大家看了上面的代码后就知道为什么了。&lt;/p&gt;

&lt;h2 id=&quot;其他生成bridge-method的情况&quot;&gt;其他生成bridge method的情况&lt;/h2&gt;
&lt;p&gt;同样，在java中子类Overriding父类方法的时候，由于返回类型可以不保持一模一样，这个时候如果不引入bridge method，则会造成方法的Overriding失效。&lt;/p&gt;</content><author><name>Xiong Liu</name></author><summary type="html">看springframework源码中关于ConfigurationClassParser在解析一个配置类的时候需要扫描某一配置类申明的带有@Bean注解所有方法，然后过滤掉bridge method，然后再继续解析。之前在看Java的泛型机制的时候有看到过关于bridge method，下面来介绍下相关概念。</summary></entry></feed>