<file_sep>---
layout: post
title: java源码-ThreadPoolExecutor
date: 2017-08-04 16:21:00
categories:
- java
tags:
- java
- 源码
- 并发
---

我们通过源码来瞅瞅java的线程池是如何实现的。
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>

### 简单例子

先通过一个简单的例子来看看吧。

```java

public class TestThreadPoolExecutor {

	public static void main(String[] args) {
		ExecutorService executor = new ThreadPoolExecutor(1, 1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
		executor.execute(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("sssssss");
			}
		});
		executor.shutdown();
	}
}

```
* 实例化一个executor，调用execute(Runnable)方法
* 调用shutdown()方法。
* 下面我们就通过execute(Runnable)方法进入开始了解```ThreadPoolExecutor```

在了解方法前，我们先来了解下```ThreadPoolExecutor```中的一些重要的参数
* clt：高三位记录当前线程池状态，低29位记录当前线程数量
* corePoolSize：线程池核心线程数量，allowCoreThreadTimeOut(默认为false)为false且当前线程数量小于corePoolSize时，现在不会死亡。
* maximunPoolSize：线程池最大线程数量;
* keepAliveTime：线程执行玩当前任务后活着的状态; 

```java

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//29
private static final int COUNT_BITS = Integer.SIZE - 3;
////00011111111111111111111111111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
//11100000000000000000000000000000
private static final int RUNNING    = -1 << COUNT_BITS;
//0
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//00100000000000000000000000000000
private static final int STOP       =  1 << COUNT_BITS;
//01000000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;
//01100000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
//获取ctl高三位，状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }
//获取线程池数量
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

```


### execute(Runnable)方法

```java

 public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
     //得到ctl
    int c = ctl.get();
    //判断当前的worker数量是否还是小于自定义的线程池容量 (1)步
    if (workerCountOf(c) < corePoolSize) {
    	//把传入的线程添加到worker中
        if (addWorker(command, true))
            return;
        //添加不成功，得到当前的ctl（因为可能有外因导致了当前线程状态的改变，才会导致addWorker失败，所以需要重新获得ctl）
        c = ctl.get();
    }
    //当前线程池是否运行中 && 把command添加到线程队列的队尾 (2)步
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
        	//如果当前线程池中没有线程 调用addWorker方法
            addWorker(null, false);
    }
    // (3)步
    else if (!addWorker(command, false))
        reject(command);
}

```

* 主要分三步
	- 判断当前线程池中线程数量是否小于```corePoolSize```,小于则添加新的线程，添加成功直接返回
	- 判断当前是否运行中&向队列中添加线程，判断当前线程数量是否为0，为0则向线程池中添加线程
	- 如果向队列中添加线程失败，然后就尝试向线程池中添加一个新的线程，失败则调用```RejectedExecutionHandler```的方法，默认是抛出一个```RejectedExecutionException```异常

### addWorker(Runnable, boolean)

* Runnable：线程对象
* boolean：false：表示当前线程数量不能大于```maximumPoolSize```；true：表示当前线程数量不能大于```corePoolSize```

```java

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            //当前线程数量大于CAPACITY(线程池中所能添加最大值2^29-1)
            //或者线程数量大于自定义的线程最大量，也返回false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            //线程数量加一
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            //线程数量新增失败，如果当前线程状态已经改变，则需要重新判断当前线程的状态
            //如果线程状态没变，则说明线程数量变了，只需要重新新增线程数量即可
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
    	// 封装到worker中
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            //获取锁
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());
                //判断线程池当前是否是RUNNING状态
                //亦或线程池状态是SHUTDOWN&传入的线程是null
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    //判断当前线程是否已经运行
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    //把worker添加到workers中
                    workers.add(w);
                    int s = workers.size();
                    //设置largestPoolSize
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
            	//运行线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

```

* 先根据线程池的状态，把线程池数量```workercount```数量+1
* 把线程封装到```Worker```类中，然后添加到```workers```集合中
* 如果添加成功，则运行线程
* 看到这里注意到，这个运行的线程是```worker.thread```，那跟我们传入的```firstTask```有什么关系呢

### Worker

```java

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    /**
     * This class will never be serialized, but we provide a
     * serialVersionUID to suppress a javac warning.
     */
    private static final long serialVersionUID = 6138294804551838833L;

    /** Thread this worker is running in.  Null if factory fails. */
    final Thread thread;
    /** Initial task to run.  Possibly null. */
    Runnable firstTask;
    /** Per-thread task counter */
    volatile long completedTasks;

    /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }

    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }

    // Lock methods
    //
    // The value 0 represents the unlocked state.
    // The value 1 represents the locked state.

    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    public void lock()        { acquire(1); }
    public boolean tryLock()  { return tryAcquire(1); }
    public void unlock()      { release(1); }
    public boolean isLocked() { return isHeldExclusively(); }

    void interruptIfStarted() {
        Thread t;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

```
* 很明显可以看到，worker.thread是线程工厂生成的，传入的是worker本身这个Runnable对象
* 所以```t.start()```运行的是worker中的run()方法，也就是```runWorker(this)```方法

### runWorker(this)

```java

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;	//	辅助gc
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
    	// 如果线程task不为空，说明是新增加的线程
    	// 当然task为空不代表，这个线程就一定不是新添加的线程
    	// 如果task为空，则通过getTask()方法尝试获取task
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            // 如果线程正在停止或已经停止，则interrupt当前线程
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                	// 运行线程，也就是firstTask，也就是传入的线程
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

```

* 如果传入的```Worker```的firstTask不为空，则直接运行这个task
* 如果为空，则通过```getTask()```方法获取task。
* 然后里面会有两个钩子方法```beforeExecute```和```afterExecute```方法

### getTask()

```java

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        //判断当前线程是否shutdown
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        // 判断从队列中获取task时使用poll还是take
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        // 线程数量大于maximumPoolSize || 已经获取超时过
        // 线程队列为空
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 线程数量减一，返回null，关闭当前线程
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
        	//获取线程
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

```

* 这个方法的作用其实就是从线程队列中获取线程。

### 总结

* 看到这里，线程池的总体流程就出来了。
1. 通过入口execute调用方法
2. 判断当前线程池中的总线程数量是否小于```corePoolSize```，小于则直接添加一个线程worker1；大于则把runnable添加到队列中，如果添加到队列失败，则会想线程池中添加非核心线程，但是线程数量不能大于```maximumPoolSize```和```CAPACITY```
3. 如果worker1运行完firstTask，则会继续从线程池中获取task。获取线程时，使用take还是poll根据```allowCoreThreadTimeOut```和```wc > corePoolSize```来确定，超时时间根据```keepAliveTime```来确定
4. 如果线程队列为空，并且已经超时，则关闭当前worker1。如果```timed```为false的话，则worker1不会关闭。

### Executors.newCachedThreadPool()

```java

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
```

* corePoolSize:0 核心线程为0，表示当线程队列为空时，所有的线程都会关闭
* maximumPoolSize:Integer.MAX_VALUE 最大的线程数量，其实```CAPACITY```比这个还小
* keepAliveTime:60 线程从队列中获取task的超时时间，超时后关闭当前线程
* 线程队列采用```SynchronousQueue```
	- SynchronousQueue有个特点：没有数据缓冲，生产者线程对其的插入操作put必须等待消费者的移除操作take。
	- 所以第一次execute(Runnable)调用时，会运行到(3)步；如果运行完firstTask，在60秒内又调用execute(Runnable)，则会运行(2)步

### Executors.newFixedThreadPool(int nThreads)

```java

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}


```

* corePoolSize：nThreads，核心线程数为设置值
* maximumPoolSize：nThreads，最大线程数也为设置值，maximumPoolSize与corePoolSize一样大，所以```timed```永远都是false，除非主动的设置```allowCoreThreadTimeOut```的值，所以getTask()时队列获取task时采用的是take()，获取不到会一直阻塞；而且线程也不会自动关闭。
* keepAliveTime：0，
* 线程队列采用```LinkedBlockingQueue```

<file_sep>---
layout: post
title: docker简单mysql主备
date: 2019-12-10 23:00:00
categories:
- mysql
- docker
tags:
- docker
- mysql
---

以下例子的mysql版本为5.7

docker官网下载docker for mac然后直接安装。下载地址自行百度\google

#### 拉取mysql5.7

```
docker pull mysql:5.7

```

#### 配置mysql的master、slave的my.cnf

##### 配置目录

* master
    * conf
        * my.cnf
    * logs
    * data
* slave
    * conf
        * my.cnf
    * logs
    * data

##### my.cnf

master的my.cnf

```
[mysqld]
#skip-grant-tables
character_set_server=utf8
server_id=1
log_bin=mysql-bin
```

slave的my.cnf

```
[mysqld]
#skip-grant-tables
character_set_server=utf8
server_id=2
log_bin=mysql-slave-bin
relay_log=edu-mysql-relay-bin
```

#### 启动mysql

```
//master目录下
docker run -p 3306:3306 --name mysql_master -v $PWD/conf/my.cnf:/etc/mysql/my.cnf -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=<PASSWORD> -d mysql:5.7


//slave目录下
docker run -p 3307:3306 --name mysql_slave -v $PWD/conf/my.cnf:/etc/mysql/my.cnf -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=<PASSWORD> -d mysql:5.7

```

#### master配置

新建一个主备账户，并且记录当前master的status

```
grant replication slave on *.* to 'testSlave'@'%' identified by 'testSlave';
flush privileges;

show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      594 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
//记录File和Positoin

```

#### slave配置

获取master容器的ip,假如是：172.17.0.2

```
docker inspect mysql_master | grep IPAddress

```

配置slave

```

CHANGE MASTER TO
MASTER_HOST='172.17.0.2',
MASTER_USER='testSlave',
MASTER_PASSWORD='<PASSWORD>',
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=594;

start slave;

```
查看slave的status

```
show slave status\G;

```

如下显示，则表示配置成功

```
Slave_IO_State: Waiting for master to send event
.
.
.
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.
.
.

```

#### 测试

进入master容器，新建数据库

```
docker exec -it mysql_master bash;
mysql -uroot -p123456;
create database canal_sync;

```

查看slave容器内的数据库，可以看到已经有了canal_sync数据库

<file_sep>---
layout: post
title: spring源码-spring初始化时bean的生成
date: 2017-09-05 16:21:00
categories:
- java
- spring
tags:
- spring
- java
- 源码
---

在spring中，我们可以通过xml或注解的方式去配置一个bean，配置好后，在spring启动的时候，spring会根据配置的属性去实例化这个bean，有可能是单例的，也有可能是多例的。
这里不会对spring如何收集bean属性做过多的说明，前面有一篇博文已经对xml的bean属性解析做过说明了，这里主要想要聊得还是spring在启动的时候，是如何生成一个个的bean对象的。

### getBean方法

* 通过跟踪spring的源码，会发现bean对象都是通过```AbstractBeanFactory.getBean(参数)```方法来生成的。
* ```AbstractBeanFactory.getBean(参数)```方法实际上会去调用```doGetBean(参数)```方法。

### doGetBean方法

```java

protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
    //获取实际的beanName，去除beanFactory的&，根据alias获取实际的beanId
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //获取单例对象
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //当前类是factoryBean对象，则通过其生成对象
        //如果是普通对象，则直接返回
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        //判断多例类型的对象是否正在创建，显然可以看出，非单例如果有循环依赖的话，会直接抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        //获取父的beanFactory，如果存在，而且当前没有beanName的定义，则从父的beanFactory中获取对象
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        //标记bean的创建
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            //获取beanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            //检查当前要创建对象是否是abstract
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            String[] dependsOn = mbd.getDependsOn();
            //为depend-on依赖创建对象，递归调用getBean
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    registerDependentBean(dep, beanName);
                    getBean(dep);
                }
            }

            // Create bean instance.
            //单例的方式创建对象
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            //多例的方式创建对象
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            //其他方式创建对象
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

```

1. 根据传入的beanName获取实际的name
    * factoryBean如果是以&开头，则去除它
    * 如果传入的是一个alias，则会返回其实际的beanId
2. 根据beanName获取单例对象（此对象有可能是提早暴露出来的对象），如果对象存在，则返回它。
3. 会判断当前对象是否正以非单例的方式创建，这里说明如果有循环依赖存在，且循环依赖的对象还是多例的，则会抛出异常
4. 获取父beanFactory
5. 标记对象正在创建
6. 根据对象scope进行对象的实际创建工作

#### transformedBeanName(name)

```java

protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

//去除开始的&符号
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}

//根据别名获取beanid
public String canonicalName(String name) {
    String canonicalName = name;

    String resolvedName;
    do {
        resolvedName = (String)this.aliasMap.get(canonicalName);
        if(resolvedName != null) {
            canonicalName = resolvedName;
        }
    } while(resolvedName != null);

    return canonicalName;
}

```
1. 如果beanName是以&开头，则去除&，有&表示```getBean()```获取factoryBean对象，并不是获取factoryBean生成的对象
2. 如果传入的是alias，则获取其实际的beanId

#### getSingleton(beanName)

```java

public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
}

//allowEarlyReference表示是否可以获取过早暴露(还未创建完成)的单例对象
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

```
1. 如果单例对象已经创建成功的话，这个方法会返回一个单例对象
2. 这个方法对于解决单例对象的循环依赖起到了很好的作用，具体在这就不讨论了，有兴趣的可以看看我下面贴出的链接！！

#### getObjectForBeanInstance

```java

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    //判断以&开头 且不是factorybean
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    //不是beanFactory对象亦或以&开头的对象 直接返回
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd == null) {
        //从缓存中获取
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
            //合并属性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //通过factoryBean生成对象并放入缓存
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
        //单例模式下factoryBean生成对象逻辑
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                //通过factory生成对象
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    if (object != null && shouldPostProcess) {
                        try {
                            //调用beanProcess的after处理方法
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

    Object object;
    try {
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                            return factory.getObject();
                        }
                    }, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            object = factory.getObject();//通过factoryBean生成对象
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    return object;
}

```

1. 如果是factoryBean且beanName不以&开头，则通过factoryBean生成对象，并且返回。
2. 如果是普通bean则直接返回

#### 获取单例对象 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

```java

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    synchronized (this.singletonObjects) {
        //如果单例对象已经存在则，直接返回
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //判断当前单例是否正在创建
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            //向集合singletonsCurrentlyInCreation中添加值
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                //通过ObjectFactory获取单例对象，实际的处理方法是上层的createBean(beanName, ex1, args)方法
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                //把生成的对象添加到缓存中
                addSingleton(beanName, singletonObject);
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

```

1. 首先从缓存中获取单例对象，存在则直接返回
2. 调用ObjectFactory的方法获取单例对象
3. 把获取的单例对象添加到缓存中

### 正式创建bean对象 createBean(String beanName, RootBeanDefinition mbd, Object[] args)

```java

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    try {
        //主要标记一下有没有方法增强
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        //给beanPostProcessors一个机会返回一个代理类
        //内部会调用InstantiationAwareBeanPostProcessor类的方法
        //aop处理类实现了此接口
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

```

1. 保证beanName能正确的解析成class
2. 标记一下当前方法有没有增强方法
3. 给beanPostProcessors一个机会，一旦其返回一个对象，则直接使用这个对象；其调用的是```InstantiationAwareBeanPostProcessor```接口类的方法；而aop的处理器则是实现的这个接口的子类```SmartInstantiationAwareBeanPostProcessor```。
4. 如果beanPostProcessors没有返回对象，则走正常的创建bean的流程，把创建的工作交给```doCreateBean(beanName, mbdToUse, args)```方法

#### doCreateBean(beanName, mbdToUse, args)

```java

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //创建bean的包装类
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                //调用MergedBeanDefinitionPostProcessor处理器
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    //判断是不是需要提早暴露对象，主要用于处理循环依赖
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                return getEarlyBeanReference(beanName, mbd, bean);
            }
        });
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        //填装属性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            //初始化对象
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }

    //这主要做一个循环依赖的检测，检测循环依赖的对象是否相同
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName,
                            "Bean with name '" + beanName + "' has been injected into other beans [" +
                            StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                            "] in its raw version as part of a circular reference, but has eventually been " +
                            "wrapped. This means that said other beans do not use the final version of the " +
                            "bean. This is often the result of over-eager type matching - consider using " +
                            "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

```
1. 生成bean的包装类对象
2. 调用MergedBeanDefinitionPostProcessor处理器的postProcessMergedBeanDefinition方法
3. 单例模式下提早的暴露当前对象，用于处理循环依赖问题
4. 填装属性，如果内部属性也是一个对象，则会递归调用getBean，所以有可能会存在循环依赖的问题
5. 单例模式下做一个循环依赖对象的检测，检测循环依赖的对象是否相同

#### createBeanInstance

```java

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // Need to determine the constructor...
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

```
1. 如果是factoryBean则委托```instantiateUsingFactoryMethod(beanName, mbd, args)```方法来创建对象
2. 如果构造方法上有autowire注解，则委托```autowireConstructor(beanName, mbd, null, null)```方法来创建对象
3. 最后使用```instantiateBean(beanName, mbd)```来创建对象，即constructor.newInstance();

#### addSingletonFactory

```java

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

```

1. 内部主要有两个中间集合```singletonFactories```：用于存储beanName和ObjectFactory关系。```earlySingletonObjects```：用于存储提早暴露出来的对象。两个集合在单例对象正式生成后都会被清空。
2. 此方法主要用于解决单例对象的循环依赖

#### populateBean

```java

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    PropertyValues pvs = mbd.getPropertyValues();

    if (bw == null) {
        if (!pvs.isEmpty()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }

    if (!continueWithPropertyPopulation) {
        return;
    }

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

        // Add property values based on autowire by name if applicable.
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }

        // Add property values based on autowire by type if applicable.
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }

        pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }

    applyPropertyValues(beanName, mbd, bw, pvs);
}

```

1. 先调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法，如果返回false，则跳过属性的自动填充
2. 对象的填充会递归调用getBean方法

#### initializeBean

```java

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        //设置aware属性
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //调用beanProcessor.postProcessBeforeInitialization(result, beanName);
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //调用初始化方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        //调用beanProcessor.postProcessAfterInitialization(result, beanName);
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
            throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            //调用afterPropertiesSet方法
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null) {
        //调用init-method方法
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

```
1. 为Aware类自动装配属性
2. 调用初始化的方法



### 总结

这里主要针对的是spring bean对象的初始化，关于方法的增强，比如aop会通过beanPostProcessor生成代理类等待这里都没有细说。
spring循环依赖的问题可以参考下面的链接：[Spring中循环引用的处理](https://www.iflym.com/index.php/code/201208280001.html"Spring中循环引用的处理")


参考：
1. [i flym 博客](https://www.iflym.com/"i flym 博客")
2. [Spring源码深度解析 郝佳]

<file_sep>---
layout: post
title: spring的event事件
date: 2017-08-04 16:21:00
categories:
- java
- spring
tags:
- spring
- java
---


先来看个简单的spring事件监听的例子

```java

@Component
public class TestListener implements ApplicationListener<TestEvent> {

	@Override
	public void onApplicationEvent(TestEvent event) {
		// TODO Auto-generated method stub
		String name = event.getName() ;
		System.out.println("name= " + name);
	}


}

public class TestEvent extends ApplicationEvent {
	
	private String name ;

	public TestEvent(String source) {
		super(source);
		this.name = source ;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

}

public class TestMain {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/dispatcherServlet-servlet.xml");  
		ctx.publishEvent(new TestEvent("111111"));
	}
}

```

运行结果：<br />
> name= 111111

* 调用了```ApplicationContext.publishEvent()```方法后，```listener```中的方法就会被自动调用。
* 那么具体是怎么调用的呢？我们进入```ApplicationContext.publishEvent()```方法看看是怎么实现的

```java

@Override
public void publishEvent(ApplicationEvent event) {
	Assert.notNull(event, "Event must not be null");
	if (logger.isTraceEnabled()) {
		logger.trace("Publishing event in " + getDisplayName() + ": " + event);
	}
	getApplicationEventMulticaster().multicastEvent(event);
	if (this.parent != null) {
		this.parent.publishEvent(event);
	}
}

```
* 实际上```ApplicationContext```类中并没有```publishEvent```方法，这个方法是在其父类中```AbstractApplicationContext```实现的
* 实际上处理是委托给```SimpleApplicationEventMulticaster```的```multicastEvent```方法

```java

@Override
public void multicastEvent(final ApplicationEvent event) {
	for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
		Executor executor = getTaskExecutor();
		if (executor != null) {
			executor.execute(new Runnable() {
				@Override
				public void run() {
					invokeListener(listener, event);
				}
			});
		}
		else {
			invokeListener(listener, event);
		}
	}
}

@SuppressWarnings({"unchecked", "rawtypes"})
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
	ErrorHandler errorHandler = getErrorHandler();
	if (errorHandler != null) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (Throwable err) {
			errorHandler.handleError(err);
		}
	}
	else {
		listener.onApplicationEvent(event);
	}
}

```

* 先获取所有event的的listener，如果listener实现了ordered接口，spring会先排序。
* 然后遍历listener，循环调用listener的onApplicationEvent方法。
* 这是一个非常典型的观察者模式。
	- ```ApplicationEvent```：发布事件实体
	- ```ApplicationListener```：监听事件
	- ```ApplicationContext.publishEvent()```方法：发布事件

<br/>

***

<br/>

* 细心的朋友能看到在```multicastEvent```方法中调用的时候分两种情况，一个是同异步调用，但是需要一个```executor```类，一中是同步调用。
* 那么这个```executor```在什么时候设置的呢？
* 看过spring初始化源码的朋友都清楚spring会调用```AbstractApplicationContext```的```refresh()```方法
* ```refresh()```方法内会调用一个```initApplicationEventMulticaster```方法。代码如下：

```java

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// 这里我们只需要关注这个方法
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}
	}
}

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isDebugEnabled()) {
			logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isDebugEnabled()) {
			logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
					APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
					"': using default [" + this.applicationEventMulticaster + "]");
		}
	}
}

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

```

* 首先会去判断是否已经有了名称为```applicationEventMulticaster```的自定义对象。
* 如果有则使用自定义的，没有则使用系统默认的```SimpleApplicationEventMulticaster```类。
* 那么现在就很清楚了，如果我们要设置```executor```，可以实现自己的```SimpleApplicationEventMulticaster```，如下：

```java

@Component("applicationEventMulticaster")
public class MySimpleApplicationEventMulticaster extends SimpleApplicationEventMulticaster {

	public MySimpleApplicationEventMulticaster() {
		setTaskExecutor(Executors.newCachedThreadPool());
	}
}

```
* 这样spring在使用事件监听的时候，就会采用异步的方式去处理。
* 这里有个问题需要注意的：
	- 如果有多个listener监听同一个event，并实现了ordered(排序)接口；处理顺序在前面的listener抛出异常的话，如果当前采用的是异步方式，那么后面的listener还会调用；如果采用的是同步方式，那么后面的listener就不会调用了。
	- 代码如下：

```java

@Component("applicationEventMulticaster")
public class MySimpleApplicationEventMulticaster extends SimpleApplicationEventMulticaster {

	public MySimpleApplicationEventMulticaster() {
		setTaskExecutor(Executors.newCachedThreadPool());
	}
}

@Component
public class TestListener implements ApplicationListener<TestEvent>, Ordered {

	@Override
	public void onApplicationEvent(TestEvent event) {
		// TODO Auto-generated method stub
		String name = event.getName() ;
		System.out.println("name= " + name);
		throw new RuntimeException("RuntimeException") ;
	}

	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return 1;
	}


}

@Component
public class TestListener2 implements ApplicationListener<TestEvent>, Ordered {

	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return 2;
	}

	@Override
	public void onApplicationEvent(TestEvent event) {
		// TODO Auto-generated method stub
		String name = event.getName() ;
		System.out.println("name2= " + name);
	}

}

```
* 最终运行结果如下：<br/>

>name= 111111<br/>
>name2= 111111<br/>
>Exception in thread "pool-1-thread-1" java.lang.RuntimeException: RuntimeException<br/>
>	at com.wgq.spring.source.event.TestListener.onApplicationEvent(TestListener.java:15)<br/>
>	at com.wgq.spring.source.event.TestListener.onApplicationEvent(TestListener.java:1)<br/>
>	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)<br/>
>	at org.springframework.context.event.SimpleApplicationEventMulticaster$1.run(SimpleApplicationEventMulticaster.java:123)<br/>
>	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)<br/>
>	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)<br/>
>	at java.lang.Thread.run(Thread.java:745)<br/>

<br/>

***

<br/>

```SimpleApplicationEventMulticaster```类中还有一个```errorHandler```的属性，如果我们想处理listener抛出的异常的话，那么可以在实现自己的```MySimpleApplicationEventMulticaster```的时候，同理的也设置一个```errorHandler```属性即可。
<file_sep>---
layout: post
title: 初识dubbo
date: 2017-09-11 15:21:00
categories:
- rpc
tags:
- dubbo
- rpc
---

<p>dubbo是一个分布式、高性能、透明化的RPC服务框架，提供服务自动注册、自动发现等高效的服务治理方案。</p>
官网地址：[Dubbo](http://dubbo.io/"Dubbo")

<p>核心包括：</p>
* 远程通讯: 提供对多种基于长连接的NIO框架抽象封装，包括多种线程模型，序列化，以及“请求-响应”模式的信息交换方式。
* 集群容错: 提供基于接口方法的透明远程过程调用，包括多协议支持，以及软负载均衡，失败容错，地址路由，动态配置等集群支持
* 自动发现: 基于注册中心目录服务，使服务消费方能动态的查找服务提供方，使地址透明，使服务提供方可以平滑增加或减少机器。

<p>Dubbo能做什么？</p>
* 透明化的远程方法调用，就像调用本地方法一样调用远程方法，只需简单配置，没有任何API侵入。
* 软负载均衡及容错机制，可在内网替代F5等硬件负载均衡器，降低成本，减少单点。
* 服务自动注册与发现，不再需要写死服务提供方地址，注册中心基于接口名查询服务提供者的IP地址，并且能够平滑添加或删除服务提供者。

<p>Dubbo提供了四种注册中心：redis、zookeeper、Multicast、simple。redis和zookeeper可用于生产；simple则想当于新建了一个项目作为注册中心，如果想要已集群的方式运行需要自行扩展；Multicast一般用于测试。</p>
* 如果使用redis作为注册中心的话，redis是通过心跳检测的方式检测脏数据，所以对服务器会有一定的压力
* zookeeper有临时节点和watch机制，相比redis的话，对服务器压力更小，个人认为更适合作为注册中心。

### 单台机器搭建zookeeper伪集群


1. 首先，zookeeper官网下载zookeeper最新版本[下载地址](http://www.apache.org/dyn/closer.cgi/zookeeper/"下载地址")
2. 分别解压到server0、server1、server2三个目录下（zookeeper集群内节点一般推荐奇数个，这里3个），然后分别新建data、logs目录，并在data目录下新建myid文件，结构如下：<br />

```
.
├── server0
│   ├── data
│   ├── logs
│   └── zookeeper-3.4.9
├── server1
│   ├── data
│   ├── logs
│   └── zookeeper-3.4.9
└── server2
    ├── data
    ├── logs
    └── zookeeper-3.4.9

```

3. 三个server的/zookeeper/conf/目录下分别新建zoo.cfg，内容如下：<br />

```
#server0/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/wgq/zkGroup/server0/data
dataLogDir=/home/wgq/zkGroup/server0/logs
clientPort=2181
server.0=127.0.0.1:2888:3888
server.1=127.0.0.1:2889:3889
server.2=127.0.0.1:2890:3890

#server1/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/wgq/zkGroup/server1/data
dataLogDir=/home/wgq/zkGroup/server1/logs
clientPort=2182
server.0=127.0.0.1:2888:3888
server.1=127.0.0.1:2889:3889
server.2=127.0.0.1:2890:3890

#server2/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/wgq/zkGroup/server2/data
dataLogDir=/home/wgq/zkGroup/server2/logs
clientPort=2183
server.0=127.0.0.1:2888:3888
server.1=127.0.0.1:2889:3889
server.2=127.0.0.1:2890:3890


#如果是部署在不同机器上的话，配置文件可能是这样的
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/wgq/zkGroup/server/data
dataLogDir=/home/wgq/zkGroup/server/logs
clientPort=2181
server.0=192.168.1.1:2888:3888
server.1=192.168.1.2:2888:3888
server.2=192.168.1.3:2888:3888

```
* clientPort表示zookeeper节点的端口，如果部署在不同的机器上可以相同
* server.myid 这里的myid就是data目录下myid文件的值，server0/data/myid=0，对应server.0
* server.0=127.0.0.1:2888:3888，3888表示推举lead时候需要使用的端口，需要同2888不一样
4. 分别调用zkServer.sh start启动服务，启动后可通过zkServer.sh status观看服务状态，如下表示没有问题。

```

[wgq@localhost zookeeper-3.4.9]$ ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/wgq/zkGroup/server0/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower

```

### 服务提供者-provider


* 通过spring-boot新建一个maven项目，pom.xml、dubbo等关键配置和类如下

```xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>mydubbo</groupId>
    <artifactId>com.wgq.dubbo.product</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test </artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.8</version>
        </dependency>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.3</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <mainClass>com.wgq.dubbo.product.AppClass</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

```
* application.properties

```

server.port=8080

```

* dubbo.properties

```

#服务名称
dubbo.application.name=mydubbo
##dubbo zookeeper config
dubbo.registry.address=zookeeper://192.168.110.65:2181?backup=192.168.110.65:2182,192.168.110.65:2183
dubbo.registry.client=zkclient
dubbo.registry.group=dubbo
##dubbo 协议
dubbo.service.protocol=dubbo
dubbo.protocol.dubbo.port=20880
## 关闭服务启动时检查
dubbo.consumer.check=false

```

* application-dubbo.xml

```xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:provider delay="-1" />

    <dubbo:service interface="com.wgq.dubbo.product.service.HelloWordService" ref="helloWordService"></dubbo:service>

</beans>

```

* spring-boot程序入口AppClass

```java

package com.wgq.dubbo.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource(
        "classpath:application-main.xml"
)
public class AppClass {
    public static void main(String[] args) {
        SpringApplication.run(AppClass.class, args) ;
    }
}

```

* 因为dubbo的接口一般都是独立的项目，打成一个jar包提供给服务端和消费端分别使用的，但是这里我们为了测试方便，紧紧是分别在服务端和消费端新建了两个包和类名相同的接口，接口如下：

```java

//
package com.wgq.dubbo.product.service;


public interface HelloWordService {
    String helloWord() ;
}

//HelloWordServiceImpl
package com.wgq.dubbo.product.service.impl;

import com.wgq.dubbo.product.service.HelloWordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class HelloWordServiceImpl implements HelloWordService {

    private static Logger LOGGER = LoggerFactory.getLogger(HelloWordServiceImpl.class) ;

    public String helloWord() {

        return "product1" ;
    }
}

```

### 服务消费者-consumer

* 服务消费者的pom.xml文件的依赖和插件同服务提供者是一样的。
* dubbo.properties

```

dubbo.application.name=mydubbo
##dubbo zookeeper config
dubbo.registry.address=zookeeper://192.168.110.65:2181?backup=192.168.110.65:2182,192.168.110.65:2183
dubbo.registry.client=zkclient
dubbo.registry.group=dubbo

```
* application.properties

```

server.port=8084

```

* AppClass

```

@SpringBootApplication
@ImportResource(
        "classpath:application-main.xml"
)
public class AppClass {
    public static void main(String[] args) {
        SpringApplication.run(AppClass.class, args) ;
    }
}


```

* application-dubbo.xml

```xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">


    <dubbo:consumer></dubbo:consumer>
    
    <dubbo:reference interface="com.wgq.dubbo.product.service.HelloWordService" id="helloWordService"></dubbo:reference>

</beans>

```
* ConsumerController

```

package com.wgq.dubbo.consumer.controller;

import com.wgq.dubbo.product.service.HelloWordService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

@Controller
@RequestMapping("/consumer")
public class ConsumerController {

    @Resource(name = "helloWordService")
    private HelloWordService helloWordServiceImpl ;

    @RequestMapping("hello")
    @ResponseBody
    public String helloWord() {
        return helloWordServiceImpl.helloWord();
    }
}

```

* 和服务提供者包名类名相同的接口

```
package com.wgq.dubbo.product.service;


public interface HelloWordService {
    String helloWord() ;
}

```

* 整体上消费者和提供者不同的地方在于xml配置文件。


### dubbo-admin dubbo的管理控制台

* 上github下载dubbo的源码，地址如下：https://github.com/alibaba/dubbo
* 修改dubbo-admin项目下WEB-INF/dubbo.properties(dubbo\dubbo-admin\src\main\webapp\WEB-INF\dubbo.properties)内注册地址：

```

#其实主要就是修改注册中心地址
dubbo.registry.address=zookeeper://192.168.110.65:2181?backup=192.168.110.65:2182,192.168.110.65:2183
dubbo.admin.root.password=<PASSWORD>
dubbo.admin.guest.password=<PASSWORD>

```

* 然后通过maven打包项目 mvn package，生成dubbo-admin-2.5.4.war的war包，放入tomcat中运行，结果如下图：
![dubbo-admin](http://otor8zzyt.bkt.clouddn.com/dubbo/dubbo-test.png "dubbo-admin")

### 测试

* 这里提供三个服务的提供者，一个服务的消费者用于测试

#### 运行服务提供者

* 其实就是修改server.port和dubbo协议的端口后，生成三个不同的jar，分别运行。（当然这里为了调用清晰，还需要修改serverImpl返回值）
* 进入到项目目录下，运行mvn clean package命令，生成jar包
* java -jar xxxxx.jar 分别运行三个服务

#### 运行消费者

* 直接运行消费者的AppClass的main方法，然后在浏览器输入测试地址：localhost:8084/consumer/hello/
* 可以很清楚的看到返回值product1,product2,product3都会出现












<file_sep>---
title: java源码--AbstractQueuedSynchronizer
date: 2017-07-27 23:48:00
categories:
- java
tags:
- 并发
- java
- 源码
---

### 通过AQS实现一个简单的Lock

java并发包下有个非常重要的类```AbstractQueuedSynchronizer```，```ReentrantLock```、```ReentrantReadWriteLock```、```CountDownLatch```、```Semaphore```都是通过```AbstractQueuedSynchronizer```（以下简称AQS）来实现的；既然AQS的用处这么大，那么这里就让我们通过阅读AQS的源码来了解一下它到底提供了一个什么样的功能。

AQS的源码中有下面的一段注释的代码，

```java

class Mutex implements Lock, java.io.Serializable {

   // Our internal helper class
   private static class Sync extends AbstractQueuedSynchronizer {
     // Reports whether in locked state
     protected boolean isHeldExclusively() {
       return getState() == 1;
     }

     // Acquires the lock if state is zero
     public boolean tryAcquire(int acquires) {
       assert acquires == 1; // Otherwise unused
       if (compareAndSetState(0, 1)) {
         setExclusiveOwnerThread(Thread.currentThread());
         return true;
       }
       return false;
     }

     // Releases the lock by setting state to zero
     protected boolean tryRelease(int releases) {
       assert releases == 1; // Otherwise unused
       if (getState() == 0) throw new IllegalMonitorStateException();
       setExclusiveOwnerThread(null);
       setState(0);
       return true;
     }

     // Provides a Condition
     Condition newCondition() { return new ConditionObject(); }

     // Deserializes properly
     private void readObject(ObjectInputStream s)
         throws IOException, ClassNotFoundException {
       s.defaultReadObject();
       setState(0); // reset to unlocked state
     }
   }

   // The sync object does all the hard work. We just forward to it.
   private final Sync sync = new Sync();

   public void lock()                { sync.acquire(1); }
   public boolean tryLock()          { return sync.tryAcquire(1); }
   public void unlock()              { sync.release(1); }
   public Condition newCondition()   { return sync.newCondition(); }
   public boolean isLocked()         { return sync.isHeldExclusively(); }
   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
   public void lockInterruptibly() throws InterruptedException {
     sync.acquireInterruptibly(1);
   }
   public boolean tryLock(long timeout, TimeUnit unit)
       throws InterruptedException {
     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
   }
 }}

```

* 这段代码的意思就是通过AQS来简单的实现一个Lock，这个锁只有两个状态0、1，0：已释放锁，1：获取锁，并且这个锁是不可重入的。
* 从这个例子上来看，实现一个这样一个锁，主要依赖的是AQS的```acquire```和```release```方法。
* 那么下面我们就通过```acquire```和```release```方法这两个方法去认识AQS到底做了些啥

### AQS的acquire方法

```java

public final void acquire(int arg) {
	//Node.EXCLUSIVE代表独占锁
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

```

* 调用```tryAcquire(int)```方法，成功则方法执行成功，返回void
* ```tryAcquire(int)```尝试获取锁失败，则调用```acquireQueued```方法。
* ```acquireQueued```方法内会先调用```addWaiter```方法，那么我们先看看```addWaiter```方法

#### addWaiter

```java

private Node addWaiter(Node mode) {
	//根据当前线程new一个新的node节点
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    //获取尾节点
    Node pred = tail;
    if (pred != null) {
    	//设置当前节点的prev为原尾节点
        node.prev = pred;
        //通过cas方法把当前节点设置为尾节点，并把原尾节点的next设置为当前节点
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;	//放回当前节点
        }
    }
    enq(node);
    return node;
}
//尾节点为空
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        //重新判断当前尾节点是否为空
        //为空表示当前队列为空
        if (t == null) { // Must initialize
        	//通过cas设置当前head节点，并把tail赋值为head
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

```

* 根据当前线程初始化一个node节点
* 如果当前链表的尾节点为null，表面当前链接还未初始化，那么初始化链接，设置tail=head=new node()
* 如果当前链表的尾节点不为null，则把当前节点放到链表的末尾
* 替换tail和head值都是通过cas操作来保证线程安全

#### acquireQueued

```java

private final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
    	//线程是否interrupted
        boolean interrupted = false;
        for (;;) {
        	//当前节点的上一个节点
            final Node p = node.predecessor();
            //如果当前节点是头节点，并且尝试获取锁
            if (p == head && tryAcquire(arg)) {
            	//获取锁成功，设置头节点。
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

//获取锁失败后，当前线程需要阻塞等待
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    //判断上一个节点的状态是否是 SIGNAL
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    if (ws > 0) {
    	//	表示当前正在处理的线程已经cancelled
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
    	//node的waitStatus 初始状态都是 0，这里需要替换成SIGNAL，表示后面有节点正在等待唤醒
    	//或者在共享模式下，head节点的有可能会设置成PROPAGATE状态
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

//阻塞当前线程，并且当前线程是否interrupted
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

```

* 首先判断上一个节点是否是head节点，如果是，则尝试获取资源，获取成功则直接返回。
* 尝试获取资源失败，则去判断prev节点的状态。
* SIGNAL：阻塞当前线程，等待唤醒。0：表示初始状态。>0：表示已取消
* 然后一直循环直到获取资源成功。

#### cancelAcquire方法

当获取资源失败时，在finally里面会调用cancelAcquire(Node node)方法。

```java

 private void cancelAcquire(Node node) {
    // Ignore if node doesn't exist
    if (node == null)
        return;

    node.thread = null;

    // Skip cancelled predecessors
    //获取当前节点的prev节点，并跳过waitStatus=CANCELLED的节点
    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;

    // predNext is the apparent node to unsplice. CASes below will
    // fail if not, in which case, we lost race vs another cancel
    // or signal, so no further action is necessary.
    Node predNext = pred.next;

    // Can use unconditional write instead of CAS here.
    // After this atomic step, other Nodes can skip past us.
    // Before, we are free of interference from other threads.
    //设置当前节点为CANCELLED
    node.waitStatus = Node.CANCELLED;

    // If we are the tail, remove ourselves.
    // 如果是当前节点是tail节点，把pred节点设置为tail节点，并且pred节点的next节点为空
    if (node == tail && compareAndSetTail(node, pred)) {
        compareAndSetNext(pred, predNext, null);
    } else {
        // If successor needs signal, try to set pred's next-link
        // so it will get one. Otherwise wake it up to propagate.
        int ws;
        if (pred != head &&
            ((ws = pred.waitStatus) == Node.SIGNAL ||
             (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
            pred.thread != null) {
            Node next = node.next;
            if (next != null && next.waitStatus <= 0)
            //pred节点不是head节点
            //pred节点的状态是 SIGNAL
            //pred的thread不为空
            //next节点不为空并且next节点状态不为CANCELLED
            //则替换pred的next节点为当前节点的next节点
                compareAndSetNext(pred, predNext, next);
        } else {
        	//直接尝试唤醒  实际上唤醒的是从链表末尾的第一个 waitStatus<=0的节点
            unparkSuccessor(node);
        }

        node.next = node; // help GC
    }
}

```

* 主要的作用就是获取资源失败后删除当前添加的节点。

### AQS的链表节点Node 

上面我们了解了acquire方法后，发现内部是通过一个链表来实现功能的，所以这里我们先来了解一下这个队列的Node

```java

static final class Node {
    /** Marker to indicate a node is waiting in shared mode */
    static final Node SHARED = new Node();
    /** Marker to indicate a node is waiting in exclusive mode */
    static final Node EXCLUSIVE = null;

    /** waitStatus value to indicate thread has cancelled */
    static final int CANCELLED =  1;
    /** waitStatus value to indicate successor's thread needs unparking */
    static final int SIGNAL    = -1;
    /** waitStatus value to indicate thread is waiting on condition */
    static final int CONDITION = -2;
    /**
     * waitStatus value to indicate the next acquireShared should
     * unconditionally propagate
     */
    static final int PROPAGATE = -3;

    /**
     * Status field, taking on only the values:
     *   SIGNAL:     The successor of this node is (or will soon be)
     *               blocked (via park), so the current node must
     *               unpark its successor when it releases or
     *               cancels. To avoid races, acquire methods must
     *               first indicate they need a signal,
     *               then retry the atomic acquire, and then,
     *               on failure, block.
     *   CANCELLED:  This node is cancelled due to timeout or interrupt.
     *               Nodes never leave this state. In particular,
     *               a thread with cancelled node never again blocks.
     *   CONDITION:  This node is currently on a condition queue.
     *               It will not be used as a sync queue node
     *               until transferred, at which time the status
     *               will be set to 0. (Use of this value here has
     *               nothing to do with the other uses of the
     *               field, but simplifies mechanics.)
     *   PROPAGATE:  A releaseShared should be propagated to other
     *               nodes. This is set (for head node only) in
     *               doReleaseShared to ensure propagation
     *               continues, even if other operations have
     *               since intervened.
     *   0:          None of the above
     *
     * The values are arranged numerically to simplify use.
     * Non-negative values mean that a node doesn't need to
     * signal. So, most code doesn't need to check for particular
     * values, just for sign.
     *
     * The field is initialized to 0 for normal sync nodes, and
     * CONDITION for condition nodes.  It is modified using CAS
     * (or when possible, unconditional volatile writes).
     */
    volatile int waitStatus;

    /**
     * Link to predecessor node that current node/thread relies on
     * for checking waitStatus. Assigned during enqueuing, and nulled
     * out (for sake of GC) only upon dequeuing.  Also, upon
     * cancellation of a predecessor, we short-circuit while
     * finding a non-cancelled one, which will always exist
     * because the head node is never cancelled: A node becomes
     * head only as a result of successful acquire. A
     * cancelled thread never succeeds in acquiring, and a thread only
     * cancels itself, not any other node.
     */
    volatile Node prev;

    /**
     * Link to the successor node that the current node/thread
     * unparks upon release. Assigned during enqueuing, adjusted
     * when bypassing cancelled predecessors, and nulled out (for
     * sake of GC) when dequeued.  The enq operation does not
     * assign next field of a predecessor until after attachment,
     * so seeing a null next field does not necessarily mean that
     * node is at end of queue. However, if a next field appears
     * to be null, we can scan prev's from the tail to
     * double-check.  The next field of cancelled nodes is set to
     * point to the node itself instead of null, to make life
     * easier for isOnSyncQueue.
     */
    volatile Node next;

    /**
     * The thread that enqueued this node.  Initialized on
     * construction and nulled out after use.
     */
    volatile Thread thread;

    /**
     * Link to next node waiting on condition, or the special
     * value SHARED.  Because condition queues are accessed only
     * when holding in exclusive mode, we just need a simple
     * linked queue to hold nodes while they are waiting on
     * conditions. They are then transferred to the queue to
     * re-acquire. And because conditions can only be exclusive,
     * we save a field by using special value to indicate shared
     * mode.
     */
    Node nextWaiter;

    /**
     * Returns true if node is waiting in shared mode.
     */
    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    /**
     * Returns previous node, or throws NullPointerException if null.
     * Use when predecessor cannot be null.  The null check could
     * be elided, but is present to help the VM.
     *
     * @return the predecessor of this node
     */
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    Node() {    // Used to establish initial head or SHARED marker
    }

    Node(Thread thread, Node mode) {     // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }

    Node(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

```

| waitStatus | 说明 |
| :----: | :----: |
|   SIGNAL  | 表示当前节点的next节点正在等待唤醒 |
|   CANCELLED  | 表示当前节点已取消获取锁 |
|   CONDITION  | 表示当前节点在condition队列上 |
|   PROPAGATE  |  |
|   0  | 一个非codition的Node节点初始状态 |

* nextWaiter ：SHARED 表示当前节点是共享，EXCLUSIVE 表示当前是独占

### AQS的release方法

```java

public final boolean release(int arg) {
	//尝试释放资源
    if (tryRelease(arg)) {
        Node h = head;
        //head节点waitStatus=0 表示后面没有其他节点
        if (h != null && h.waitStatus != 0)
        	//唤醒下一个节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

/**
 * Wakes up node's successor, if one exists.
 *
 * @param node the node
 */
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    //重置waitStatus为0
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    //获取next节点
    Node s = node.next;
    //如果next节点为空或者next节点为取消状态
    //则从后往前遍历队列获取非node节点并且 waitStatus<=0的那个节点
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    //直接唤醒
    if (s != null)
        LockSupport.unpark(s.thread);
}

```

* 尝试释放资源，成功则根据当前head节点去唤醒下一个节点
* 唤醒过程中会先把当前节点的waitStatus设置为0,这边设置为0后，acquire时便不会去park阻塞next节点了。
* 失败则直接返回false


### AQS的acquireInterruptibly

```java

public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

```

* 如果仔细的看完过上面的acquire方法的同学，这里应该就能一目了然了。
* 这个方法跟acquire方法不同的地方在于，如果线程已经中断，则直接抛出InterruptedException。

### AQS的独占模式总结

* 尝试获取资源，获取失败，把当前线程封装成EXCLUSIVE类型Node添加到队列。
* 如果pred不是head节点或者再次尝试获取资源失败，则会把当前对象从线程调度上取下，并自旋一直尝试获取资源
* 当head节点调用了```release```方法时，会唤醒head的next节点，如果next节点是CANCELLED状态或者为null，则会并从tail节点往前遍历队列，知道获取一个非CANCELLED节点，并唤醒他。

### AQS的acquireShared方法

AQS的共享模式

```java

public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

```
* ```tryAcquireShared```会返回一个int值，>0: 表示可以唤醒next的share节点，<0: 表示获取失败，=0：表示获取成功，但是不可唤醒next节点
* 返回值小于0，加入到同步队列中。

#### AQS的doAcquireShared

```java

/**
 * Acquires in shared uninterruptible mode.
 * @param arg the acquire argument
 */
private void doAcquireShared(int arg) {
	//添加节点，SHARED模式
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            //判断pred节点是否为head节点
            if (p == head) {
            	//尝试获取共享资源
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                	//设置head节点，r>0时，next节点是share节点，则唤醒他
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    if (interrupted)
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

```

* 把当前节点封装为SHARED节点添加到队列尾部
* 当前节点的pred节点是head节点，则尝试获取共享资源
* 获取共享资源成功后，返回值>0，则重新设置节点并唤醒后置的share节点。

#### AQS的setHeadAndPropagate节点

```java

private void setHeadAndPropagate(Node node, int propagate) {
    Node h = head; // Record old head for check below
    //设置头节点
    setHead(node);
    /*
     * Try to signal next queued node if:
     *   Propagation was indicated by caller,
     *     or was recorded (as h.waitStatus either before
     *     or after setHead) by a previous operation
     *     (note: this uses sign-check of waitStatus because
     *      PROPAGATE status may transition to SIGNAL.)
     * and
     *   The next node is waiting in shared mode,
     *     or we don't know, because it appears null
     *
     * The conservatism in both of these checks may cause
     * unnecessary wake-ups, but only when there are multiple
     * racing acquires/releases, so most need signals now or soon
     * anyway.
     */
    if (propagate > 0 || h == null || h.waitStatus < 0 ||
        (h = head) == null || h.waitStatus < 0) {
        Node s = node.next;
        if (s == null || s.isShared())
            doReleaseShared();
    }
}

```

* 先设置head节点
* 返回值```propagate```>0时，如果next节点为空，或者next节点是SHARED节点，则唤醒next节点

#### AQS的doReleaseShared

```java

/**
     * Release action for shared mode -- signals successor and ensures
     * propagation. (Note: For exclusive mode, release just amounts
     * to calling unparkSuccessor of head if it needs signal.)
     */
    private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            //head节点不为空，head节点不等于tail节点
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                //head节点的状态为SIGNAL直接唤醒后置节点
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                //head节点状态为0，状态设置为PROPAGATE
                //两种情况，一种是head节点没有next节点，则状态还是初始的0
                //一种是另外一个线程把head节点状态更新为0
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

```

* head节点状态为SIGNAL，则直接唤醒后一个节点。
* head节点状态为0，则设置为PROPAGATE状态。

### AQS的releaseShared

共享模式释放资源

```java

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

```

* ```tryReleaseShared```返回true的时候表示所有的共享资源全部被释放
* 调用```doReleaseShared```方法。
* ```doReleaseShared```方法上面有说过,这个时候会唤醒下一个节点，这个时候无论下一个节点是独占节点还是SHARED节点

### AQS共享模式总结

* 获取资源时，根据```tryAcquireShared```返回值，
	+ 小于0 获取资源失败，则初始化一个SHARED模式Node添加到队列末尾
	+ 等于0 获取资源成功，但是不唤醒next的SHARED节点
	+ 大于0 获取资源成功，如果next节点是SHARED节点，则直接唤醒。
* 释放资源时，```tryReleaseShared```只有释放所有的资源时才会返回true，这个时候会唤醒下一个资源。


### AQS的ConditionObject

这个我们首先得先了解一下ConditionObject的用法

```java

package test.wgq;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadConditionTest {
	
	private static ReentrantLock lock = new ReentrantLock() ;
	
	private static Condition condition = lock.newCondition() ;
	
	public static void main(String[] args) throws Exception {
		Thread thread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
				try {
					lock.lock();
					System.out.println("线程1获取到锁");
					System.out.println("线程1等待condition信号");
					condition.await();	
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("线程1获取到condition信号");
				lock.unlock();
			}
		}) ;
		
		thread.start();
		Thread.currentThread().sleep(1000l);
		Thread thread1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				lock.lock();
				System.out.println("线程2获取到锁");
				condition.signal();
				System.out.println("线程2发送信号量");
				lock.unlock();
			}
		}) ;
		thread1.start();
	}
	
	
}


```

运行结果：
>线程1获取到锁<br/>
>线程1等待condition信号<br/>
>线程2获取到锁<br/>
>线程2发送信号量<br/>
>线程1获取到condition信号<br/>

* 调用顺序 线程一获取锁 -> 线程一codition.await -> 线程二获取到锁 -> 线程二codition.signal -> 线程二释放锁 -> 线程一释放锁
* 上面了解了codition的用法，那么下面通过源码看看await和signal是怎么实现的。

#### await

```java

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //向Codition队列上添加一个codition节点
    Node node = addConditionWaiter();
    //释放当前资源
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //判断当前节点是否在同步队列上
    //不在则一直自旋直到调用signal方法
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //重新把当前节点添加到同步队列上
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

private Node addConditionWaiter() {
    Node t = lastWaiter;
    // If lastWaiter is cancelled, clean out.
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

final boolean isOnSyncQueue(Node node) {
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
    if (node.next != null) // If has successor, it must be on queue
        return true;
    /*
     * node.prev can be non-null, but not yet on queue because
     * the CAS to place it on queue can fail. So we have to
     * traverse from tail to make sure it actually made it.  It
     * will always be near the tail in calls to this method, and
     * unless the CAS failed (which is unlikely), it will be
     * there, so we hardly ever traverse much.
     */
    return findNodeFromTail(node);
}

```

* 首先先把当前线程的锁释放掉。
* 然后等待其他线程signal发送信号：判断节点是否在同步队列上，如果在了，则重新调用acquireQueued，获取到锁，继续执行

#### signal

```java

public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}

private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;

    /*
     * Splice onto queue and try to set waitStatus of predecessor to
     * indicate that thread is (probably) waiting. If cancelled or
     * attempt to set waitStatus fails, wake up to resync (in which
     * case the waitStatus can be transiently and harmlessly wrong).
     */
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}

```
* 获取到codition队列的first节点
* 把first节点的状态从CONDITION替换成0
* 把first节点添加到同步队列尾部，并获取到原tail节点p


#### codition总结

* 线程1调用reentrantLock.lock时，线程被加入到AQS的等待队列中。
* 线程1调用await方法被调用时，该线程从AQS中移除，对应操作是锁的释放。
* 接着马上被加入到Condition的等待队列中，以为着该线程需要signal信号。
* 线程2，因为线程1释放锁的关系，被唤醒，并判断可以获取锁，于是线程2获取锁，并被加入到AQS的等待队列中。
* 线程2调用signal方法，这个时候Condition的等待队列中只有线程1一个节点，于是它被取出来，并被加入到AQS的等待队列中。  注意，这个时候，线程1 并没有被唤醒。
* signal方法执行完毕，线程2调用reentrantLock.unLock()方法，释放锁。这个时候因为AQS中只有线程1，于是，AQS释放锁后按从头到尾的顺序唤醒线程时，线程1被唤醒，于是线程1回复执行。
* 直到释放所整个过程执行完毕




<file_sep>---
title: id生成
date: 2017-07-23 16:00:00
categories:
- java
tags:
- java
---

美团点评上有一片关于id生成的文章写的很好，大家可以参考一下：
[Leaf——美团点评分布式ID生成系统](https://tech.meituan.com/MT_Leaf.html "Leaf——美团点评分布式ID生成系统")

这里要说的主要还是我们公司当前内部自己的生成id的实现；其实现上来说其实有些类似美团点评的```Leaf-segment```实现。

下面具体的说明一下是怎么实现的。

公司内部的应用一般都有2个以上的节点，每个节点下部署的代码是一样的，获取id时，调用：getNextSeq("tbl_account_history_id", 20);
每个节点的在获取id时，采用```synchronized```关键字保证当前节点应用下的数据安全。

#### 获取id ```getNextSeq```
```java

public synchronized String getNextSeq(String sequenceName, int width) throws Exception{
	SequencePool pool = seqMap.get(sequenceName);
	if(seqMap.get(sequenceName) == null || pool.isEmpty()){
		pool = refillPool(sequenceName);
		seqMap.put(sequenceName, pool);
	}
	return formatSequence(String.valueOf(pool.next()),width);
}

```

上面一段代码主要干了两件事情：
* 从seqMap中获取到SequencePool对象，如果SequencePool对象不存在或者为空则重新初始化一个SequencePool对象,放入到seqMap中。
* 通过SequencePool格式化返回的id字符串

```SequencePool```<br />
```java

private static class SequencePool{
	private long low;
	private long high;
	public SequencePool(long low, long high){
		this.low = low;
		this.high = high;
	}
	public long next() {
		return low++;
	}
	public boolean isEmpty(){
		return low > high;
	}
}

```


#### 初始化pool ```refillPool```
```java

private SequencePool refillPool(String sequenceName) throws Exception{
	int allotment = 100 ;
	long nextSeq = batchSequenceDao.getNextSeq(sequenceName, allotment);
	return new SequencePool(nextSeq, nextSeq + allotment -1); 
}

//batchSequenceDao.getNextSeq
public long getNextSeq(String key, int allotment) throws Exception{
	HashMap<String, Object> parameters = new HashMap<String, Object>();
	parameters.put("sequenceName", key);
	parameters.put("allotment", allotment);
	Long result = (Long)sqlMapClient.queryForObject("batch_sequence.getNextSequence", parameters);
	return result;
}

```
初始化的时候干了啥呢？
* 先通过数据库函数batch_sequence.getNextSequence获取到id。
* 然后初始化SequencePool，很明显可以看到pool里的high=low+100（不要纠结99还是100哈）。

那么这个数据库函数又干了啥呢？继续往下看

#### 更新数据库并返回id
```sql

--表
CREATE TABLE common.sequence_center
(
    sequence_name character varying(32) COLLATE pg_catalog."default" NOT NULL,
    next_val numeric(18),
    CONSTRAINT sequence_center_pkey PRIMARY KEY (sequence_name)
)

--函数
CREATE OR REPLACE FUNCTION common.batch_sequence(
	p_sequence_name character varying,
	allotment integer)
RETURNS numeric
    LANGUAGE 'plpgsql'
    COST 100.0
    VOLATILE NOT LEAKPROOF 
AS $function$
declare 
	begin_sequence  numeric(18);
	cur_val  numeric(18);
	result numeric(18);
begin
	select next_val into cur_val from common.sequence_center where sequence_name=p_sequence_name for update;
	if cur_val is null 
	then
	  begin
	    cur_val := allotment + 1;
	    insert into common.sequence_center(sequence_name,next_val) values (p_sequence_name, cur_val);
	  exception when unique_violation then
	  	select common.batch_sequence(p_sequence_name, allotment) into result;
                return result;
          end;
	else
	  cur_val := allotment + cur_val;
	  update common.sequence_center set next_val=cur_val where sequence_name=p_sequence_name;
	end if;
	result := cur_val - allotment;
	return result;
	
end;

```
* sequence_name：序列名称
* next_val：表示<next_val的值都已被应用节点缓存.


这个函数主要的作用是根据传入的id序列号```sequence_name```和缓存id的长度```allotment```来更新common.sequence_center表内的值
* 1、 首先根据主键sequence_name查询出当前列
* 2、 如果当前列存在next_val的值就等于next_val+allotment，更新common.sequence_center表，返回原始的next_val。
* 3、 如果当前列不存在，说明是第一次获取id，直接插入一条数据next_val=allotment+1，因为当数据不存在时使用select...for update加排它锁是无效的，所以会有可能有两个节点同时调用函数插入数据的情况存在，那么第二个插入的必定失败，失败则重新调用这个函数，这个时候则select...for update排它锁生效，然后重复步骤2。

#### 总结
上面看完了各个步骤的实现后，id生成的业务逻辑总结如下：
* 每个应用节点内部使用```synchronized```保证应用内部不会出现多线程的问题
* 根据```sequence_name```获取id时，先从当前应用节点的缓存中获取，没有或者```SequencePool```中的low > high，则需要更新数据库，并返回当前最新的一段数据，然后缓存起来，缓存的id的数量为```allotment```大小。
* 根据```sequence_name```更新数据库id时，使用select...for update排它锁来保证应用多个节点下的数据安全。


<file_sep>---
layout: post
title: 简单算法-java实现
date: 2017-07-23 15:00:00
categories:
- java
tags:
- 算法
- java
---

算法的稳定性：假定在待排序的记录序列中，存在多个具有相同的关键字的记录，若经过排序，这些记录的相对次序保持不变，即在原序列中，ri=rj，且ri在rj之前，而在排序后的序列中，ri仍在rj之前，则称这种排序算法是稳定的；否则称为不稳定的。

### 冒泡排序

\\( o(n^2) \\) 稳定

```java

public class BubbleSort {
	/**
	 * 冒泡排序
	 * 比较相邻的元素，如果第一个比第二个大/第一个比第二个小，则交换他们
	 * 排序一趟后，最后一个应该是最大的或者最小的
	 * 重复上面的步骤，除了最后一个
	 * @param args
	 */
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,4,33,2,3,4,32,543,63,76} ;
		int temp ;
		for(int i=0;i<a.length-1;i++) {
			for(int j=0;j<a.length-1-i;j++) {
				if(a[j] > a[j+1]) {
					temp = a[j] ;
					a[j] = a[j+1] ;
					a[j+1] = temp ;
				}
				System.out.print(a[j] + " ");
			}
			System.out.println("");
		}
	}
}

```


### 快速排序

\\( o(nlogn) \\) 不稳定

```java

public class QuickSort {
	/**
	 * 快速排序思想
	 * 选取数组第一个数字作为中轴
	 * 和最后一个比，比他大则交换；交换后再和最前面那个比，比他小则交换。
	 * 这样循环，一趟排序完成后，左边的都是比中轴小的，右边的都是比中轴大的。
	 * 然后左右两边分别递归排序。
	 * @param a
	 * @param low
	 * @param high
	 * @return
	 */
	public static int getMiddle(int[] a, int low, int high) {
		
		int temp = a[low] ;
		while(low < high) {
			while(low < high && a[high] >= temp) {
				high-- ;
			}
			a[low] = a[high] ;
			while(low < high && a[low] <= temp) {
				low++ ;
			}
			a[high] = a[low] ;
		}
		a[low] = temp ;
		return low ;
	}
	
	public static void quickSort(int[] a, int low, int high) {
		if(low < high) {
			int middle = getMiddle(a, low, high) ;
			quickSort(a, middle + 1, high) ;
			quickSort(a, low, middle - 1) ;
		}
	} 
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,33,2,3,4,32,543,63,76} ;
		long startTime = System.currentTimeMillis() ;
		quickSort(a, 0, a.length - 1) ;
		long endTime = System.currentTimeMillis() ;
		System.out.println("排序时间：" + (startTime - endTime));
		for(int i=0;i<a.length - 1;i++) {
			System.out.print(a[i] + " ");
		}
	}
}

```

### 选择排序

\\( o(n^2) \\) 不稳定

```java

public class SelectSort {
	
	/**
	 * 选择排序
	 * 选择数组中最小元素与第一个置换，选择数组剩余元素中最小元素与第二个置换，以此类推...
	 * @param a
	 */
	
	public static void selectSort(int[] a) {
		int size = a.length ;
		int temp = 0 ;
		
		for(int i=0;i < size;i++) {
			int k = i ;
			
			for(int j=i;j<size;j++) {
				if(a[j] < a[k]) {
					k = j ;
				}
			}
			
			temp = a[i] ;
			a[i] = a[k] ;
			a[k] = temp ;
			
		}
	}
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,33,2,3,4,32,543,63,76} ;
		long startTime = System.currentTimeMillis() ;
		selectSort(a) ;
		long endTime = System.currentTimeMillis() ;
		System.out.println("排序时间：" + (startTime - endTime));
		for(int i=0;i<a.length - 1;i++) {
			System.out.print(a[i] + " ");
		}
	}
}

```

### 插入排序

\\( o(n^2) \\) 稳定

```java

public class InsertSort {
	/**
	 * 插入排序
	 * 从第一个元素开始，改元素可以认为已经被排序
	 * 取出下一个元素，与有序的元素从后往前比较
	 * 如果当前元素小于有序的元素，则把有序元素移到下一位。
	 * 直到当前元素大于有序的元素，则把当前元素放入有序的元素中。
	 * @param a
	 */
	
	public static void insetSort(int[] a) {
		int temp ;
		int j = 0;
		for(int i=1;i<a.length;i++) {
			
			temp = a[i] ;
			for(j=i;j > 0 && temp < a[j-1];j--) {
				a[j] = a[j-1] ;
			}
			a[j] = temp ;
		}
	}
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,33,2,3,4,32,543,63,76} ;
		long startTime = System.currentTimeMillis() ;
		insetSort(a) ;
		long endTime = System.currentTimeMillis() ;
		System.out.println("排序时间：" + (startTime - endTime));
		for(int i=0;i<a.length - 1;i++) {
			System.out.print(a[i] + " ");
		}
	}
}

```

### 希尔排序

\\( o(n^2) \\) 不稳定

```java

public class ShellSort {
	/**
	 * 希尔排序
	 * 根据需求，如果你想要结果从大到小排列，它会首先将数组进行分组，然后将较大值移到前面，较小值移到后面，
	 * 最后将整个数组进行插入排序,这样比起一开始就用插入排序减少了数据交换和移动的次数，可以说希尔排序是加强版的插入排序
	 * @param a
	 */
	
	public static void shellSort(int[] a) {
		int size = a.length ;
		int j,temp ;
		
		for(int ic=size/2; ic>0 ; ic = ic/2) {//就相当于在插入排序外面套了一层这个遍历
			
			for(int i=ic;i<a.length;i++) {
				
				temp = a[i] ;
				for(j=i;j >= ic && temp < a[j - ic];j = j - ic) {
					a[j] = a[j-ic] ;
				}
				a[j] = temp ;
			}
		}
	}
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,33,2,3,4,32,543,63,76} ;
		long startTime = System.currentTimeMillis() ;
		shellSort(a) ;
		long endTime = System.currentTimeMillis() ;
		System.out.println("排序时间：" + (startTime - endTime));
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i] + " ");
		}
	}
}

```

### 归并排序

\\( o(nlogn) \\) 稳定

```java

/**
 * 归并排序
 * 将两个或两个以上的有序表合成一个新的有序表。
 * 把待排序的序列分成若干子序列，每个子序列都是有序的，然后再把有序的子序列合并为整体有序的序列。
 * 时间复杂度0(nlogn)
 * 稳定排序
 * @author wangguangqiao
 *
 */
public class MergeSort {
	
	public static void mergeSort(int[] a, int low, int high) {
		int mid = (low + high) / 2 ;
		if(low < high) {
			mergeSort(a, low, mid) ;
			
			mergeSort(a, mid + 1, high) ;
			
			merge(a, low, mid, high) ;
		}
	}
	
	/**
	 * 讲数组中 low 到 high的位置进行排序
	 * @param a 待排序数组
	 * @param low 待排序开始位置
	 * @param mid 待排序中间位置
	 * @param high 待排序结束位置
	 */
	public static void merge(int[] a, int low, int mid, int high) {
		int[] temp = new int[high - low + 1] ;
		int i = low ;
		int j = mid + 1 ;
		int k = 0 ;
		
		//将两个有序队列中较小的移到新数组
		//总会有一个数组会有剩余的元素
		while(i <= mid && j <= high) {
			if(a[i] < a[j]) {
				temp[k++] = a[i++] ;
			}else {
				temp[k++] = a[j++] ;
			}
		}
		
		//将剩余的元素加入到数组
		while(i <= mid) {
			temp[k++] = a[i++] ;
		}
		
		//将剩余的元素加入到数组
		while(j <= high) {
			temp[k++] = a[j++] ;
		}
		
		for(int t = 0;t<temp.length;t++) {
			a[t + low] = temp[t] ;
		}
	}
	
	public static void main(String[] args) {
		int[] a = {88,23,32,44,12,45,33,2,3,4,32,543,63,76} ;
		long startTime = System.currentTimeMillis() ;
		mergeSort(a, 0, a.length - 1) ;
		long endTime = System.currentTimeMillis() ;
		System.out.println("排序时间：" + (startTime - endTime));
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i] + " ");
		}
	}
}

```

### 堆排序

利用大根堆的特性，先建堆，建堆后把根节点和最后一个值交换。然后把1-(n-1)重新建堆，然后把根节点同n-1的值交换，以此类推。<file_sep>---
layout: post
title: xxl-job源码解析一
date: 2018-04-10 16:04:00
categories:
- quartz
tags:
- quartz
- xxl-job
---


XXL-JOB是一个轻量级分布式任务调度框架，其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线，开箱即用。

主要特性如下：
* 1、简单：支持通过Web页面对任务进行CRUD操作，操作简单，一分钟上手；
* 2、动态：支持动态修改任务状态、暂停/恢复任务，以及终止运行中任务，即时生效；
* 3、调度中心HA（中心式）：调度采用中心式设计，“调度中心”基于集群Quartz实现并支持集群部署，可保证调度中心HA；
* 4、执行器HA（分布式）：任务分布式执行，任务"执行器"支持集群部署，可保证任务执行HA；
* 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时，也支持手动录入执行器地址；
* 6、弹性扩容缩容：一旦有新执行器机器上线或者下线，下次调度时将会重新分配任务；
* 7、路由策略：执行器集群部署时提供丰富的路由策略，包括：第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等；
* 8、故障转移：任务路由策略选择"故障转移"情况下，如果执行器集群中某一台机器故障，将会自动Failover切换到一台正常的执行器发送调度请求。
* 9、失败处理策略；调度失败时的处理策略，策略包括：失败告警（默认）、失败重试；
* 10、失败重试：调度中心调度失败且启用"失败重试"策略时，将会自动重试一次；执行器执行失败且回调失败重试状态时，也将会自动重试一次；
* 11、阻塞处理策略：调度过于密集执行器来不及处理时的处理策略，策略包括：单机串行（默认）、丢弃后续调度、覆盖之前调度；
* 12、分片广播任务：执行器集群部署时，任务路由策略选择"分片广播"情况下，一次任务调度将会广播触发集群中所有执行器执行一次任务，可根据分片参数开发分片任务；
* 13、动态分片：分片广播任务以执行器为维度进行分片，支持动态扩容执行器集群从而动态增加分片数量，协同进行业务处理；在进行大数据量业务操作时可显著提升任务处理能力和速度。
* 14、事件触发：除了"Cron方式"和"任务依赖方式"触发任务执行之外，支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务，可根据业务事件灵活触发。
* 15、任务进度监控：支持实时监控任务进度；
* 16、Rolling实时日志：支持在线查看调度结果，并且支持以Rolling方式实时查看执行器输出的完整的执行日志；
* 17、GLUE：提供Web IDE，支持在线开发任务逻辑代码，动态发布，实时编译生效，省略部署上线的过程。支持30个版本的历史版本回溯。
* 18、脚本任务：支持以GLUE模式开发和运行脚本任务，包括Shell、Python、NodeJS等类型脚本;
* 19、任务依赖：支持配置子任务依赖，当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔；
* 20、一致性：“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行；
* 21、自定义任务参数：支持在线配置调度任务入参，即时生效；
* 22、调度线程池：调度系统多线程触发调度运行，确保调度精确执行，不被堵塞；
* 23、数据加密：调度中心和执行器之间的通讯进行数据加密，提升调度信息安全性；
* 24、邮件报警：任务失败时支持邮件报警，支持配置多邮件地址群发报警邮件；
* 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
* 26、运行报表：支持实时查看运行数据，如任务数量、调度次数、执行器数量等；以及调度报表，如调度日期分布图，调度成功分布图等；
* 27、全异步：系统底层实现全部异步化，针对密集调度进行流量削峰，理论上支持任意时长任务的运行；
* 28、国际化：调度中心支持国际化设置，提供中文、英文两种可选语言，默认为中文；

官方的地址为：[XXL-JOB](http://www.xuxueli.com/xxl-job/"XXL-JOB")


XXL-JOB依托于spring quartz集群的实现，对于quartz集群有想了解的朋友可以先看看美团点评的这篇文章：[Quartz应用与集群原理分析](https://tech.meituan.com/mt-crm-quartz.html"Quartz应用与集群原理分析")


* XXL-JOB主要分为两个部分，一个是任务的调度中心，一个是任务的执行器，调度中心和执行器会公用一套核心的代码，执行器为具体的任务系统。
* 下面我们就通过一个任务具体执行的过程，先来通读一遍代码
	* 调度中心新建任务
	* 调度中心触发任务，通过http发送请求到执行器，获取调用结果
	* 执行器具体的去执行任务，记录日志，执行完后通过http请求通知调度中心执行结果
	* 调度中心查询执行结果


### 调度中心新建任务



```java

/**
 * index controller
 * @author xuxueli 2015-12-19 16:13:16
 */
@Controller
@RequestMapping("/jobinfo")
public class JobInfoController {

	@Resource
	private XxlJobGroupDao xxlJobGroupDao;
	@Resource
	private XxlJobService xxlJobService;
	
	...........

	//添加任务的入口
	@RequestMapping("/add")
	@ResponseBodyadd(XxlJobInfo jobInfo)
	public ReturnT<String>  {
		return xxlJobService.add(jobInfo);
	}
	
	...........
	
}


/**
 * core job action for xxl-job
 * @author xuxueli 2016-5-28 15:30:33
 */
@Service
public class XxlJobServiceImpl implements XxlJobService {
	private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);

	@Resource
	private XxlJobGroupDao xxlJobGroupDao;
	@Resource
	private XxlJobInfoDao xxlJobInfoDao;
	@Resource
	public XxlJobLogDao xxlJobLogDao;
	@Resource
	private XxlJobLogGlueDao xxlJobLogGlueDao;
	
	.............................

	@Override
	public ReturnT<String> add(XxlJobInfo jobInfo) {
		// valid
		.....................

		// add in db 保存到数据库
		xxlJobInfoDao.save(jobInfo);
		if (jobInfo.getId() < 1) {
			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
		}

		// add in quartz
        String qz_group = String.valueOf(jobInfo.getJobGroup());
        String qz_name = String.valueOf(jobInfo.getId());
        try {
        	//添加任务到quartz集群
            XxlJobDynamicScheduler.addJob(qz_name, qz_group, jobInfo.getJobCron());
            //XxlJobDynamicScheduler.pauseJob(qz_name, qz_group);
            return ReturnT.SUCCESS;
        } catch (SchedulerException e) {
            logger.error(e.getMessage(), e);
            try {
                xxlJobInfoDao.delete(jobInfo.getId());
                XxlJobDynamicScheduler.removeJob(qz_name, qz_group);
            } catch (SchedulerException e1) {
                logger.error(e.getMessage(), e1);
            }
            return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail"))+":" + e.getMessage());
        }
	}


	............................
}


```

* 上面的代码可以看出，调度中心的任务管理类主要是```XxlJobDynamicScheduler```,通过```XxlJobDynamicScheduler.addJob```方法添加任务到quartz集群中去
* xxlJobDynamicScheduler类在配置文件中有配置

```xml

//spring 实现的scheduler工厂类
<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="autoStartup" value="true" />			<!--自动启动 -->
	<property name="startupDelay" value="20" />				<!--延时启动，应用启动成功后在启动 -->
	<property name="overwriteExistingJobs" value="true" />	<!--覆盖DB中JOB：true、以数据库中已经存在的为准：false -->
	<property name="applicationContextSchedulerContextKey"  value="applicationContextKey" />
	<property name="configLocation" value="classpath:quartz.properties"/>
</bean>

//xxl-job封装的scheduler工具类
<bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" >
	<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
	<property name="scheduler" ref="quartzScheduler"/>
	<property name="accessToken" value="${xxl.job.accessToken}" />
</bean>



```

下面看看xxlJobDynamicScheduler类

```java


/**
 * base quartz scheduler util
 * @author xuxueli 2015-12-19 16:13:53
 */
public final class XxlJobDynamicScheduler implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler.class);

    // ---------------------- param ----------------------

    // scheduler
    private static Scheduler scheduler;
    public void setScheduler(Scheduler scheduler) {
		XxlJobDynamicScheduler.scheduler = scheduler;
	}

	// accessToken
    private static String accessToken;
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    // dao
    public static XxlJobLogDao xxlJobLogDao;
    public static XxlJobInfoDao xxlJobInfoDao;
    public static XxlJobRegistryDao xxlJobRegistryDao;
    public static XxlJobGroupDao xxlJobGroupDao;
    public static AdminBiz adminBiz;

    // ---------------------- applicationContext ----------------------
    @Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		XxlJobDynamicScheduler.xxlJobLogDao = applicationContext.getBean(XxlJobLogDao.class);
		XxlJobDynamicScheduler.xxlJobInfoDao = applicationContext.getBean(XxlJobInfoDao.class);
        XxlJobDynamicScheduler.xxlJobRegistryDao = applicationContext.getBean(XxlJobRegistryDao.class);
        XxlJobDynamicScheduler.xxlJobGroupDao = applicationContext.getBean(XxlJobGroupDao.class);
        XxlJobDynamicScheduler.adminBiz = applicationContext.getBean(AdminBiz.class);
	}

    // ---------------------- init + destroy ----------------------
    public void init() throws Exception {
        // admin registry monitor run 辅助线程
        JobRegistryMonitorHelper.getInstance().start();

        // admin monitor runJob  辅助线程
        JobFailMonitorHelper.getInstance().start();

        // admin-server(spring-mvc)	用于callback
        NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
        NetComServerFactory.setAccessToken(accessToken);

        // valid
        Assert.notNull(scheduler, "quartz scheduler is null");
        logger.info(">>>>>>>>> init xxl-job admin success.");
    }

    public void destroy(){
        // admin registry stop
        JobRegistryMonitorHelper.getInstance().toStop();

        // admin monitor stop
        JobFailMonitorHelper.getInstance().toStop();
    }

    // ---------------------- executor-client ----------------------
    private static ConcurrentHashMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
    public static ExecutorBiz getExecutorBiz(String address) throws Exception {
        // valid
        if (address==null || address.trim().length()==0) {
            return null;
        }

        // load-cache
        address = address.trim();
        ExecutorBiz executorBiz = executorBizRepository.get(address);
        if (executorBiz != null) {
            return executorBiz;
        }

        // set-cache   NetComClientProxy主要用于rpc的调用
        executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address, accessToken).getObject();
        executorBizRepository.put(address, executorBiz);
        return executorBiz;
    }

    // ---------------------- schedule util ----------------------

 	........................................

    /**
     * addJob
     *
     * @param jobName
     * @param jobGroup
     * @param cronExpression
     * @return
     * @throws SchedulerException
     */
	public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {
    	// TriggerKey : name + group
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        JobKey jobKey = new JobKey(jobName, jobGroup);
        
        // TriggerKey valid if_exists
        if (checkExists(jobName, jobGroup)) {
            logger.info(">>>>>>>>> addJob fail, job already exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
            return false;
        }
        
        // CronTrigger : TriggerKey + cronExpression	// withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

        // JobDetail : jobClass
		Class<? extends Job> jobClass_ = RemoteHttpJobBean.class;   // Class.forName(jobInfo.getJobClass());
        
		JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
        /*if (jobInfo.getJobData()!=null) {
        	JobDataMap jobDataMap = jobDetail.getJobDataMap();
        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	
        	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
		}*/
        
        // schedule : jobDetail + cronTrigger
        Date date = scheduler.scheduleJob(jobDetail, cronTrigger);

        logger.info(">>>>>>>>>>> addJob success, jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
        return true;
    }
    
    ..............................

}


```

* 代码太长，这里我们主要关注两点，init()和addJob(String jobName, String jobGroup, String cronExpression)方法
* init()内会初始化两个线程，JobRegistryMonitorHelper和JobFailMonitorHelper
	* JobRegistryMonitorHelper用于监控执行器的注册
	* JobFailMonitorHelper用于监控任务执行结果
* init()还会初始化NetComServerFactory类，此类主要的作用在于对AdminBizImpl做了一层代理，实际调用的方法还是AdminBizImpl的方法
* getExecutorBiz()主要为每个地址生成一个```ExecutorBiz```的代理类，此代理类主要的作用是发送http请求，这里不做过多赘述
* addJob()其实就是向quartz内添加一个job
* 此类中还有其他的比如暂停任务，重新运行任务等其他方法这里就不过多介绍。


### 调度中心触发任务

* 调度中心按照cron表达式新建好任务之后，就是等待quartz定时的去执行任务了。
* 细心的朋友可能发现了，addJob()内向quartz集群中添加的job固定为```RemoteHttpJobBean```。

```java

 
//@DisallowConcurrentExecution
public class RemoteHttpJobBean extends QuartzJobBean {
    private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);

    @Override
    protected void executeInternal(JobExecutionContext context)
            throws JobExecutionException {

        // load jobId
        JobKey jobKey = context.getTrigger().getJobKey();
        Integer jobId = Integer.valueOf(jobKey.getName());

        // trigger
        XxlJobTrigger.trigger(jobId);
    }

}

```

* 可以看到，定时任务启动后，调用```RemoteHttpJobBean```的方法，其实已经代理给了```XxlJobTrigger```类了

```java


/**
 * xxl-job trigger
 * Created by xuxueli on 17/7/13.
 */
public class XxlJobTrigger {
    private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);

    /**
     * trigger job
     *
     * @param jobId
     */
    public static void trigger(int jobId) {

        // load data
        XxlJobInfo jobInfo = XxlJobDynamicScheduler.xxlJobInfoDao.loadById(jobId);              // job info
        if (jobInfo == null) {
            logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid，jobId={}", jobId);
            return;
        }
        XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(jobInfo.getJobGroup());  // group info

        //阻塞策略
        ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION);  // block strategy
        //失败策略
        ExecutorFailStrategyEnum failStrategy = ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), ExecutorFailStrategyEnum.FAIL_ALARM);    // fail strategy
        //路由策略
        ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);    // route strategy
        ArrayList<String> addressList = (ArrayList<String>) group.getRegistryList();

        // broadcast
        if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum && CollectionUtils.isNotEmpty(addressList)) {
            //数据分片先略过
            ...........

        } else {
            // 1、save log-id
            XxlJobLog jobLog = new XxlJobLog();
            jobLog.setJobGroup(jobInfo.getJobGroup());
            jobLog.setJobId(jobInfo.getId());
            XxlJobDynamicScheduler.xxlJobLogDao.save(jobLog);
            logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());

            // 2、prepare trigger-info
            //jobLog.setExecutorAddress(executorAddress);
            jobLog.setGlueType(jobInfo.getGlueType());
            jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
            jobLog.setExecutorParam(jobInfo.getExecutorParam());
            jobLog.setTriggerTime(new Date());

            ReturnT<String> triggerResult = new ReturnT<String>(null);
            StringBuffer triggerMsgSb = new StringBuffer();
            triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append("：").append(IpUtil.getIp());
            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append("：")
                    .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append("：").append(group.getRegistryList());
            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append("：").append(executorRouteStrategyEnum.getTitle());
            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append("：").append(blockStrategy.getTitle());
            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append("：").append(failStrategy.getTitle());

            // 3、trigger-valid      验证是否有可用的执行器
            if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
                triggerResult.setCode(ReturnT.FAIL_CODE);
                triggerMsgSb.append("<br>----------------------<br>").append(I18nUtil.getString("jobconf_trigger_address_empty"));
            }

            if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
                // 4.1、trigger-param    准备参数
                TriggerParam triggerParam = new TriggerParam();
                triggerParam.setJobId(jobInfo.getId());
                triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
                triggerParam.setExecutorParams(jobInfo.getExecutorParam());
                triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
                triggerParam.setLogId(jobLog.getId());
                triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime());
                triggerParam.setGlueType(jobInfo.getGlueType());
                triggerParam.setGlueSource(jobInfo.getGlueSource());
                triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
                triggerParam.setBroadcastIndex(0);
                triggerParam.setBroadcastTotal(1);

                // 4.2、trigger-run (route run / trigger remote executor)
                //根据路由策略获取address然后去执行
                triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
                triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());

                // 4.3、trigger (fail retry)
                //如果设置了失败重试的策略，如果调用不成功，会再调用一次
                if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
                    triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
                    triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_fail_retry") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
                }
            }

            // 5、save trigger-info
            jobLog.setExecutorAddress(triggerResult.getContent());
            jobLog.setTriggerCode(triggerResult.getCode());
            jobLog.setTriggerMsg(triggerMsgSb.toString());
            XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);

            // 6、monitor trigger
            //添加任务执行失败监控
            JobFailMonitorHelper.monitor(jobLog.getId());
            logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
        }

    }

    /**
     * run executor
     * @param triggerParam
     * @param address
     * @return  ReturnT.content: final address
     */
    public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
        ReturnT<String> runResult = null;
        try {
            //获取ExecutorBiz，然后去执行
            //获取到的是个代理类
            //实际上就是个http请求
            ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
            runResult = executorBiz.run(triggerParam);
        } catch (Exception e) {
            logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
        }

        StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + "：");
        runResultSB.append("<br>address：").append(address);
        runResultSB.append("<br>code：").append(runResult.getCode());
        runResultSB.append("<br>msg：").append(runResult.getMsg());

        runResult.setMsg(runResultSB.toString());
        runResult.setContent(address);
        return runResult;
    }

}


```

* 先获取到任务中配置的阻塞、失败重试(只针对调用)、路由策略。
* 添加trigger调用日志
* 准备传递参数
* 验证是否有可用的执行器
* 根据路由策略去调用执行，实际上是通过```NetComClientProxy```工厂类获取代理生成```ExecutorBiz```的去执行的
* 调用失败如果设置了失败重试则会再调用一次
* 把当前任务添加到任务执行结果监控线程中去
* 各种执行策略可以自己单独去看或者后面会单独拉出一篇文章来讲解

```java

public class NetComClientProxy implements FactoryBean<Object> {
    private static final Logger logger = LoggerFactory.getLogger(NetComClientProxy.class);

    // ---------------------- config ----------------------
    private Class<?> iface;
    private String serverAddress;
    private String accessToken;
    private JettyClient client = new JettyClient();
    public NetComClientProxy(Class<?> iface, String serverAddress, String accessToken) {
        this.iface = iface;
        this.serverAddress = serverAddress;
        this.accessToken = accessToken;
    }

    @Override
    public Object getObject() throws Exception {
        return Proxy.newProxyInstance(Thread.currentThread()
                .getContextClassLoader(), new Class[] { iface },
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        // filter method like "Object.toString()"
                        if (Object.class.getName().equals(method.getDeclaringClass().getName())) {
                            logger.error(">>>>>>>>>>> xxl-rpc proxy class-method not support [{}.{}]", method.getDeclaringClass().getName(), method.getName());
                            throw new RuntimeException("xxl-rpc proxy class-method not support");
                        }
                        
                        // request
                        RpcRequest request = new RpcRequest();
                        request.setServerAddress(serverAddress);
                        request.setCreateMillisTime(System.currentTimeMillis());
                        request.setAccessToken(accessToken);
                        request.setClassName(method.getDeclaringClass().getName());
                        request.setMethodName(method.getName());
                        request.setParameterTypes(method.getParameterTypes());
                        request.setParameters(args);

                        // send
                        RpcResponse response = client.send(request);
                        
                        // valid response
                        if (response == null) {
                            logger.error(">>>>>>>>>>> xxl-rpc netty response not found.");
                            throw new Exception(">>>>>>>>>>> xxl-rpc netty response not found.");
                        }
                        if (response.isError()) {
                            throw new RuntimeException(response.getError());
                        } else {
                            return response.getResult();
                        }
                       
                    }
                });
    }
    @Override
    public Class<?> getObjectType() {
        return iface;
    }
    @Override
    public boolean isSingleton() {
        return false;
    }

}

public class JettyClient {
    private static Logger logger = LoggerFactory.getLogger(JettyClient.class);

    public RpcResponse send(RpcRequest request) throws Exception {
        try {
            // serialize request
            byte[] requestBytes = HessianSerializer.serialize(request);

            // reqURL
            String reqURL = request.getServerAddress();
            if (reqURL!=null && reqURL.toLowerCase().indexOf("http")==-1) {
                reqURL = "http://" + request.getServerAddress() + "/";  // IP:PORT, need parse to url
            }

            // remote invoke
            byte[] responseBytes = HttpClientUtil.postRequest(reqURL, requestBytes);
            if (responseBytes == null || responseBytes.length==0) {
                RpcResponse rpcResponse = new RpcResponse();
                rpcResponse.setError("RpcResponse byte[] is null");
                return rpcResponse;
            }

            // deserialize response
            RpcResponse rpcResponse = (RpcResponse) HessianSerializer.deserialize(responseBytes, RpcResponse.class);
            return rpcResponse;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);

            RpcResponse rpcResponse = new RpcResponse();
            rpcResponse.setError("Client-error:" + e.getMessage());
            return rpcResponse;
        }
    }

}

```

* NetComClientProxy生产的ExecutorBiz类，实际上就是一个http请求的方法
* http请求的序列化采用的hessian

### 总结前两步的调用链，调度中心->执行器

1. XxlJobDynamicScheduler.addJob()添加任务到quartz
2. RemoteHttpJobBean.executeInternal()定时触发任务执行
3. XxlJobTrigger.trigger()
4. XxlJobDynamicScheduler.getExecutorBiz() -> NetComClientProxy.getObject()获取代理的ExecutorBiz
5. ExecutorBiz.run() -> JettyClient.send()通过http请求调用执行器
6. 此处忽略了各种执行策略

### 执行器启动

执行器启动的时候，需要初始化```XxlJobExecutor```类，此类在初始化的时候，会进行一系列的准备。

```java

/**
 * Created by xuxueli on 2016/3/2 21:14.
 */
public class XxlJobExecutor implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);

    // ---------------------- param ----------------------
    private String adminAddresses;
    private String appName;
    private String ip;
    private int port;
    private String accessToken;
    private String logPath;
    private int logRetentionDays;

    public void setAdminAddresses(String adminAddresses) {
        this.adminAddresses = adminAddresses;
    }
    public void setAppName(String appName) {
        this.appName = appName;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
    public void setLogPath(String logPath) {
        this.logPath = logPath;
    }
    public void setLogRetentionDays(int logRetentionDays) {
        this.logRetentionDays = logRetentionDays;
    }

    // ---------------------- applicationContext ----------------------
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }


    // ---------------------- start + stop ----------------------
    public void start() throws Exception {
        // init admin-client 初始化admin-http-client
        initAdminBizList(adminAddresses, accessToken);

        // init executor-jobHandlerRepository 初始化jobHandler
        initJobHandlerRepository(applicationContext);

        // init logpath 初始化XxlJobLog
        XxlJobFileAppender.initLogPath(logPath);

        // init executor-server 初始化内嵌的jetty服务器
        initExecutorServer(port, ip, appName, accessToken);

        // init JobLogFileCleanThread   初始化定时清理日志线程
        JobLogFileCleanThread.getInstance().start(logRetentionDays);
    }
    public void destroy(){
        // destory JobThreadRepository
        if (JobThreadRepository.size() > 0) {
            for (Map.Entry<Integer, JobThread> item: JobThreadRepository.entrySet()) {
                removeJobThread(item.getKey(), "Web容器销毁终止");
            }
            JobThreadRepository.clear();
        }

        // destory executor-server
        stopExecutorServer();

        // destory JobLogFileCleanThread
        JobLogFileCleanThread.getInstance().toStop();
    }


    // ---------------------- admin-client ----------------------
    private static List<AdminBiz> adminBizList;
    private static void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
        if (adminAddresses!=null && adminAddresses.trim().length()>0) {
            for (String address: adminAddresses.trim().split(",")) {
                if (address!=null && address.trim().length()>0) {
                    String addressUrl = address.concat(AdminBiz.MAPPING);
                    AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, addressUrl, accessToken).getObject();
                    if (adminBizList == null) {
                        adminBizList = new ArrayList<AdminBiz>();
                    }
                    adminBizList.add(adminBiz);
                }
            }
        }
    }
    public static List<AdminBiz> getAdminBizList(){
        return adminBizList;
    }


    // ---------------------- executor-server(jetty) ----------------------
    private NetComServerFactory serverFactory = new NetComServerFactory();
    private void initExecutorServer(int port, String ip, String appName, String accessToken) throws Exception {
        // valid param
        port = port>0?port: NetUtil.findAvailablePort(9999);

        // start server
        NetComServerFactory.putService(ExecutorBiz.class, new ExecutorBizImpl());   // rpc-service, base on jetty
        NetComServerFactory.setAccessToken(accessToken);
        serverFactory.start(port, ip, appName); // jetty + registry
    }
    private void stopExecutorServer() {
        serverFactory.destroy();    // jetty + registry + callback
    }


    // ---------------------- job handler repository ----------------------
    private static ConcurrentHashMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
    public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
        logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
        return jobHandlerRepository.put(name, jobHandler);
    }
    public static IJobHandler loadJobHandler(String name){
        return jobHandlerRepository.get(name);
    }
    private static void initJobHandlerRepository(ApplicationContext applicationContext){
        if (applicationContext == null) {
            return;
        }

        // init job handler action
        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);

        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
            for (Object serviceBean : serviceBeanMap.values()) {
                if (serviceBean instanceof IJobHandler){
                    String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
                    IJobHandler handler = (IJobHandler) serviceBean;
                    if (loadJobHandler(name) != null) {
                        throw new RuntimeException("xxl-job jobhandler naming conflicts.");
                    }
                    registJobHandler(name, handler);
                }
            }
        }
    }


    // ---------------------- job thread repository ----------------------
    private static ConcurrentHashMap<Integer, JobThread> JobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();
    public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){
        JobThread newJobThread = new JobThread(jobId, handler);
        newJobThread.start();
        logger.info(">>>>>>>>>>> xxl-job regist JobThread success, jobId:{}, handler:{}", new Object[]{jobId, handler});

        JobThread oldJobThread = JobThreadRepository.put(jobId, newJobThread);  // putIfAbsent | oh my god, map's put method return the old value!!!
        if (oldJobThread != null) {
            oldJobThread.toStop(removeOldReason);
            oldJobThread.interrupt();
        }

        return newJobThread;
    }
    public static void removeJobThread(int jobId, String removeOldReason){
        JobThread oldJobThread = JobThreadRepository.remove(jobId);
        if (oldJobThread != null) {
            oldJobThread.toStop(removeOldReason);
            oldJobThread.interrupt();
        }
    }
    public static JobThread loadJobThread(int jobId){
        JobThread jobThread = JobThreadRepository.get(jobId);
        return jobThread;
    }

}


```

* 主要关注XxlJobExecutor的init方法
* 初始化AdminBiz的类集合，通过工厂类生产的代理类，生成的方法雷同前面的代理ExecutorBiz类，实际上也是一个NetComClientProxy.getObject()，http请求的地址为"调用中心地址+/api"
* 初始化jobHandler，也就是实际的任务执行类
* 初始化XxlJobLog，通过此log记录日志，日志记录到执行器服务器的文件内。
* 初始化执行器内嵌的jetty服务器，端口号默认9999；初始化内嵌服务器时，还会启动一个执行器自动注册到调度中心的线程。
* 初始化自动清除XxlJobLog生产的日志文件的线程

#### 初始化AdminBiz类的集合

前面有讲过，再调度中心调用执行器的过程中，是通过NetComClientProxy工厂类生产的代理ExecutorBiz类，此生成的类实际上就是封装了一个http请求；这里出书画生成的AdminBiz类也是如此，实际上就是封装了一个http请求

#### 初始化jobHandler

jobHandler在xxl-job中，就是执行器的实际任务执行类，例子如下：

```java

@JobHandler(value="demoJobHandler")
@Component
public class DemoJobHandler extends IJobHandler {

    @Override
    public ReturnT<String> execute(String param) throws Exception {
        XxlJobLogger.log("XXL-JOB, Hello World.");

        for (int i = 0; i < 5; i++) {
            XxlJobLogger.log("beat at:" + i);
            TimeUnit.SECONDS.sleep(2);
        }
        return SUCCESS;
    }

}

```

* demoJobHandler在调度中心中添加任务的时候需要用到

#### 初始化XxlJobLog

```java

/**
 * store trigger log in each log-file
 * @author xuxueli 2016-3-12 19:25:12
 */
public class XxlJobFileAppender {
    private static Logger logger = LoggerFactory.getLogger(XxlJobFileAppender.class);
    
    // for JobThread (support log for child thread of job handler)
    //public static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();


    /**
     * log base path
     *
     * strut like:
     *  ---/
     *  ---/gluesource/
     *  ---/gluesource/10_1514171108000.js
     *  ---/gluesource/10_1514171108000.js
     *  ---/2017-12-25/
     *  ---/2017-12-25/639.log
     *  ---/2017-12-25/821.log
     *
     */
    private static String logBasePath = "/data/applogs/xxl-job/jobhandler";
    private static String glueSrcPath = logBasePath.concat("/gluesource");
    public static void initLogPath(String logPath){
        // init
        if (logPath!=null && logPath.trim().length()>0) {
            logBasePath = logPath;
        }
        // mk base dir
        File logPathDir = new File(logBasePath);
        if (!logPathDir.exists()) {
            logPathDir.mkdirs();
        }
        logBasePath = logPathDir.getPath();

        // mk glue dir
        File glueBaseDir = new File(logPathDir, "gluesource");
        if (!glueBaseDir.exists()) {
            glueBaseDir.mkdirs();
        }
        glueSrcPath = glueBaseDir.getPath();
    }
    
    ........

}


```
* 主要是初始化日志存放的路径和glue过来的代码存放路径


#### 初始化jetty服务器

```java

public class JettyServer {
    private static final Logger logger = LoggerFactory.getLogger(JettyServer.class);

    private Server server;
    private Thread thread;
    public void start(final int port, final String ip, final String appName) throws Exception {
        thread = new Thread(new Runnable() {
            @Override
            public void run() {

                // The Server
                server = new Server(new ExecutorThreadPool());  // 非阻塞

                // HTTP connector
                ServerConnector connector = new ServerConnector(server);
                if (ip!=null && ip.trim().length()>0) {
                    connector.setHost(ip);  // The network interface this connector binds to as an IP address or a hostname.  If null or 0.0.0.0, then bind to all interfaces.
                }
                connector.setPort(port);
                server.setConnectors(new Connector[]{connector});

                // Set a handler
                HandlerCollection handlerc =new HandlerCollection();
                handlerc.setHandlers(new Handler[]{new JettyServerHandler()});
                server.setHandler(handlerc);

                try {
                    // Start server 启动内嵌服务器
                    server.start();
                    logger.info(">>>>>>>>>>> xxl-job jetty server start success at port:{}.", port);

                    // Start Registry-Server 自动注册线程
                    ExecutorRegistryThread.getInstance().start(port, ip, appName);

                    // Start Callback-Server 任务执行结束异步回调线程
                    TriggerCallbackThread.getInstance().start();

                    server.join();  // block until thread stopped
                    logger.info(">>>>>>>>>>> xxl-rpc server join success, netcon={}, port={}", JettyServer.class.getName(), port);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                } finally {
                    //destroy();
                }
            }
        });
        thread.setDaemon(true); // daemon, service jvm, user thread leave >>> daemon leave >>> jvm leave
        thread.start();
    }

    ......

}

```

* 启动内嵌的jetty服务器，设置JettyServerHandler，当接受到调用请求后，会调用此类
* 启动自动注册到调度中心线程
* 启动任务执行结束异步回调线程


### 执行器执行任务

执行器收到请求后，调用```JettyServerHandler```的handle方法

```java

/**
 * jetty handler
 * @author xuxueli 2015-11-19 22:32:36
 */
public class JettyServerHandler extends AbstractHandler {
    private static Logger logger = LoggerFactory.getLogger(JettyServerHandler.class);

    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        
        // invoke
        RpcResponse rpcResponse = doInvoke(request);

        // serialize response
        byte[] responseBytes = HessianSerializer.serialize(rpcResponse);
        
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        baseRequest.setHandled(true);
        
        OutputStream out = response.getOutputStream();
        out.write(responseBytes);
        out.flush();
        
    }

    private RpcResponse doInvoke(HttpServletRequest request) {
        try {
            // deserialize request
            byte[] requestBytes = HttpClientUtil.readBytes(request);
            if (requestBytes == null || requestBytes.length==0) {
                RpcResponse rpcResponse = new RpcResponse();
                rpcResponse.setError("RpcRequest byte[] is null");
                return rpcResponse;
            }
            //hession 反序列化
            RpcRequest rpcRequest = (RpcRequest) HessianSerializer.deserialize(requestBytes, RpcRequest.class);

            // invoke 实际调用
            RpcResponse rpcResponse = NetComServerFactory.invokeService(rpcRequest, null);
            return rpcResponse;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);

            RpcResponse rpcResponse = new RpcResponse();
            rpcResponse.setError("Server-error:" + e.getMessage());
            return rpcResponse;
        }
    }

}

public class NetComServerFactory  {
    private static final Logger logger = LoggerFactory.getLogger(NetComServerFactory.class);

    // ---------------------- server start ----------------------
    JettyServer server = new JettyServer();
    public void start(int port, String ip, String appName) throws Exception {
        server.start(port, ip, appName);
    }

    // ---------------------- server destroy ----------------------
    public void destroy(){
        server.destroy();
    }

    // ---------------------- server instance ----------------------
    /**
     * init local rpc service map
     */
    private static Map<String, Object> serviceMap = new HashMap<String, Object>();
    private static String accessToken;
    public static void putService(Class<?> iface, Object serviceBean){
        serviceMap.put(iface.getName(), serviceBean);
    }
    public static void setAccessToken(String accessToken) {
        NetComServerFactory.accessToken = accessToken;
    }
    public static RpcResponse invokeService(RpcRequest request, Object serviceBean) {
        if (serviceBean==null) {
            serviceBean = serviceMap.get(request.getClassName());
        }
        if (serviceBean == null) {
            // TODO
        }

        RpcResponse response = new RpcResponse();

        if (System.currentTimeMillis() - request.getCreateMillisTime() > 180000) {
            response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The timestamp difference between admin and executor exceeds the limit."));
            return response;
        }
        if (accessToken!=null && accessToken.trim().length()>0 && !accessToken.trim().equals(request.getAccessToken())) {
            response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The access token[" + request.getAccessToken() + "] is wrong."));
            return response;
        }

        try {
            Class<?> serviceClass = serviceBean.getClass();
            //获取调度中心调用的方法
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParameterTypes();
            Object[] parameters = request.getParameters();

            FastClass serviceFastClass = FastClass.create(serviceClass);
            FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);
            //去实际调用方法
            Object result = serviceFastMethod.invoke(serviceBean, parameters);

            response.setResult(result);
        } catch (Throwable t) {
            t.printStackTrace();
            response.setError(t.getMessage());
        }

        return response;
    }

}

```

* 首先通过hession反序列化获取调度中心传过来的数据，内包含serviceBean和调用方法
* serviceMap.get(request.getClassName());获取的一般就是ExecutorBizImpl类，在XxlJobExecutor初始化的时候会添加进serviceMap中
* 根据传过来的调用方法名称（run()方法），通过反射调用

下面来看看ExecutorBizImpl的run方法

```java

    @Override
    public ReturnT<String> run(TriggerParam triggerParam) {
        // load old：jobHandler + jobThread
        JobThread jobThread = XxlJobExecutor.loadJobThread(triggerParam.getJobId());
        IJobHandler jobHandler = jobThread!=null?jobThread.getHandler():null;
        String removeOldReason = null;

        // valid：jobHandler + jobThread
        GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerParam.getGlueType());
        if (GlueTypeEnum.BEAN == glueTypeEnum) {

            // new jobhandler
            IJobHandler newJobHandler = XxlJobExecutor.loadJobHandler(triggerParam.getExecutorHandler());

            // valid old jobThread
            if (jobThread!=null && jobHandler != newJobHandler) {
                // change handler, need kill old thread
                removeOldReason = "更换JobHandler或更换任务模式,终止旧任务线程";

                jobThread = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                jobHandler = newJobHandler;
                if (jobHandler == null) {
                    return new ReturnT<String>(ReturnT.FAIL_CODE, "job handler [" + triggerParam.getExecutorHandler() + "] not found.");
                }
            }

        } else if (GlueTypeEnum.GLUE_GROOVY == glueTypeEnum) {

            // valid old jobThread
            if (jobThread != null &&
                    !(jobThread.getHandler() instanceof GlueJobHandler
                        && ((GlueJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {
                // change handler or gluesource updated, need kill old thread
                removeOldReason = "更新任务逻辑或更换任务模式,终止旧任务线程";

                jobThread = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                try {
                    IJobHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerParam.getGlueSource());
                    jobHandler = new GlueJobHandler(originJobHandler, triggerParam.getGlueUpdatetime());
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
                }
            }
        } else if (glueTypeEnum!=null && glueTypeEnum.isScript()) {

            // valid old jobThread
            if (jobThread != null &&
                    !(jobThread.getHandler() instanceof ScriptJobHandler
                            && ((ScriptJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {
                // change script or gluesource updated, need kill old thread
                removeOldReason = "更新任务逻辑或更换任务模式,终止旧任务线程";

                jobThread = null;
                jobHandler = null;
            }

            // valid handler
            if (jobHandler == null) {
                jobHandler = new ScriptJobHandler(triggerParam.getJobId(), triggerParam.getGlueUpdatetime(), triggerParam.getGlueSource(), GlueTypeEnum.match(triggerParam.getGlueType()));
            }
        } else {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "glueType[" + triggerParam.getGlueType() + "] is not valid.");
        }

        // executor block strategy
        if (jobThread != null) {
            ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(triggerParam.getExecutorBlockStrategy(), null);
            if (ExecutorBlockStrategyEnum.DISCARD_LATER == blockStrategy) {
                // discard when running
                if (jobThread.isRunningOrHasQueue()) {
                    return new ReturnT<String>(ReturnT.FAIL_CODE, "阻塞处理策略-生效："+ExecutorBlockStrategyEnum.DISCARD_LATER.getTitle());
                }
            } else if (ExecutorBlockStrategyEnum.COVER_EARLY == blockStrategy) {
                // kill running jobThread
                if (jobThread.isRunningOrHasQueue()) {
                    removeOldReason = "阻塞处理策略-生效：" + ExecutorBlockStrategyEnum.COVER_EARLY.getTitle();

                    jobThread = null;
                }
            } else {
                // just queue trigger
            }
        }

        // replace thread (new or exists invalid)
        if (jobThread == null) {
            jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);
        }

        // push data to queue
        ReturnT<String> pushResult = jobThread.pushTriggerQueue(triggerParam);
        return pushResult;
    }

```

* 根据调度中心配置的任务执行方法，分为三种：bean、glue、脚本（shell，python等），这里先不讨论他们具体的实现方式，主要讨论bean的方式
* 先去缓存中获取jobThread，一个jobId一般只会有一个线程（再不考虑堵塞策略和线程生命周期的情况下）
* 如果jobThread已经存在，并且老的jobHandler和新的jobHandler不一致，则会把jobHandler设置为新的，并且重新生成一个新的jobThread代替老的
* 如果jobThread不存在，则会生成一个新的jobThread，用于执行任务
* 把任务推送到jobThread队列中
* 注意：这里有一点要注意的地方是，阻塞策略是调度中心传递到执行来实现的。
    - 阻塞策略的覆盖策略，如果任务已经开始执行，则要等待此任务执行完

```java

/**
 * handler thread
 * @author xuxueli 2016-1-16 19:52:47
 */
public class JobThread extends Thread{
    private static Logger logger = LoggerFactory.getLogger(JobThread.class);

    private int jobId;
    private IJobHandler handler;
    private LinkedBlockingQueue<TriggerParam> triggerQueue;
    private ConcurrentHashSet<Integer> triggerLogIdSet;     // avoid repeat trigger for the same TRIGGER_LOG_ID

    private boolean toStop = false;
    private String stopReason;

    private boolean running = false;    // if running job
    private int idleTimes = 0;          // idel times


    public JobThread(int jobId, IJobHandler handler) {
        this.jobId = jobId;
        this.handler = handler;
        this.triggerQueue = new LinkedBlockingQueue<TriggerParam>();
        this.triggerLogIdSet = new ConcurrentHashSet<Integer>();
    }
    public IJobHandler getHandler() {
        return handler;
    }

    /**
     * new trigger to queue
     *
     * @param triggerParam
     * @return
     */
    public ReturnT<String> pushTriggerQueue(TriggerParam triggerParam) {
        // avoid repeat
        if (triggerLogIdSet.contains(triggerParam.getLogId())) {
            logger.info(">>>>>>>>>>> repeate trigger job, logId:{}", triggerParam.getLogId());
            return new ReturnT<String>(ReturnT.FAIL_CODE, "repeate trigger job, logId:" + triggerParam.getLogId());
        }

        triggerLogIdSet.add(triggerParam.getLogId());
        triggerQueue.add(triggerParam);
        return ReturnT.SUCCESS;
    }

    /**
     * kill job thread
     *
     * @param stopReason
     */
    public void toStop(String stopReason) {
        /**
         * Thread.interrupt只支持终止线程的阻塞状态(wait、join、sleep)，
         * 在阻塞出抛出InterruptedException异常,但是并不会终止运行的线程本身；
         * 所以需要注意，此处彻底销毁本线程，需要通过共享变量方式；
         */
        this.toStop = true;
        this.stopReason = stopReason;
    }

    /**
     * is running job
     * @return
     */
    public boolean isRunningOrHasQueue() {
        return running || triggerQueue.size()>0;
    }

    @Override
    public void run() {

        // init
        try {
            handler.init();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }

        // execute
        while(!toStop){
            running = false;
            idleTimes++;

            TriggerParam triggerParam = null;
            ReturnT<String> executeResult = null;
            try {
                // to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)
                triggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);
                if (triggerParam!=null) {
                    running = true;
                    idleTimes = 0;
                    triggerLogIdSet.remove(triggerParam.getLogId());

                    // log filename, like "logPath/yyyy-MM-dd/9999.log"
                    String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTim()), triggerParam.getLogId());
                    XxlJobFileAppender.contextHolder.set(logFileName);
                    ShardingUtil.setShardingVo(new ShardingUtil.ShardingVO(triggerParam.getBroadcastIndex(), triggerParam.getBroadcastTotal()));

                    // execute
                    XxlJobLogger.log("<br>----------- xxl-job job execute start -----------<br>----------- Param:" + triggerParam.getExecutorParams());
                    executeResult = handler.execute(triggerParam.getExecutorParams());
                    if (executeResult == null) {
                        executeResult = IJobHandler.FAIL;
                    }
                    XxlJobLogger.log("<br>----------- xxl-job job execute end(finish) -----------<br>----------- ReturnT:" + executeResult);

                } else {
                    if (idleTimes > 30) {
                        XxlJobExecutor.removeJobThread(jobId, "excutor idel times over limit.");
                    }
                }
            } catch (Throwable e) {
                if (toStop) {
                    XxlJobLogger.log("<br>----------- JobThread toStop, stopReason:" + stopReason);
                }

                StringWriter stringWriter = new StringWriter();
                e.printStackTrace(new PrintWriter(stringWriter));
                String errorMsg = stringWriter.toString();
                executeResult = new ReturnT<String>(ReturnT.FAIL_CODE, errorMsg);

                XxlJobLogger.log("<br>----------- JobThread Exception:" + errorMsg + "<br>----------- xxl-job job execute end(error) -----------");
            } finally {
                if(triggerParam != null) {
                    // callback handler info
                    if (!toStop) {
                        // commonm
                        TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), executeResult));
                    } else {
                        // is killed
                        ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [业务运行中，被强制终止]");
                        TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), stopResult));
                    }
                }
            }
        }

        // callback trigger request in queue
        while(triggerQueue !=null && triggerQueue.size()>0){
            TriggerParam triggerParam = triggerQueue.poll();
            if (triggerParam!=null) {
                // is killed
                ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [任务尚未执行，在调度队列中被终止]");
                TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), stopResult));
            }
        }

        // destroy
        try {
            handler.destroy();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }

        logger.info(">>>>>>>>>>> xxl-job JobThread stoped, hashCode:{}", Thread.currentThread());
    }
}


```
* 基本就是从队列中取出任务，获取jobHandler，然后执行
* 执行玩之后，会把任务执行结果添加到TriggerCallbackThread线程中


```java

/**
 * Created by xuxueli on 16/7/22.
 */
public class TriggerCallbackThread {
    private static Logger logger = LoggerFactory.getLogger(TriggerCallbackThread.class);

    private static TriggerCallbackThread instance = new TriggerCallbackThread();
    public static TriggerCallbackThread getInstance(){
        return instance;
    }

    /**
     * job results callback queue
     */
    private LinkedBlockingQueue<HandleCallbackParam> callBackQueue = new LinkedBlockingQueue<HandleCallbackParam>();
    public static void pushCallBack(HandleCallbackParam callback){
        getInstance().callBackQueue.add(callback);
        logger.debug(">>>>>>>>>>> xxl-job, push callback request, logId:{}", callback.getLogId());
    }

    /**
     * callback thread
     */
    private Thread triggerCallbackThread;
    private volatile boolean toStop = false;
    public void start() {

        // valid
        if (XxlJobExecutor.getAdminBizList() == null) {
            logger.warn(">>>>>>>>>>> xxl-job, executor callback config fail, adminAddresses is null.");
            return;
        }

        triggerCallbackThread = new Thread(new Runnable() {

            @Override
            public void run() {

                // normal callback
                while(!toStop){
                    try {
                        HandleCallbackParam callback = getInstance().callBackQueue.take();
                        if (callback != null) {

                            // callback list param
                            List<HandleCallbackParam> callbackParamList = new ArrayList<HandleCallbackParam>();
                            int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);
                            callbackParamList.add(callback);

                            // callback, will retry if error
                            if (callbackParamList!=null && callbackParamList.size()>0) {
                                doCallback(callbackParamList);
                            }
                        }
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }

                // last callback
                try {
                    List<HandleCallbackParam> callbackParamList = new ArrayList<HandleCallbackParam>();
                    int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);
                    if (callbackParamList!=null && callbackParamList.size()>0) {
                        doCallback(callbackParamList);
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
                logger.info(">>>>>>>>>>> xxl-job, executor callback thread destory.");

            }
        });
        triggerCallbackThread.setDaemon(true);
        triggerCallbackThread.start();
    }
    public void toStop(){
        toStop = true;
        // interrupt and wait
        triggerCallbackThread.interrupt();
        try {
            triggerCallbackThread.join();
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * do callback, will retry if error
     * @param callbackParamList
     */
    private void doCallback(List<HandleCallbackParam> callbackParamList){
        // callback, will retry if error
        for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
            try {
                ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
                if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
                    callbackResult = ReturnT.SUCCESS;
                    logger.info(">>>>>>>>>>> xxl-job callback success, callbackParamList:{}, callbackResult:{}", new Object[]{callbackParamList, callbackResult});
                    break;
                } else {
                    logger.info(">>>>>>>>>>> xxl-job callback fail, callbackParamList:{}, callbackResult:{}", new Object[]{callbackParamList, callbackResult});
                }
            } catch (Exception e) {
                logger.error(">>>>>>>>>>> xxl-job callback error, callbackParamList：{}", callbackParamList, e);
                //getInstance().callBackQueue.addAll(callbackParamList);
            }
        }
    }

}


```

* 先从队列中取出任务执行结果
* 通过admin-http-client（前面初始化的AdminBiz代理类）逐个调用，直至成功，如果全部失败不会重试（被注释掉了，不知道为什么）


调度中心对执行器开放的接口

```java

@Controller
public class JobApiController {
    private static Logger logger = LoggerFactory.getLogger(JobApiController.class);

    private RpcResponse doInvoke(HttpServletRequest request) {
        try {
            // deserialize request
            byte[] requestBytes = HttpClientUtil.readBytes(request);
            if (requestBytes == null || requestBytes.length==0) {
                RpcResponse rpcResponse = new RpcResponse();
                rpcResponse.setError("RpcRequest byte[] is null");
                return rpcResponse;
            }
            RpcRequest rpcRequest = (RpcRequest) HessianSerializer.deserialize(requestBytes, RpcRequest.class);

            // invoke
            RpcResponse rpcResponse = NetComServerFactory.invokeService(rpcRequest, null);
            return rpcResponse;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);

            RpcResponse rpcResponse = new RpcResponse();
            rpcResponse.setError("Server-error:" + e.getMessage());
            return rpcResponse;
        }
    }

    @RequestMapping(AdminBiz.MAPPING)
    @PermessionLimit(limit=false)
    public void api(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // invoke
        RpcResponse rpcResponse = doInvoke(request);

        // serialize response
        byte[] responseBytes = HessianSerializer.serialize(rpcResponse);

        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        //baseRequest.setHandled(true);

        OutputStream out = response.getOutputStream();
        out.write(responseBytes);
        out.flush();
    }

}


```

* 执行器注册和执行器结果的异步回调都是统一调用此接口
* 然后去实际的调用AdminBizImpl类中的具体方法，下面是AdminBizImpl

```java

public class AdminBizImpl implements AdminBiz {
    private static Logger logger = LoggerFactory.getLogger(AdminBizImpl.class);

    @Resource
    public XxlJobLogDao xxlJobLogDao;
    @Resource
    private XxlJobInfoDao xxlJobInfoDao;
    @Resource
    private XxlJobRegistryDao xxlJobRegistryDao;
    @Resource
    private XxlJobService xxlJobService;


    @Override
    public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
        for (HandleCallbackParam handleCallbackParam: callbackParamList) {
            ReturnT<String> callbackResult = callback(handleCallbackParam);
            logger.info(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
                    (callbackResult.getCode()==IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult);
        }

        return ReturnT.SUCCESS;
    }

    private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
        // valid log item
        XxlJobLog log = xxlJobLogDao.load(handleCallbackParam.getLogId());
        if (log == null) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
        }
        if (log.getHandleCode() > 0) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback.");     // avoid repeat callback, trigger child job etc
        }

        // trigger success, to trigger child job
        String callbackMsg = null;
        if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
            XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
            if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) {
                callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";

                String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
                for (int i = 0; i < childJobIds.length; i++) {
                    int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1;
                    if (childJobId > 0) {
                        ReturnT<String> triggerChildResult = xxlJobService.triggerJob(childJobId);

                        // add msg
                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
                                (i+1),
                                childJobIds.length,
                                childJobIds[i],
                                (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
                                triggerChildResult.getMsg());
                    } else {
                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
                                (i+1),
                                childJobIds.length,
                                childJobIds[i]);
                    }
                }

            }
        } else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){
            ReturnT<String> retryTriggerResult = xxlJobService.triggerJob(log.getJobId());
            callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_exe_fail_retry") +"<<<<<<<<<<< </span><br>";

            callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_msg1"),
                   (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")), retryTriggerResult.getMsg());
        }

        // handle msg
        StringBuffer handleMsg = new StringBuffer();
        if (log.getHandleMsg()!=null) {
            handleMsg.append(log.getHandleMsg()).append("<br>");
        }
        if (handleCallbackParam.getExecuteResult().getMsg() != null) {
            handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
        }
        if (callbackMsg != null) {
            handleMsg.append(callbackMsg);
        }

        // success, save log
        log.setHandleTime(new Date());
        log.setHandleCode(handleCallbackParam.getExecuteResult().getCode());
        log.setHandleMsg(handleMsg.toString());
        xxlJobLogDao.updateHandleInfo(log);

        return ReturnT.SUCCESS;
    }

    @Override
    public ReturnT<String> registry(RegistryParam registryParam) {
        int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
        if (ret < 1) {
            xxlJobRegistryDao.registrySave(registryParam.getRegistGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
        }
        return ReturnT.SUCCESS;
    }

    @Override
    public ReturnT<String> registryRemove(RegistryParam registryParam) {
        xxlJobRegistryDao.registryDelete(registryParam.getRegistGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
        return ReturnT.SUCCESS;
    }

    @Override
    public ReturnT<String> triggerJob(int jobId) {
        return xxlJobService.triggerJob(jobId);
    }

}

```

* 至此，一个完成的流程就完成了，其他的比如路由策略，各种线程，xxl日志等等，后面有时间会用一篇单独的文章来书写。







<file_sep>---
layout: post
title: java的spi
date: 2017-09-13 15:21:00
categories:
- java
tags:
- java
---

<p>最近在看dubbo的源码时看到了其spi(Service Provider Interface)的实现，想要了解dubbo的spi的实现的话，就不得不要先了解一下java原生提供的spi实现了。</p>

<p>dubbo在其官网上是这样评价他们的spi机制的：</p>

Dubbo改进了JDK标准的SPI的以下问题：
* JDK标准的SPI会一次性实例化扩展点所有实现，如果有扩展实现初始化很耗时，但如果没用上也加载，会很浪费资源。
* 如果扩展点加载失败，连扩展点的名称都拿不到了。比如：JDK标准的ScriptEngine，通过 getName() 获取脚本类型的名称，但如果RubyScriptEngine因为所依赖的jruby.jar不存在，导致RubyScriptEngine类加载失败，这个失败原因被吃掉了，和ruby对应不起来，当用户执行ruby脚本时，会报不支持ruby，而不是真正失败的原因。
* 增加了对扩展点IoC和AOP的支持，一个扩展点可以直接setter注入其它扩展点。

<p>接下来就是对java原生提供的spi机制的详细说明了，dubbo的留到下次再说</p>

#### spi功能实现

* java原生的spi相对来说还是比较简单的，主要通过java.util.ServiceLoader这个类来实现功能
* 首先定义一个interface

```java

package com.wgq.spi.test;

public interface ISearch  {
    void search() ;
}

```

* 接口的实现

```java

package com.wgq.spi.test;

public class SearchBean implements ISearch {
    public void search() {
        System.out.println("spi search");
    }
}

```

* 然后在resources配置文件下新建文件夹META-INF/services/*,*表示接口名称的全称，所以这里*=com.wgq.spi.test.ISearch
* 在文件META-INF/services/com.wgq.spi.test.ISearch内添加接口的实现类全称，如果有多个实现，则一行一个

```
####com.wgq.spi.test.ISearch文件
com.wgq.spi.test.SearchBean

```
* 然后通过java.util.ServiceLoader调用接口

```java

public static void main(String[] args) {
    ServiceLoader<ISearch> serviceLoader = ServiceLoader.load(ISearch.class) ;
    Iterator<ISearch> iterator = serviceLoader.iterator() ;
    while (iterator.hasNext()) {
        ISearch search = iterator.next() ;
        search.search();
    }
}

```

* 到这里一个简单的java原生spi功能就演示完毕了。

#### ServiceLoader源码阅读

```java

package java.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;


/**
 * A simple service-provider loading facility.
 *
 * <p> A <i>service</i> is a well-known set of interfaces and (usually
 * abstract) classes.  A <i>service provider</i> is a specific implementation
 * of a service.  The classes in a provider typically implement the interfaces
 * and subclass the classes defined in the service itself.  Service providers
 * can be installed in an implementation of the Java platform in the form of
 * extensions, that is, jar files placed into any of the usual extension
 * directories.  Providers can also be made available by adding them to the
 * application's class path or by some other platform-specific means.
 *
 * <p> For the purpose of loading, a service is represented by a single type,
 * that is, a single interface or abstract class.  (A concrete class can be
 * used, but this is not recommended.)  A provider of a given service contains
 * one or more concrete classes that extend this <i>service type</i> with data
 * and code specific to the provider.  The <i>provider class</i> is typically
 * not the entire provider itself but rather a proxy which contains enough
 * information to decide whether the provider is able to satisfy a particular
 * request together with code that can create the actual provider on demand.
 * The details of provider classes tend to be highly service-specific; no
 * single class or interface could possibly unify them, so no such type is
 * defined here.  The only requirement enforced by this facility is that
 * provider classes must have a zero-argument constructor so that they can be
 * instantiated during loading.
 *
 * <p><a name="format"> A service provider is identified by placing a
 * <i>provider-configuration file</i> in the resource directory
 * <tt>META-INF/services</tt>.</a>  The file's name is the fully-qualified <a
 * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
 * The file contains a list of fully-qualified binary names of concrete
 * provider classes, one per line.  Space and tab characters surrounding each
 * name, as well as blank lines, are ignored.  The comment character is
 * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>,
 * <font style="font-size:smaller;">NUMBER SIGN</font>); on
 * each line all characters following the first comment character are ignored.
 * The file must be encoded in UTF-8.
 *
 * <p> If a particular concrete provider class is named in more than one
 * configuration file, or is named in the same configuration file more than
 * once, then the duplicates are ignored.  The configuration file naming a
 * particular provider need not be in the same jar file or other distribution
 * unit as the provider itself.  The provider must be accessible from the same
 * class loader that was initially queried to locate the configuration file;
 * note that this is not necessarily the class loader from which the file was
 * actually loaded.
 *
 * <p> Providers are located and instantiated lazily, that is, on demand.  A
 * service loader maintains a cache of the providers that have been loaded so
 * far.  Each invocation of the {@link #iterator iterator} method returns an
 * iterator that first yields all of the elements of the cache, in
 * instantiation order, and then lazily locates and instantiates any remaining
 * providers, adding each one to the cache in turn.  The cache can be cleared
 * via the {@link #reload reload} method.
 *
 * <p> Service loaders always execute in the security context of the caller.
 * Trusted system code should typically invoke the methods in this class, and
 * the methods of the iterators which they return, from within a privileged
 * security context.
 *
 * <p> Instances of this class are not safe for use by multiple concurrent
 * threads.
 *
 * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
 * method in this class will cause a {@link NullPointerException} to be thrown.
 *
 *
 * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
 * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
 * intended to represent sets of encoder/decoder pairs for some protocol.  In
 * this case it is an abstract class with two abstract methods:
 *
 * <blockquote><pre>
 * public abstract Encoder getEncoder(String encodingName);
 * public abstract Decoder getDecoder(String encodingName);</pre></blockquote>
 *
 * Each method returns an appropriate object or <tt>null</tt> if the provider
 * does not support the given encoding.  Typical providers support more than
 * one encoding.
 *
 * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
 * <tt>CodecSet</tt> service then its jar file also contains a file named
 *
 * <blockquote><pre>
 * META-INF/services/com.example.CodecSet</pre></blockquote>
 *
 * <p> This file contains the single line:
 *
 * <blockquote><pre>
 * com.example.impl.StandardCodecs    # Standard codecs</pre></blockquote>
 *
 * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
 * at initialization:
 *
 * <blockquote><pre>
 * private static ServiceLoader&lt;CodecSet&gt; codecSetLoader
 *     = ServiceLoader.load(CodecSet.class);</pre></blockquote>
 *
 * <p> To locate an encoder for a given encoding name it defines a static
 * factory method which iterates through the known and available providers,
 * returning only when it has located a suitable encoder or has run out of
 * providers.
 *
 * <blockquote><pre>
 * public static Encoder getEncoder(String encodingName) {
 *     for (CodecSet cp : codecSetLoader) {
 *         Encoder enc = cp.getEncoder(encodingName);
 *         if (enc != null)
 *             return enc;
 *     }
 *     return null;
 * }</pre></blockquote>
 *
 * <p> A <tt>getDecoder</tt> method is defined similarly.
 *
 *
 * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
 * the class path of a class loader that is used for provider loading includes
 * remote network URLs then those URLs will be dereferenced in the process of
 * searching for provider-configuration files.
 *
 * <p> This activity is normal, although it may cause puzzling entries to be
 * created in web-server logs.  If a web server is not configured correctly,
 * however, then this activity may cause the provider-loading algorithm to fail
 * spuriously.
 *
 * <p> A web server should return an HTTP 404 (Not Found) response when a
 * requested resource does not exist.  Sometimes, however, web servers are
 * erroneously configured to return an HTTP 200 (OK) response along with a
 * helpful HTML error page in such cases.  This will cause a {@link
 * ServiceConfigurationError} to be thrown when this class attempts to parse
 * the HTML page as a provider-configuration file.  The best solution to this
 * problem is to fix the misconfigured web server to return the correct
 * response code (HTTP 404) along with the HTML error page.
 *
 * @param  <S>
 *         The type of the service to be loaded by this loader
 *
 * @author <NAME>
 * @since 1.6
 */

public final class ServiceLoader<S>
    implements Iterable<S>
{

    private static final String PREFIX = "META-INF/services/";

    // The class or interface representing the service being loaded
    private final Class<S> service;

    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;

    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // The current lazy-lookup iterator
    private LazyIterator lookupIterator;

    /**
     * Clear this loader's provider cache so that all providers will be
     * reloaded.
     *
     * <p> After invoking this method, subsequent invocations of the {@link
     * #iterator() iterator} method will lazily look up and instantiate
     * providers from scratch, just as is done by a newly-created loader.
     *
     * <p> This method is intended for use in situations in which new providers
     * can be installed into a running Java virtual machine.
     */
    public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }

    private static void fail(Class<?> service, String msg, Throwable cause)
        throws ServiceConfigurationError
    {
        throw new ServiceConfigurationError(service.getName() + ": " + msg,
                                            cause);
    }

    private static void fail(Class<?> service, String msg)
        throws ServiceConfigurationError
    {
        throw new ServiceConfigurationError(service.getName() + ": " + msg);
    }

    private static void fail(Class<?> service, URL u, int line, String msg)
        throws ServiceConfigurationError
    {
        fail(service, u + ":" + line + ": " + msg);
    }

    // Parse a single line from the given configuration file, adding the name
    // on the line to the names list.
    //
    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
                          List<String> names)
        throws IOException, ServiceConfigurationError
    {
        String ln = r.readLine();
        if (ln == null) {
            return -1;
        }
        int ci = ln.indexOf('#');
        if (ci >= 0) ln = ln.substring(0, ci);
        ln = ln.trim();
        int n = ln.length();
        if (n != 0) {
            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
                fail(service, u, lc, "Illegal configuration-file syntax");
            int cp = ln.codePointAt(0);
            if (!Character.isJavaIdentifierStart(cp))
                fail(service, u, lc, "Illegal provider-class name: " + ln);
            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
                cp = ln.codePointAt(i);
                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
                    fail(service, u, lc, "Illegal provider-class name: " + ln);
            }
            if (!providers.containsKey(ln) && !names.contains(ln))
                names.add(ln);
        }
        return lc + 1;
    }

    // Parse the content of the given URL as a provider-configuration file.
    //
    // @param  service
    //         The service type for which providers are being sought;
    //         used to construct error detail strings
    //
    // @param  u
    //         The URL naming the configuration file to be parsed
    //
    // @return A (possibly empty) iterator that will yield the provider-class
    //         names in the given configuration file that are not yet members
    //         of the returned set
    //
    // @throws ServiceConfigurationError
    //         If an I/O error occurs while reading from the given URL, or
    //         if a configuration-file format error is detected
    //
    private Iterator<String> parse(Class<?> service, URL u)
        throws ServiceConfigurationError
    {
        InputStream in = null;
        BufferedReader r = null;
        ArrayList<String> names = new ArrayList<>();
        try {
            in = u.openStream();
            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
            int lc = 1;
            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
        } catch (IOException x) {
            fail(service, "Error reading configuration file", x);
        } finally {
            try {
                if (r != null) r.close();
                if (in != null) in.close();
            } catch (IOException y) {
                fail(service, "Error closing configuration file", y);
            }
        }
        return names.iterator();
    }

    // Private inner class implementing fully-lazy provider lookup
    //
    private class LazyIterator
        implements Iterator<S>
    {

        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }

        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();
            return true;
        }

        private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
                fail(service,
                     "Provider " + cn  + " not a subtype");
            }
            try {
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }

        public boolean hasNext() {
            if (acc == null) {
                return hasNextService();
            } else {
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
                    public Boolean run() { return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public S next() {
            if (acc == null) {
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

    /**
     * Lazily loads the available providers of this loader's service.
     *
     * <p> The iterator returned by this method first yields all of the
     * elements of the provider cache, in instantiation order.  It then lazily
     * loads and instantiates any remaining providers, adding each one to the
     * cache in turn.
     *
     * <p> To achieve laziness the actual work of parsing the available
     * provider-configuration files and instantiating providers must be done by
     * the iterator itself.  Its {@link java.util.Iterator#hasNext hasNext} and
     * {@link java.util.Iterator#next next} methods can therefore throw a
     * {@link ServiceConfigurationError} if a provider-configuration file
     * violates the specified format, or if it names a provider class that
     * cannot be found and instantiated, or if the result of instantiating the
     * class is not assignable to the service type, or if any other kind of
     * exception or error is thrown as the next provider is located and
     * instantiated.  To write robust code it is only necessary to catch {@link
     * ServiceConfigurationError} when using a service iterator.
     *
     * <p> If such an error is thrown then subsequent invocations of the
     * iterator will make a best effort to locate and instantiate the next
     * available provider, but in general such recovery cannot be guaranteed.
     *
     * <blockquote style="font-size: smaller; line-height: 1.2"><span
     * style="padding-right: 1em; font-weight: bold">Design Note</span>
     * Throwing an error in these cases may seem extreme.  The rationale for
     * this behavior is that a malformed provider-configuration file, like a
     * malformed class file, indicates a serious problem with the way the Java
     * virtual machine is configured or is being used.  As such it is
     * preferable to throw an error rather than try to recover or, even worse,
     * fail silently.</blockquote>
     *
     * <p> The iterator returned by this method does not support removal.
     * Invoking its {@link java.util.Iterator#remove() remove} method will
     * cause an {@link UnsupportedOperationException} to be thrown.
     *
     * @implNote When adding providers to the cache, the {@link #iterator
     * Iterator} processes resources in the order that the {@link
     * java.lang.ClassLoader#getResources(java.lang.String)
     * ClassLoader.getResources(String)} method finds the service configuration
     * files.
     *
     * @return  An iterator that lazily loads providers for this loader's
     *          service
     */
    public Iterator<S> iterator() {
        return new Iterator<S>() {

            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();

            public boolean hasNext() {
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

    /**
     * Creates a new service loader for the given service type and class
     * loader.
     *
     * @param  <S> the class of the service type
     *
     * @param  service
     *         The interface or abstract class representing the service
     *
     * @param  loader
     *         The class loader to be used to load provider-configuration files
     *         and provider classes, or <tt>null</tt> if the system class
     *         loader (or, failing that, the bootstrap class loader) is to be
     *         used
     *
     * @return A new service loader
     */
    public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }

    /**
     * Creates a new service loader for the given service type, using the
     * current thread's {@linkplain java.lang.Thread#getContextClassLoader
     * context class loader}.
     *
     * <p> An invocation of this convenience method of the form
     *
     * <blockquote><pre>
     * ServiceLoader.load(<i>service</i>)</pre></blockquote>
     *
     * is equivalent to
     *
     * <blockquote><pre>
     * ServiceLoader.load(<i>service</i>,
     *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
     *
     * @param  <S> the class of the service type
     *
     * @param  service
     *         The interface or abstract class representing the service
     *
     * @return A new service loader
     */
    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

    /**
     * Creates a new service loader for the given service type, using the
     * extension class loader.
     *
     * <p> This convenience method simply locates the extension class loader,
     * call it <tt><i>extClassLoader</i></tt>, and then returns
     *
     * <blockquote><pre>
     * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
     *
     * <p> If the extension class loader cannot be found then the system class
     * loader is used; if there is no system class loader then the bootstrap
     * class loader is used.
     *
     * <p> This method is intended for use when only installed providers are
     * desired.  The resulting service will only find and load providers that
     * have been installed into the current Java virtual machine; providers on
     * the application's class path will be ignored.
     *
     * @param  <S> the class of the service type
     *
     * @param  service
     *         The interface or abstract class representing the service
     *
     * @return A new service loader
     */
    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        ClassLoader prev = null;
        while (cl != null) {
            prev = cl;
            cl = cl.getParent();
        }
        return ServiceLoader.load(service, prev);
    }

    /**
     * Returns a string describing this service.
     *
     * @return  A descriptive string
     */
    public String toString() {
        return "java.util.ServiceLoader[" + service.getName() + "]";
    }

}


```

* ServiceLoader.load(Class)方法其实就是通过传入的Class对象new一个ServiceLoader对象出来
* 在new对象时，会生成一个LazyIterator的内部类对象
* 然后通过LazyIterator这个对象迭代生成配置文件中的对象。

<file_sep>---
layout: post
title: dubbo的扩展点机制-spi
date: 2017-09-25 18:21:00
categories:
- spi
tags:
- dubbo
- spi
---


Dubbo改进了JDK标准的SPI的以下问题：
* JDK标准的SPI会一次性实例化扩展点所有实现，如果有扩展实现初始化很耗时，但如果没用上也加载，会很浪费资源。
* 如果扩展点加载失败，连扩展点的名称都拿不到了。比如：JDK标准的ScriptEngine，通过 getName() 获取脚本类型的名称，但如果RubyScriptEngine因为所依赖的jruby.jar不存在，导致RubyScriptEngine类加载失败，这个失败原因被吃掉了，和ruby对应不起来，当用户执行ruby脚本时，会报不支持ruby，而不是真正失败的原因。
* 增加了对扩展点IoC和AOP的支持，一个扩展点可以直接setter注入其它扩展点。

<p>Dubbo的spi实现类是com.alibaba.dubbo.common.extension.ExtensionLoader。</p>
<p>Dubbo会为每个接口都生成一个ExtensionLoader对象，并放入到缓存中。</p>

```java

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    if (type == null)
        throw new IllegalArgumentException("Extension type == null");
    if(!type.isInterface()) {
        throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    }
    if(!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type(" + type + 
                ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    }
    //先从缓存中获取ExtensionLoader
    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) {
    	//缓存中不存在，则new一个ExtensionLoader对象并放入缓存中
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

private ExtensionLoader(Class<?> type) {
    this.type = type;
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

```
* 根据class类型获取到ExtensionLoader对象后，一般有三个方法获取扩展点对象
	* getAdaptiveExtension(): 获取适配的扩展点。
	* getExtension(String name)：根据key获取扩展点
	* getActivateExtension(URL url, String[] values, String group)：获取激活状态的扩展点
* 在这三个方法中，都会调用到一个方法，getExtensionClasses()，这个方法的主要作用就是加载配置文件，然后根据配置把数据放入到缓存中。

#### getExtensionClasses

先来看看getExtensionClasses方法，了解一下Dubbo读取的配置文件有哪些，又是如何读取配置文件中的内容的。

```java

private Map<String, Class<?>> getExtensionClasses() {
	//holder缓存中获取
    Map<String, Class<?>> classes = cachedClasses.get();
    //double check
    if (classes == null) {
        synchronized (cachedClasses) {
            classes = cachedClasses.get();
            if (classes == null) {
            	//缓存中没有，加载扩展点
                classes = loadExtensionClasses();
                cachedClasses.set(classes);
            }
        }
    }
    return classes;
}

private Map<String, Class<?>> loadExtensionClasses() {
	//根据spi注解中设置的name，设置当前接口的默认扩展点
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if(defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if(value != null && (value = value.trim()).length() > 0) {
            String[] names = NAME_SEPARATOR.split(value);
            if(names.length > 1) {
                throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if(names.length == 1) cachedDefaultName = names[0];
        }
    }
    
    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    //加载 META-INF/dubbo/internal/ 下的文件
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    //加载 META-INF/dubbo/ 下的文件
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    //加载 META-INF/services/ 下的文件
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}


private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
	//根据目录和接口的全名 获取到文件路径
    String fileName = dir + type.getName();
    try {
        Enumeration<java.net.URL> urls;
        ClassLoader classLoader = findClassLoader();
        if (classLoader != null) {
            urls = classLoader.getResources(fileName);
        } else {
            urls = ClassLoader.getSystemResources(fileName);
        }
        if (urls != null) {
            while (urls.hasMoreElements()) {
                java.net.URL url = urls.nextElement();
                try {
                	//读入文件到reader
                    BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                    try {
                        String line = null;
                        //按行获取
                        while ((line = reader.readLine()) != null) {
                            final int ci = line.indexOf('#');
                            if (ci >= 0) line = line.substring(0, ci);
                            line = line.trim();
                            if (line.length() > 0) {
                                try {
                                    String name = null;
                                    int i = line.indexOf('=');
                                    if (i > 0) {
                                    	//扩展点name
                                        name = line.substring(0, i).trim();
                                        //扩展点的类
                                        line = line.substring(i + 1).trim();
                                    }
                                    if (line.length() > 0) {
                                    	//获取到扩展点class
                                        Class<?> clazz = Class.forName(line, true, classLoader);
                                        if (! type.isAssignableFrom(clazz)) {
                                            throw new IllegalStateException("Error when load extension class(interface: " +
                                                    type + ", class line: " + clazz.getName() + "), class " 
                                                    + clazz.getName() + "is not subtype of interface.");
                                        }
                                        if (clazz.isAnnotationPresent(Adaptive.class)) {		//判断是否有Adaptive注解
                                            if(cachedAdaptiveClass == null) {
                                                cachedAdaptiveClass = clazz;	//如果有则设置cachedAdaptiveClass属性
                                            } else if (! cachedAdaptiveClass.equals(clazz)) {
                                                throw new IllegalStateException("More than 1 adaptive class found: "
                                                        + cachedAdaptiveClass.getClass().getName()
                                                        + ", " + clazz.getClass().getName());
                                            }
                                        } else {
                                            try {
                                            	//判断是否是一个wrapper包装类，包装类会有一个传入一个当前扩展点对象的构造函数
                                                clazz.getConstructor(type);
                                                Set<Class<?>> wrappers = cachedWrapperClasses;
                                                if (wrappers == null) {
                                                    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                                                    wrappers = cachedWrapperClasses;
                                                }
                                                wrappers.add(clazz);
                                            } catch (NoSuchMethodException e) {
                                            	//没有这个构造函数，说明是普通的扩展点类
                                                clazz.getConstructor();
                                                if (name == null || name.length() == 0) {
                                                    name = findAnnotationName(clazz);
                                                    if (name == null || name.length() == 0) {
                                                        if (clazz.getSimpleName().length() > type.getSimpleName().length()
                                                                && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                                                            name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                                                        } else {
                                                            throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                                                        }
                                                    }
                                                }
                                                String[] names = NAME_SEPARATOR.split(name);
                                                if (names != null && names.length > 0) {
                                                	//判断是否有activate注解，加入到缓存中
                                                    Activate activate = clazz.getAnnotation(Activate.class);
                                                    if (activate != null) {
                                                        cachedActivates.put(names[0], activate);
                                                    }
                                                    for (String n : names) {
                                                        if (! cachedNames.containsKey(clazz)) {
                                                        	//放入扩展点name缓存
                                                            cachedNames.put(clazz, n);
                                                        }
                                                        Class<?> c = extensionC lasses.get(n);
                                                        if (c == null) {
                                                        	//放入扩展点缓存
                                                            extensionClasses.put(n, clazz);
                                                        } else if (c != clazz) {
                                                            throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                } catch (Throwable t) {
                                    IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
                                    exceptions.put(line, e);
                                }
                            }
                        } // end of while read lines
                    } finally {
                        reader.close();
                    }
                } catch (Throwable t) {
                    logger.error("Exception when load extension class(interface: " +
                                        type + ", class file: " + url + ") in " + url, t);
                }
            } // end of while urls
        }
    } catch (Throwable t) {
        logger.error("Exception when load extension class(interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}

```


* 先从holder类中获取扩展点class集合，获取不到才会去加载一遍
* 加载扩展点前会先根据spi注解内设置的name，设置默认的扩展点
* 然后会去三个文件夹下加载扩展点，分别是：```META-INF/dubbo/internal/```,```META-INF/dubbo/```,```META-INF/services/```


#### getAdaptiveExtension

```java

public T getAdaptiveExtension() {
	//getExtensionClasses时设置
    Object instance = cachedAdaptiveInstance.get();
    if (instance == null) {
        if(createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }
        else {
            throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }

    return (T) instance;
}

private T createAdaptiveExtension() {
    try {
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
    }
}

private Class<?> getAdaptiveExtensionClass() {
	//加载扩展点
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

private Class<?> createAdaptiveExtensionClass() {
	//组装扩展点的类代码
    String code = createAdaptiveExtensionClassCode();
    ClassLoader classLoader = findClassLoader();
    //获取编译器，默认javassist
    com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

private String createAdaptiveExtensionClassCode() {
    StringBuilder codeBuidler = new StringBuilder();
    Method[] methods = type.getMethods();
    boolean hasAdaptiveAnnotation = false;
    for(Method m : methods) {
        if(m.isAnnotationPresent(Adaptive.class)) {
            hasAdaptiveAnnotation = true;
            break;
        }
    }
    // 完全没有Adaptive方法，则不需要生成Adaptive类
    if(! hasAdaptiveAnnotation)
        throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
    
    codeBuidler.append("package " + type.getPackage().getName() + ";");
    codeBuidler.append("\nimport " + ExtensionLoader.class.getName() + ";");
    codeBuidler.append("\npublic class " + type.getSimpleName() + "$Adpative" + " implements " + type.getCanonicalName() + " {");
    
    for (Method method : methods) {
        Class<?> rt = method.getReturnType();
        Class<?>[] pts = method.getParameterTypes();
        Class<?>[] ets = method.getExceptionTypes();

        Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
        StringBuilder code = new StringBuilder(512);
        if (adaptiveAnnotation == null) {
            code.append("throw new UnsupportedOperationException(\"method ")
                    .append(method.toString()).append(" of interface ")
                    .append(type.getName()).append(" is not adaptive method!\");");
        } else {
            int urlTypeIndex = -1;
            for (int i = 0; i < pts.length; ++i) {
                if (pts[i].equals(URL.class)) {
                    urlTypeIndex = i;
                    break;
                }
            }
            // 有类型为URL的参数
            if (urlTypeIndex != -1) {
                // Null Point check
                String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
                                urlTypeIndex);
                code.append(s);
                
                s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex); 
                code.append(s);
            }
            // 参数没有URL类型
            else {
                String attribMethod = null;
                
                // 找到参数的URL属性
                LBL_PTS:
                for (int i = 0; i < pts.length; ++i) {
                    Method[] ms = pts[i].getMethods();
                    for (Method m : ms) {
                        String name = m.getName();
                        if ((name.startsWith("get") || name.length() > 3)
                                && Modifier.isPublic(m.getModifiers())
                                && !Modifier.isStatic(m.getModifiers())
                                && m.getParameterTypes().length == 0
                                && m.getReturnType() == URL.class) {
                            urlTypeIndex = i;
                            attribMethod = name;
                            break LBL_PTS;
                        }
                    }
                }
                if(attribMethod == null) {
                    throw new IllegalStateException("fail to create adative class for interface " + type.getName()
                    		+ ": not found url parameter or url attribute in parameters of method " + method.getName());
                }
                
                // Null point check
                String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
                                urlTypeIndex, pts[urlTypeIndex].getName());
                code.append(s);
                s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
                                urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
                code.append(s);

                s = String.format("%s url = arg%d.%s();",URL.class.getName(), urlTypeIndex, attribMethod); 
                code.append(s);
            }
            
            String[] value = adaptiveAnnotation.value();
            // 没有设置Key，则使用“扩展点接口名的点分隔 作为Key
            if(value.length == 0) {
                char[] charArray = type.getSimpleName().toCharArray();
                StringBuilder sb = new StringBuilder(128);
                for (int i = 0; i < charArray.length; i++) {
                    if(Character.isUpperCase(charArray[i])) {
                        if(i != 0) {
                            sb.append(".");
                        }
                        sb.append(Character.toLowerCase(charArray[i]));
                    }
                    else {
                        sb.append(charArray[i]);
                    }
                }
                value = new String[] {sb.toString()};
            }
            
            boolean hasInvocation = false;
            for (int i = 0; i < pts.length; ++i) {
                if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
                    // Null Point check
                    String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
                    code.append(s);
                    s = String.format("\nString methodName = arg%d.getMethodName();", i); 
                    code.append(s);
                    hasInvocation = true;
                    break;
                }
            }
            
            String defaultExtName = cachedDefaultName;
            String getNameCode = null;
            for (int i = value.length - 1; i >= 0; --i) {
                if(i == value.length - 1) {
                    if(null != defaultExtName) {
                        if(!"protocol".equals(value[i]))
                            if (hasInvocation) 
                                getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                            else
                                getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
                        else
                            getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
                    }
                    else {
                        if(!"protocol".equals(value[i]))
                            if (hasInvocation) 
                                getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                            else
                                getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
                        else
                            getNameCode = "url.getProtocol()";
                    }
                }
                else {
                    if(!"protocol".equals(value[i]))
                        if (hasInvocation) 
                            getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                        else
                            getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
                    else
                        getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
                }
            }
            code.append("\nString extName = ").append(getNameCode).append(";");
            // check extName == null?
            String s = String.format("\nif(extName == null) " +
            		"throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
                    type.getName(), Arrays.toString(value));
            code.append(s);
            
            s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
                    type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
            code.append(s);
            
            // return statement
            if (!rt.equals(void.class)) {
                code.append("\nreturn ");
            }

            s = String.format("extension.%s(", method.getName());
            code.append(s);
            for (int i = 0; i < pts.length; i++) {
                if (i != 0)
                    code.append(", ");
                code.append("arg").append(i);
            }
            code.append(");");
        }
        
        codeBuidler.append("\npublic " + rt.getCanonicalName() + " " + method.getName() + "(");
        for (int i = 0; i < pts.length; i ++) {
            if (i > 0) {
                codeBuidler.append(", ");
            }
            codeBuidler.append(pts[i].getCanonicalName());
            codeBuidler.append(" ");
            codeBuidler.append("arg" + i);
        }
        codeBuidler.append(")");
        if (ets.length > 0) {
            codeBuidler.append(" throws ");
            for (int i = 0; i < ets.length; i ++) {
                if (i > 0) {
                    codeBuidler.append(", ");
                }
                codeBuidler.append(pts[i].getCanonicalName());
            }
        }
        codeBuidler.append(" {");
        codeBuidler.append(code.toString());
        codeBuidler.append("\n}");
    }
    codeBuidler.append("\n}");
    if (logger.isDebugEnabled()) {
        logger.debug(codeBuidler.toString());
    }
    return codeBuidler.toString();
}

```
* 先从holder缓存中获取当前接口的Adaptive类
* 如果为空，则尝试加载一下扩展点，如果还没有默认的Adaptive类
* 则会自动生成一个Adaptive类。
* 如下就是Protocol接口和自动生成的Adaptive类

```java

/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

/**
 * Protocol. (API/SPI, Singleton, ThreadSafe)
 * 
 * @author william.liangf
 */
@SPI("dubbo")
public interface Protocol {
    
    /**
     * 获取缺省端口，当用户没有配置端口时使用。
     * 
     * @return 缺省端口
     */
    int getDefaultPort();

    /**
     * 暴露远程服务：<br>
     * 1. 协议在接收请求时，应记录请求来源方地址信息：RpcContext.getContext().setRemoteAddress();<br>
     * 2. export()必须是幂等的，也就是暴露同一个URL的Invoker两次，和暴露一次没有区别。<br>
     * 3. export()传入的Invoker由框架实现并传入，协议不需要关心。<br>
     * 
     * @param <T> 服务的类型
     * @param invoker 服务的执行体
     * @return exporter 暴露服务的引用，用于取消暴露
     * @throws RpcException 当暴露服务出错时抛出，比如端口已占用
     */
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    /**
     * 引用远程服务：<br>
     * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时，协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。<br>
     * 2. refer()返回的Invoker由协议实现，协议通常需要在此Invoker中发送远程请求。<br>
     * 3. 当url中有设置check=false时，连接失败不能抛出异常，并内部自动恢复。<br>
     * 
     * @param <T> 服务的类型
     * @param type 服务的类型
     * @param url 远程服务的URL地址
     * @return invoker 服务的本地代理
     * @throws RpcException 当连接服务提供方失败时抛出
     */
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;

    /**
     * 释放协议：<br>
     * 1. 取消该协议所有已经暴露和引用的服务。<br>
     * 2. 释放协议所占用的所有资源，比如连接和端口。<br>
     * 3. 协议在释放后，依然能暴露和引用新的服务。<br>
     */
    void destroy();

}

//自动生成的代码
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}

```


#### getExtension(String name)

通过扩展点名称获取扩展点对象

```java

public T getExtension(String name) {
	if (name == null || name.length() == 0)
	    throw new IllegalArgumentException("Extension name == null");
	if ("true".equals(name)) {
	    return getDefaultExtension();
	}
	Holder<Object> holder = cachedInstances.get(name);
	if (holder == null) {
	    cachedInstances.putIfAbsent(name, new Holder<Object>());
	    holder = cachedInstances.get(name);
	}
	Object instance = holder.get();
	if (instance == null) {
	    synchronized (holder) {
            instance = holder.get();
            if (instance == null) {
            	//创建
                instance = createExtension(name);
                holder.set(instance);
            }
        }
	}
	return (T) instance;
}

private T createExtension(String name) {
	//加载扩展点
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null) {
        throw findException(name);
    }
    try {
        T instance = (T) EXTENSION_INSTANCES.get(clazz);
        if (instance == null) {
            EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
            instance = (T) EXTENSION_INSTANCES.get(clazz);
        }
        injectExtension(instance);
        Set<Class<?>> wrapperClasses = cachedWrapperClasses;
        //想当于aop，实现wrapper类的扩展功能
        if (wrapperClasses != null && wrapperClasses.size() > 0) {
            for (Class<?> wrapperClass : wrapperClasses) {
                instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
            }
        }
        //返回扩展类
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                type + ")  could not be instantiated: " + t.getMessage(), t);
    }
}

```

* 先从holder缓存中获取扩展点对象
* 缓存中不存在，则创建扩展点对象，如果存在wapper类，则会通过wapper封装扩展点对象，所以最后返回的是wapper对象















<file_sep>source 'https://ruby.taobao.org/'
gem 'github-pages', group: :jekyll_plugins
#gem 'jekyll-admin', group: :jekyll_plugins
<file_sep>---
layout: post
title: docker简单mysql主备
date: 2022-03-15 23:00:00
categories:
- mysql
tags:
- mysql
---

以下例子的mysql版本为5.7

讨论对象主要针对X锁和gap锁，且只讨论rc和rr级别下的锁，最后给结论；

#### 表信息

| 字段名称 | 类型 | 是否可为空 | 其他 |
| :------: | :------: | :-------: | :----: |
| id | bigint | N | 主键 |
| user_name | varchar(50) | N | 名称,普通索引 |
| real_name | varchar(50) | N | 真实姓名 |
| age | int | N | 年龄 |

具体的建表语句如下

```sql
CREATE TABLE `user_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(50) NOT NULL DEFAULT '',
  `real_name` varchar(50) NOT NULL DEFAULT '',
  `age` int(11) NOT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user_name` (`user_name`)
) 
```

插入一些默认数据：

```sql
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(1, '小王', '王X', 12, now(), now());
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(2, '大王', '王XX', 22, now(), now());
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(5, '老王', '王XXX', 52, now(), now());
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(10, '小李', '李X', 12, now(), now());
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(20, '大李', '李XX', 22, now(), now());
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(30, '老李', '李XXX', 52, now(), now());
```


#### 给不存在的数据加锁

##### rr隔离级别

###### 事物1(select ... for update) + 事物2(select ... for update)

事物1执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物2执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物1执行：
```sql
commit;
```

事物2执行：
```sql
commit;
```

可以正常运行

###### 事物1(select ... for update + insert) + 事物2(select ... for update)


事物1执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物2执行：
```sql
begin ;
select * from payment_detail where id = 4 for update ;
```

事物1执行：
```sql
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(3, '老天', '天下第一', 99999, now(), now());
commit;
```
此时事物1进入等待，等带事物2 ``` select ... from update ```产生的gap锁；

事物2执行：
```sql
commit;
```

* 因为事物2执行的id = 3；出于已存在数据(2,5)之间，gap锁会把(2,5)之间的空隙加上锁，不让插入；
* 因为事物1也执行了``` select ... for update ```语句，且条件一样，也侧面验证了，gap锁不是排他锁；
* 也就是上面``` 事物1(select ... for update) + 事物2(select ... for update) ```可以正常执行的原因；

###### gap锁导致的死锁

事物1执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物2执行：
```sql
begin ;
select * from payment_detail where id = 4 for update ;
```

事物1执行：
```sql
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(3, '老天', '天下第一', 99999, now(), now());
commit;
```

事物2执行：
```sql
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(4, '小天', '天下第二', 9999, now(), now());
commit;
```
此时事物1在等待事物2的gap锁释放；事物2在等待事物1的gap锁释放，会产生死锁；

###### 事物1(select ... for update) + 事物2(select ... for update) 列无索引

事物1执行：
```sql
begin ;
select * from user_info where age = 13 for update ;
```

事物2执行：
```sql
begin ;
select * from user_info where age = 14 for update ;
```

事物2无法顺利执行，在等待事物1释放锁

事物1执行：
```sql
commit;
```
事物2顺利执行

* 此处事物1的``` select ... for update ```因为age字段没有索引，且数据不存在，直接锁全表，导致事物2无法顺利执行；
* 即使事物2的age改成12，数据库中存在，也是无法获取到锁的；因为事物1已经锁的全表。

###### 事物1(select ... for update) + 事物2(insert) 列无索引

事物1执行：
```sql
begin ;
select * from user_info where age = 13 for update ;
```

事物2执行：
```sql
begin ;
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(4, '小四', '十四是十四', 14, now(), now());
```

* 和上面一样的结果，insert无法插入到数据，必须等待事物1释放表锁


##### rc隔离级别

###### 事物1(select ... for update) + 事物2(select ... for update)

事物1执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物2执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物1执行：
```sql
commit;
```

事物2执行：
```sql
commit;
```

可以正常运行

###### 事物1(select ... for update + insert) + 事物2(select ... for update)


事物1执行：
```sql
begin ;
select * from payment_detail where id = 3 for update ;
```

事物2执行：
```sql
begin ;
select * from payment_detail where id = 4 for update ;
```

事物1执行：
```sql
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(3, '老天', '天下第一', 99999, now(), now());
commit;
```

事物2执行：
```sql
commit;
```

* 正常运行；rc隔离级别没有gap锁，不会锁insert；

###### 事物1(select ... for update) + 事物2(select ... for update) 列无索引

事物1执行：
```sql
begin ;
select * from user_info where age = 13 for update ;
```

事物2执行：
```sql
begin ;
select * from user_info where age = 14 for update ;
select * from user_info where age = 12 for update ;
```

可以顺利执行。


###### 事物1(select ... for update) + 事物2(insert) 列无索引

事物1执行：
```sql
begin ;
select * from user_info where age = 13 for update ;
```

事物2执行：
```sql
begin ;
insert into user_info(id,user_name, real_name, age,create_time,update_time)
values(4, '小四', '十四是十四', 14, now(), now());
```

可以顺利执行


##### 总结

* 不管是rc的隔离级别还是rr的隔离级别，即使在有索引的情况下，``` select ... for update ```在所查询的数据不存在的时候都不能很好的获取到排他锁，在rr的隔离级别下能获取到gap锁防止插入而已，并不能让任务的并发执行变成顺序执行。反而有可能导致死锁
* 别给无索引的列加锁，rr级别会锁全表；但是rc在操作的时候并不会；猜测是会先锁表中的所有数据，但是mysql发现其中的数据不满足条件，又把锁给释放掉了。

#### 给存在的数据加锁

##### rr隔离级别



#### 范围加锁

##### rr隔离级别









<file_sep>---
layout: post
title: spring源码解析--默认标签
date: 2017-08-03 15:18:00
categories:
- java
- spring
tags:
- spring
- java
- 源码
---

前面的文章中，我们有了解过spring的自定义标签的使用和解析过程，相比于自定义标签，默认标签的解析就要复杂的多，下面就让我们开始吧。

![初始化到默认标签解析调用时序图](http://otor8zzyt.bkt.clouddn.com/spring/spring%E9%BB%98%E8%AE%A4%E6%A0%87%E7%AD%BE%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B.png "初始化到默认标签解析调用时序图")

通过上面的时序图，我们发现自定义标签和默认标签在解析前面的步骤都是一样的，只是在后面调用的方法不一样。默认标签是：```parseDefaultElement```方法，自定义标签是```parseCustomElement```方法，前面我们已经讲过```parseCustomElement```方法了。


### parseCustomElement

```java

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	// 解析import标签
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	// 解析alias标签
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	// 解析bean标签
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	// 递归解析beans标签
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

```
* 对默认标签的解析，主要委托给四个private方法进行，分别对import,alias,bean,beans标签进行解析。
* 这里我们先看对bean标签的解析，因为bean标签解析了解了，其他几个标签也就差不多了。

### bean标签解析

```java

/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	//解析bean标签
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		//如果子标签有自定义标签则解析他
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// Register the final decorated instance.
			//注册bean
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// Send registration event.
		//发送注册bean事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

```
* 解析bean标签，解析的属性存放在```AbstractBeanDefinition```内
* 如果子标签有自定义的标签则解析他
* 注册bean

#### 解析bean标签：parseBeanDefinitionElement

```java

/**
 * Parses the supplied {@code &lt;bean&gt;} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 */
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
	return parseBeanDefinitionElement(ele, null);
}

/**
 * Parses the supplied {@code &lt;bean&gt;} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 */
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
	// bean标签的id属性
	String id = ele.getAttribute(ID_ATTRIBUTE);
	// bean标签的name属性
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

	List<String> aliases = new ArrayList<String>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}

	String beanName = id;
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isDebugEnabled()) {
			logger.debug("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}

	//检查beanName是否唯一
	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}

	//解析bean
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		if (!StringUtils.hasText(beanName)) {
			try {
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					beanName = this.readerContext.generateBeanName(beanDefinition);
					// Register an alias for the plain bean class name, if still possible,
					// if the generator returned the class name plus a suffix.
					// This is expected for Spring 1.2/2.0 backwards compatibility.
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						aliases.add(beanClassName);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Neither XML 'id' nor 'name' specified - " +
							"using generated bean name [" + beanName + "]");
				}
			}
			catch (Exception ex) {
				error(ex.getMessage(), ele);
				return null;
			}
		}
		String[] aliasesArray = StringUtils.toStringArray(aliases);
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}

```

* 根据id，name属性，确定beanName，并保证beanName的唯一
* 然后委托给```parseBeanDefinitionElement(ele, beanName, containingBean)```方法

```java

public AbstractBeanDefinition parseBeanDefinitionElement(
		Element ele, String beanName, BeanDefinition containingBean) {

	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}

	try {
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);

		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

		parseMetaElements(ele, bd);
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

		parseConstructorArgElements(ele, bd);
		parsePropertyElements(ele, bd);
		parseQualifierElements(ele, bd);

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		return bd;
	}
	catch (ClassNotFoundException ex) {
		error("Bean class [" + className + "] not found", ele, ex);
	}
	catch (NoClassDefFoundError err) {
		error("Class that bean class [" + className + "] depends on not found", ele, err);
	}
	catch (Throwable ex) {
		error("Unexpected failure during bean definition parsing", ele, ex);
	}
	finally {
		this.parseState.pop();
	}

	return null;
}

```
* 先获取className，parent等属性，然后新建一个AbstractBeanDefinition对象。
* 解析bean标签上的属性
* 然后分别对bean的一些子节点进行解析
	- description标签
	- meta标签
	- lookup-method标签
	- replaced-method标签
	- constructor-arg标签
	- property标签
	- qualifier标签

#### 解析bean标签上的属性

```java

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
		BeanDefinition containingBean, AbstractBeanDefinition bd) {
	// 判断singleton节点
	if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
		error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
	}
	// scope属性
	else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
		bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
	}
	//	继承父bean的scope属性
	else if (containingBean != null) {
		// Take default from containing bean in case of an inner bean definition.
		bd.setScope(containingBean.getScope());
	}
	// abstract属性
	if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
		bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
	}
	// lazy-init属性
	String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
	if (DEFAULT_VALUE.equals(lazyInit)) {
		lazyInit = this.defaults.getLazyInit();
	}
	bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

	// autowire属性
	String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
	bd.setAutowireMode(getAutowireMode(autowire));

	// dependency-check属性
	String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
	bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

	// depends-on属性
	if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
		String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
		bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
	}

	// autowire-candidate属性
	String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
	if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
		String candidatePattern = this.defaults.getAutowireCandidates();
		if (candidatePattern != null) {
			String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
			bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
		}
	}
	else {
		bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
	}

	// primary属性
	if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
		bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
	}

	// init-method属性
	if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
		String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
		if (!"".equals(initMethodName)) {
			bd.setInitMethodName(initMethodName);
		}
	}
	else {
		if (this.defaults.getInitMethod() != null) {
			bd.setInitMethodName(this.defaults.getInitMethod());
			bd.setEnforceInitMethod(false);
		}
	}

	// destroy-method属性
	if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
		String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
		if (!"".equals(destroyMethodName)) {
			bd.setDestroyMethodName(destroyMethodName);
		}
	}
	else {
		if (this.defaults.getDestroyMethod() != null) {
			bd.setDestroyMethodName(this.defaults.getDestroyMethod());
			bd.setEnforceDestroyMethod(false);
		}
	}

	// factory-method属性
	if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
		bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
	}

	// factory-bean属性
	if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
		bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
	}

	return bd;
}

```

* this.defaults缓存的是root节点上的参数。
* 包含的属性如下：
	- scope属性
	- abstract属性
	- lazy-init属性
	- autowire属性
	- dependency-check属性
	- depends-on属性
	- autowire-candidate属性
	- primary属性
	- init-method属性
	- destroy-method属性
	- factory-method属性
	- factory-bean属性
* 这些属性被保存在```AbstractBeanDefinition```对象内

#### meta标签

```java

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
	NodeList nl = ele.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		//判断子节点是否默认标签&子节点的标签名称是否是meta标签
		if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
			Element metaElement = (Element) node;
			String key = metaElement.getAttribute(KEY_ATTRIBUTE);
			String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
			BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
			attribute.setSource(extractSource(metaElement));
			attributeAccessor.addMetadataAttribute(attribute);
		}
	}
}

```

* 先判断子节点内是否有meta标签
* 封装到```AbstractBeanDefinition```的一个名称为```attributes```的```LinkedHashMap```内

#### lookup-method标签和replaced-method标签

```java

/**
 * Parse lookup-override sub-elements of the given bean element.
 */
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		// 判断子标签是否有lookup-method标签
		if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
			Element ele = (Element) node;
			String methodName = ele.getAttribute(NAME_ATTRIBUTE);
			String beanRef = ele.getAttribute(BEAN_ELEMENT);
			LookupOverride override = new LookupOverride(methodName, beanRef);
			override.setSource(extractSource(ele));
			overrides.addOverride(override);
		}
	}
}

/**
 * Parse replaced-method sub-elements of the given bean element.
 */
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		//判断子标签是否有replaced-method标签
		if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
			Element replacedMethodEle = (Element) node;
			String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
			String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
			ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
			// Look for arg-type match elements.
			List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
			for (Element argTypeEle : argTypeEles) {
				String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
				match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
				if (StringUtils.hasText(match)) {
					replaceOverride.addTypeIdentifier(match);
				}
			}
			replaceOverride.setSource(extractSource(replacedMethodEle));
			overrides.addOverride(replaceOverride);
		}
	}
}

```

* lookup-method标签封装成```LookupOverride```，replaced-method标签封装成```ReplaceOverride```
* 都添加到```MethodOverrides```的一个名称为```overrides```的```HashSet```内

#### constructor-arg标签

```java

/**
 * Parse constructor-arg sub-elements of the given bean element.
 */
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
			parseConstructorArgElement((Element) node, bd);
		}
	}
}

/**
 * Parse a constructor-arg element.
 */
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
	//index属性
	String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
	//type属性
	String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
	//name属性
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
	//判断是否有index属性
	if (StringUtils.hasLength(indexAttr)) {
		try {
			int index = Integer.parseInt(indexAttr);
			if (index < 0) {
				error("'index' cannot be lower than 0", ele);
			}
			else {
				try {
					this.parseState.push(new ConstructorArgumentEntry(index));
					//获取value，也有可能是一个ref对象
					Object value = parsePropertyValue(ele, bd, null);
					ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
					if (StringUtils.hasLength(typeAttr)) {
						valueHolder.setType(typeAttr);
					}
					if (StringUtils.hasLength(nameAttr)) {
						valueHolder.setName(nameAttr);
					}
					valueHolder.setSource(extractSource(ele));
					if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
						error("Ambiguous constructor-arg entries for index " + index, ele);
					}
					else {
						bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
					}
				}
				finally {
					this.parseState.pop();
				}
			}
		}
		catch (NumberFormatException ex) {
			error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
		}
	}
	else {
		try {
			this.parseState.push(new ConstructorArgumentEntry());
			Object value = parsePropertyValue(ele, bd, null);
			ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
			if (StringUtils.hasLength(typeAttr)) {
				valueHolder.setType(typeAttr);
			}
			if (StringUtils.hasLength(nameAttr)) {
				valueHolder.setName(nameAttr);
			}
			valueHolder.setSource(extractSource(ele));
			bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
		}
		finally {
			this.parseState.pop();
		}
	}
}

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
	String elementName = (propertyName != null) ?
					"<property> element for property '" + propertyName + "'" :
					"<constructor-arg> element";

	// Should only have one child element: ref, value, list, etc.
	//只能拥有一个子节点
	NodeList nl = ele.getChildNodes();
	Element subElement = null;
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
				!nodeNameEquals(node, META_ELEMENT)) {
			// Child element is what we're looking for.
			if (subElement != null) {
				error(elementName + " must not contain more than one sub-element", ele);
			}
			else {
				subElement = (Element) node;
			}
		}
	}

	boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
	boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
	if ((hasRefAttribute && hasValueAttribute) ||
			((hasRefAttribute || hasValueAttribute) && subElement != null)) {
		error(elementName +
				" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
	}

	if (hasRefAttribute) {
		//解析ref属性
		String refName = ele.getAttribute(REF_ATTRIBUTE);
		if (!StringUtils.hasText(refName)) {
			error(elementName + " contains empty 'ref' attribute", ele);
		}
		RuntimeBeanReference ref = new RuntimeBeanReference(refName);
		ref.setSource(extractSource(ele));
		return ref;
	}
	else if (hasValueAttribute) {
		//解析value属性
		TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
		valueHolder.setSource(extractSource(ele));
		return valueHolder;
	}
	else if (subElement != null) {
		//如果有子节点，解析子节点
		return parsePropertySubElement(subElement, bd);
	}
	else {
		// Neither child element nor "ref" or "value" attribute found.
		error(elementName + " must specify a ref or value", ele);
		return null;
	}
}

```

* 看上去代码好像很长，但是读进去的话业务逻辑也不是很复杂
* index属性不能有两个相同的值。
* constructor-arg标签的属性会封装到```constructorArgumentValues```属性内
* constructor-arg标签只能有一个子节点，ref，value或者其他。

#### property标签

```java

/**
 * Parse property sub-elements of the given bean element.
 */
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
			parsePropertyElement((Element) node, bd);
		}
	}
}

/**
 * Parse a property element.
 */
public void parsePropertyElement(Element ele, BeanDefinition bd) {
	String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
	if (!StringUtils.hasLength(propertyName)) {
		error("Tag 'property' must have a 'name' attribute", ele);
		return;
	}
	this.parseState.push(new PropertyEntry(propertyName));
	try {
		if (bd.getPropertyValues().contains(propertyName)) {
			error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
			return;
		}
		Object val = parsePropertyValue(ele, bd, propertyName);
		PropertyValue pv = new PropertyValue(propertyName, val);
		parseMetaElements(ele, pv);
		pv.setSource(extractSource(ele));
		bd.getPropertyValues().addPropertyValue(pv);
	}
	finally {
		this.parseState.pop();
	}
}

```

* 只能有一个propertyName，多个相同的会报错
* 解析property标签下的meta子标签

#### qualifier标签

```java

/**
 * Parse qualifier sub-elements of the given bean element.
 */
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
			parseQualifierElement((Element) node, bd);
		}
	}
}

/**
 * Parse a qualifier element.
 */
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
	String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
	if (!StringUtils.hasLength(typeName)) {
		error("Tag 'qualifier' must have a 'type' attribute", ele);
		return;
	}
	this.parseState.push(new QualifierEntry(typeName));
	try {
		AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
		qualifier.setSource(extractSource(ele));
		String value = ele.getAttribute(VALUE_ATTRIBUTE);
		if (StringUtils.hasLength(value)) {
			qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
		}
		NodeList nl = ele.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
				Element attributeEle = (Element) node;
				String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
				String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
				if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
					BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
					attribute.setSource(extractSource(attributeEle));
					qualifier.addMetadataAttribute(attribute);
				}
				else {
					error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
					return;
				}
			}
		}
		bd.addQualifier(qualifier);
	}
	finally {
		this.parseState.pop();
	}
}

```

#### delegate.decorateBeanDefinitionIfRequired 解析子标签的自定义标签

```java

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
	return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}


public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
		Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

	BeanDefinitionHolder finalDefinition = definitionHolder;

	// Decorate based on custom attributes first.
	NamedNodeMap attributes = ele.getAttributes();
	for (int i = 0; i < attributes.getLength(); i++) {
		Node node = attributes.item(i);
		finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
	}

	// Decorate based on custom nested elements.
	NodeList children = ele.getChildNodes();
	for (int i = 0; i < children.getLength(); i++) {
		Node node = children.item(i);
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
		}
	}
	return finalDefinition;
}

public BeanDefinitionHolder decorateIfRequired(
		Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {

	String namespaceUri = getNamespaceURI(node);
	//非默认标签
	if (!isDefaultNamespace(namespaceUri)) {
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler != null) {
			return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
		}
		else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
		}
		else {
			// A custom namespace, not to be handled by Spring - maybe "xml:...".
			if (logger.isDebugEnabled()) {
				logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
			}
		}
	}
	return originalDef;
}

```

* 看过前面我写的自定义标签的应该都能看懂上面的代码。
* 对自定义标签，根据命名空间获取处理器来进行处理

#### 注册解析的bean

```java

public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// Register bean definition under primary name.
	String beanName = definitionHolder.getBeanName();
	//注册bean
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			//注册别名
			registry.registerAlias(beanName, alias);
		}
	}
}

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {

	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");

	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			// 注册前的校验
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	BeanDefinition oldBeanDefinition;

	// 根据beanName获取已注册的beanDetinition
	oldBeanDefinition = this.beanDefinitionMap.get(beanName);
	if (oldBeanDefinition != null) {
		// 如果beanDetinition已被注册且不允许覆盖，则抛出异常
		if (!this.allowBeanDefinitionOverriding) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
					"': There is already [" + oldBeanDefinition + "] bound.");
		}
		else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
						" with a framework-generated bean definition ': replacing [" +
						oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		}
		else {
			if (this.logger.isInfoEnabled()) {
				this.logger.info("Overriding bean definition for bean '" + beanName +
						"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		}
	}
	else {
		// 记录beanName
		this.beanDefinitionNames.add(beanName);
		this.manualSingletonNames.remove(beanName);
		this.frozenBeanDefinitionNames = null;
	}
	// 注册beanDetinition
	this.beanDefinitionMap.put(beanName, beanDefinition);

	if (oldBeanDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

```

* 注册beandefinition也只是把beanName作为key，beanDefinition作为value放到一个map中

#### 注册别名

```java

@Override
public void registerAlias(String name, String alias) {
	Assert.hasText(name, "'name' must not be empty");
	Assert.hasText(alias, "'alias' must not be empty");
	if (alias.equals(name)) {
		//如果别名和beanName相同，直接remove掉
		this.aliasMap.remove(alias);
	}
	else {
		if (!allowAliasOverriding()) {
			//如果不允许别名覆盖，并且别名已经被注册，则抛出异常
			String registeredName = this.aliasMap.get(alias);
			if (registeredName != null && !registeredName.equals(name)) {
				throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
						name + "': It is already registered for name '" + registeredName + "'.");
			}
		}
		//检测循环别名设置  A->B->C->B->A
		checkForAliasCircle(name, alias);
		//注册别名
		this.aliasMap.put(alias, name);
	}
}

/**
 * Determine the raw name, resolving aliases to canonical names.
 * @param name the user-specified name
 * @return the transformed name
 */
public String canonicalName(String name) {
	String canonicalName = name;
	// Handle aliasing...
	String resolvedName;
	do {
		resolvedName = this.aliasMap.get(canonicalName);
		if (resolvedName != null) {
			canonicalName = resolvedName;
		}
	}
	while (resolvedName != null);
	return canonicalName;
}

/**
 * Check whether the given name points back to given alias as an alias
 * in the other direction, catching a circular reference upfront and
 * throwing a corresponding IllegalStateException.
 * @param name the candidate name
 * @param alias the candidate alias
 * @see #registerAlias
 */
protected void checkForAliasCircle(String name, String alias) {
	if (alias.equals(canonicalName(name))) {
		throw new IllegalStateException("Cannot register alias '" + alias +
				"' for name '" + name + "': Circular reference - '" +
				name + "' is a direct or indirect alias for '" + alias + "' already");
	}
}


```

* 注册别名的时候，会判断是否有别名的循环设置。有的话会抛出异常。

### import标签

```java

protected void importBeanDefinitionResource(Element ele) {
	String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
	if (!StringUtils.hasText(location)) {
		getReaderContext().error("Resource location must not be empty", ele);
		return;
	}

	// Resolve system properties: e.g. "${user.dir}"
	location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

	Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

	// Discover whether the location is an absolute or relative URI
	boolean absoluteLocation = false;
	try {
		// 判断是否绝对地址
		absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
	}
	catch (URISyntaxException ex) {
		// cannot convert to an URI, considering the location relative
		// unless it is the well-known Spring prefix "classpath*:"
	}

	// Absolute or relative?
	if (absoluteLocation) {
		try {
			int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
			if (logger.isDebugEnabled()) {
				logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
			}
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error(
					"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
		}
	}
	else {
		// No URL -> considering resource location as relative to the current file.
		try {
			int importCount;
			Resource relativeResource = getReaderContext().getResource().createRelative(location);
			if (relativeResource.exists()) {
				importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
				actualResources.add(relativeResource);
			}
			else {
				String baseLocation = getReaderContext().getResource().getURL().toString();
				importCount = getReaderContext().getReader().loadBeanDefinitions(
						StringUtils.applyRelativePath(baseLocation, location), actualResources);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
			}
		}
		catch (IOException ex) {
			getReaderContext().error("Failed to resolve current resource location", ele, ex);
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
					ele, ex);
		}
	}
	Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
	// 发送event事件
	getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

```

* import标签的解析，首先解析文件的地址，转换为绝对地址，然后递归调用```loadBeanDefinitions```方法。
* 最后发送event事件

### alias标签

```java

/**
 * Process the given alias element, registering the alias with the registry.
 */
protected void processAliasRegistration(Element ele) {
	String name = ele.getAttribute(NAME_ATTRIBUTE);
	String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
	boolean valid = true;
	if (!StringUtils.hasText(name)) {
		getReaderContext().error("Name must not be empty", ele);
		valid = false;
	}
	if (!StringUtils.hasText(alias)) {
		getReaderContext().error("Alias must not be empty", ele);
		valid = false;
	}
	if (valid) {
		try {
			getReaderContext().getRegistry().registerAlias(name, alias);
		}
		catch (Exception ex) {
			getReaderContext().error("Failed to register alias '" + alias +
					"' for bean with name '" + name + "'", ele, ex);
		}
		getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
	}
}

```

* alias标签的注册同bean标签解析，最后注册别名调用的方法是同一个。

### beans标签

```java

/**
 * Register each bean definition within the given root {@code <beans/>} element.
 */
protected void doRegisterBeanDefinitions(Element root) {
	// Any nested <beans> elements will cause recursion in this method. In
	// order to propagate and preserve <beans> default-* attributes correctly,
	// keep track of the current (parent) delegate, which may be null. Create
	// the new (child) delegate with a reference to the parent for fallback purposes,
	// then ultimately reset this.delegate back to its original (parent) reference.
	// this behavior emulates a stack of delegates without actually necessitating one.
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);

	if (this.delegate.isDefaultNamespace(root)) {
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				return;
			}
		}
	}

	preProcessXml(root);
	parseBeanDefinitions(root, this.delegate);
	postProcessXml(root);

	this.delegate = parent;
}

```
* 递归调用解析。

<file_sep>---
layout: post
title: dubbo自定义标签解析
date: 2017-09-14 11:00:00
categories:
- dubbo
tags:
- dubbo
- spring
---

<p>dubbo依赖spring容器，想要先了解dubbo的实现机制和原理的话，那么首先就需要先了解dubbo的自定义标签是如何去解析的，是如何把参数转化成beenDefinition的。</p>

<p>前面已经对spring的自定义标签做过详细的讲解，这里就不做过多的介绍了，直接进入主题吧</p>

### DubboNamespaceHandler

```java

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

	static {
		Version.checkDuplicate(DubboNamespaceHandler.class);
	}

	public void init() {
	    registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }

}

```

* dubbo标签的解析都是交给```DubboBeanDefinitionParser```这个类来进行的。
* ```DubboBeanDefinitionParser```会传入两个参数，第一个Class类型的表示的是这个beanDefinition的beanClass，也就是后面生成bean对象的类型；第二个表示，如果当前标签没有传入id字段，是否自动生成id字段

### DubboBeanDefinitionParser

* DubboBeanDefinitionParser继承了BeanDefinitionParser类，并重写了其parse方法
* 这个parse方法有点长，因为dubbo的所有标签都是通过其来解析。

```java

public BeanDefinition parse(Element element, ParserContext parserContext) {
    return parse(element, parserContext, beanClass, required);
}

@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(beanClass);
    beanDefinition.setLazyInit(false);
    String id = element.getAttribute("id");
    //没有自定义id，则根据条件自动生成id
    if ((id == null || id.length() == 0) && required) {
    	String generatedBeanName = element.getAttribute("name");
    	if (generatedBeanName == null || generatedBeanName.length() == 0) {
    	    if (ProtocolConfig.class.equals(beanClass)) {	//ProtocolConfig.class默认id为dubbo
    	        generatedBeanName = "dubbo";
    	    } else {
    	        generatedBeanName = element.getAttribute("interface");		//其他的则从interface节点获取
    	    }
    	}
    	if (generatedBeanName == null || generatedBeanName.length() == 0) {	//如果还为空，则获取beanClass的全名称
    		generatedBeanName = beanClass.getName();
    	}
        id = generatedBeanName; 
        int counter = 2;
        while(parserContext.getRegistry().containsBeanDefinition(id)) {	//确定id的最终名称。
            id = generatedBeanName + (counter ++);
        }
    }
    //注册beanDefinition
    if (id != null && id.length() > 0) {
        if (parserContext.getRegistry().containsBeanDefinition(id))  {
    		throw new IllegalStateException("Duplicate spring bean id " + id);
    	}
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        beanDefinition.getPropertyValues().addPropertyValue("id", id);
    }
    //解析ProtocolConfig.class时，找出其他beanDefinition中依赖当前protocol的地方，把当前对象注入进去
    if (ProtocolConfig.class.equals(beanClass)) {
        for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
            BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
            PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
            if (property != null) {
                Object value = property.getValue();
                if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                    definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                }
            }
        }
    } else if (ServiceBean.class.equals(beanClass)) {
    //解析ServiceBean.class时，节点上有class属性的解析
        String className = element.getAttribute("class");
        if(className != null && className.length() > 0) {
            RootBeanDefinition classDefinition = new RootBeanDefinition();
            classDefinition.setBeanClass(ReflectUtils.forName(className));
            classDefinition.setLazyInit(false);
            parseProperties(element.getChildNodes(), classDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
        }
    } else if (ProviderConfig.class.equals(beanClass)) {
    //解析ProviderConfig.class时，如果有<dubbo:service>子节点，则解析它
        parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
    } else if (ConsumerConfig.class.equals(beanClass)) {
    //解析ConsumerConfig.class时，如果有<dubbo:reference>子节点，则解析它
        parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
    }
    Set<String> props = new HashSet<String>();
    ManagedMap parameters = null;
    for (Method setter : beanClass.getMethods()) {
        String name = setter.getName();
        //找set方法，比如setName
        if (name.length() > 3 && name.startsWith("set")
                && Modifier.isPublic(setter.getModifiers())
                && setter.getParameterTypes().length == 1) {
            Class<?> type = setter.getParameterTypes()[0];
            //得到setName后面的name
            String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
            props.add(property);
            Method getter = null;
            //获取set方法对应的get方法，如果没有可能是boolean属性，则判断是否有isName方法
            try {
                getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);
            } catch (NoSuchMethodException e) {
                try {
                    getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);
                } catch (NoSuchMethodException e2) {
                }
            }
            //get方法不存在，或者get方法不是public，或者get返回值类型与set的类型不同，则跳过当前set方法
            if (getter == null 
                    || ! Modifier.isPublic(getter.getModifiers())
                    || ! type.equals(getter.getReturnType())) {
                continue;
            }
            if ("parameters".equals(property)) {
            //当前方法是setParameters方法
                parameters = parseParameters(element.getChildNodes(), beanDefinition);
            } else if ("methods".equals(property)) {
            //当前方法是setMethods方法
                parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
            } else if ("arguments".equals(property)) {
            //当前方法是setArguments方法
                parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
            } else {
            //其他set方法
            	//获取set的属性在标签中设置的值
                String value = element.getAttribute(property);
                if (value != null) {
                	value = value.trim();
                	if (value.length() > 0) {
                		if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
                        	RegistryConfig registryConfig = new RegistryConfig();
                        	registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
                        	beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);
                        } else if ("registry".equals(property) && value.indexOf(',') != -1) {
                        //解析多个registry地址
                			parseMultiRef("registries", value, beanDefinition, parserContext);
                        } else if ("provider".equals(property) && value.indexOf(',') != -1) {
                        //解析多个provider属性
                        	parseMultiRef("providers", value, beanDefinition, parserContext);
                        } else if ("protocol".equals(property) && value.indexOf(',') != -1) {
                        //解析多个protocol属性
                            parseMultiRef("protocols", value, beanDefinition, parserContext);
                        } else {
                            Object reference;
                            if (isPrimitive(type)) {
                                if ("async".equals(property) && "false".equals(value)
                                        || "timeout".equals(property) && "0".equals(value)
                                        || "delay".equals(property) && "0".equals(value)
                                        || "version".equals(property) && "0.0.0".equals(value)
                                        || "stat".equals(property) && "-1".equals(value)
                                        || "reliable".equals(property) && "false".equals(value)) {
                                    // 兼容旧版本xsd中的default值
                                    value = null;
                                }
                                reference = value;
                            } else if ("protocol".equals(property) 
                                    && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value)
                                    && (! parserContext.getRegistry().containsBeanDefinition(value)
                                            || ! ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {
                                if ("dubbo:provider".equals(element.getTagName())) {
                                    logger.warn("Recommended replace <dubbo:provider protocol=\"" + value + "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />");
                                }
                                // 兼容旧版本配置
                                ProtocolConfig protocol = new ProtocolConfig();		//感觉像占个位置，等待protocolConfig标签初始化时，再设置
                                protocol.setName(value);
                                reference = protocol;
                            } else if ("monitor".equals(property) 
                                    && (! parserContext.getRegistry().containsBeanDefinition(value)
                                            || ! MonitorConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {
                                // 兼容旧版本配置
                                reference = convertMonitor(value);
                            } else if ("onreturn".equals(property)) {
                            //设置return钩子方法
                                int index = value.lastIndexOf(".");
                                String returnRef = value.substring(0, index);
                                String returnMethod = value.substring(index + 1);
                                reference = new RuntimeBeanReference(returnRef);
                                beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
                            } else if ("onthrow".equals(property)) {
                            //设置throw钩子方法
                                int index = value.lastIndexOf(".");
                                String throwRef = value.substring(0, index);
                                String throwMethod = value.substring(index + 1);
                                reference = new RuntimeBeanReference(throwRef);
                                beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
                            } else {
                                if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
                                    BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
                                    if (! refBean.isSingleton()) {
                                        throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: <bean id=\"" + value+ "\" scope=\"singleton\" ...>");
                                    }
                                }
                                reference = new RuntimeBeanReference(value);
                            }
	                        beanDefinition.getPropertyValues().addPropertyValue(property, reference);
                        }
                	}
                }
            }
        }
    }
    //处理标签上未处理的属性
    NamedNodeMap attributes = element.getAttributes();
    int len = attributes.getLength();
    for (int i = 0; i < len; i++) {
        Node node = attributes.item(i);
        String name = node.getLocalName();
        if (! props.contains(name)) {
            if (parameters == null) {
                parameters = new ManagedMap();
            }
            String value = node.getNodeValue();
            parameters.put(name, new TypedStringValue(value, String.class));
        }
    }
    if (parameters != null) {
        beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
    }
    return beanDefinition;
}

```

* 先获取标签的id，如果id不存在，则会根据规则自动生成一个id，然后注册当前beanDefinition
* 根据beanClass的不同做一些特定的工作
	- 解析ProtocolConfig.class时，找出其他beanDefinition中依赖当前protocol的地方，把当前对象注入进去
	- 解析ServiceBean.class时，节点上有class属性会转化成ref属性
	- 解析ProviderConfig.class时，如果有<dubbo:service>子节点，则解析它
	- 解析ConsumerConfig.class时，如果有<dubbo:reference>子节点，则解析它
* 根据beanClass的set方法到标签属性上寻找对应的值，并设置到beanDefinition中去
	- 设置前需要判断是否有get方法或者is方法，get或者is方法是否public，且set方法的参数类型是否和get方法的返回类型相同
	- 单个属性有多个值得解析，registry、provider、protocol
	- 对旧版本的兼容处理
	- 设置onreturn和onthrow钩子方法
	- 然后才是其他所有的属性
* 最后会遍历节点的所有属性，找到未处理的属性，然后处理它。


#### parseNested方法

* parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
* parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);

```java

private static void parseNested(Element element, ParserContext parserContext, Class<?> beanClass, boolean required, String tag, String property, String ref, BeanDefinition beanDefinition) {
    NodeList nodeList = element.getChildNodes();
    if (nodeList != null && nodeList.getLength() > 0) {
        boolean first = true;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                if (tag.equals(node.getNodeName())
                        || tag.equals(node.getLocalName())) {
                    if (first) {
                        first = false;
                        String isDefault = element.getAttribute("default");
                        if (isDefault == null || isDefault.length() == 0) {
                            beanDefinition.getPropertyValues().addPropertyValue("default", "false");
                        }
                    }
                    //递归调用解析子标签
                    BeanDefinition subDefinition = parse((Element) node, parserContext, beanClass, required);
                    if (subDefinition != null && ref != null && ref.length() > 0) {
                    	//子标签添加属性
                        subDefinition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(ref));
                    }
                }
            }
        }
    }
}

```

* <dubbo:provider>节点下有<dubbo:service>或者<dubbo:consumer>节点下有<dubbo:reference>节点时，才会调用当前方法
* 递归调用parse解析子节点，并把父节点注入到子节点中去

#### parseParameters

* 解析beanClass的setParameters方法时调用方法

```java

private static ManagedMap parseParameters(NodeList nodeList, RootBeanDefinition beanDefinition) {
    if (nodeList != null && nodeList.getLength() > 0) {
        ManagedMap parameters = null;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                if ("parameter".equals(node.getNodeName())
                        || "parameter".equals(node.getLocalName())) {
                    if (parameters == null) {
                        parameters = new ManagedMap();
                    }
                    String key = ((Element) node).getAttribute("key");
                    String value = ((Element) node).getAttribute("value");
                    boolean hide = "true".equals(((Element) node).getAttribute("hide"));
                    if (hide) {
                        key = Constants.HIDE_KEY_PREFIX + key;
                    }
                    parameters.put(key, new TypedStringValue(value, String.class));
                }
            }
        }
        return parameters;
    }
    return null;
}

```

* 子节点是否有<dubbo:parameter>节点，如果有则解析它并添加到parameters集合中去

#### parseMethods

* 解析beanClass的setMethods方法时调用的方法

```java

private static void parseMethods(String id, NodeList nodeList, RootBeanDefinition beanDefinition,
                              ParserContext parserContext) {
    if (nodeList != null && nodeList.getLength() > 0) {
        ManagedList methods = null;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                Element element = (Element) node;
                if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) {
                    String methodName = element.getAttribute("name");
                    if (methodName == null || methodName.length() == 0) {
                        throw new IllegalStateException("<dubbo:method> name attribute == null");
                    }
                    if (methods == null) {
                        methods = new ManagedList();
                    }
                    BeanDefinition methodBeanDefinition = parse(((Element) node),
                            parserContext, MethodConfig.class, false);
                    String name = id + "." + methodName;
                    BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(
                            methodBeanDefinition, name);
                    methods.add(methodBeanDefinitionHolder);
                }
            }
        }
        if (methods != null) {
            beanDefinition.getPropertyValues().addPropertyValue("methods", methods);
        }
    }
}

```

* 解析method子节点。

#### parseArguments

```java

private static void parseArguments(String id, NodeList nodeList, RootBeanDefinition beanDefinition,
                              ParserContext parserContext) {
    if (nodeList != null && nodeList.getLength() > 0) {
        ManagedList arguments = null;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                Element element = (Element) node;
                if ("argument".equals(node.getNodeName()) || "argument".equals(node.getLocalName())) {
                    String argumentIndex = element.getAttribute("index");
                    if (arguments == null) {
                        arguments = new ManagedList();
                    }
                    BeanDefinition argumentBeanDefinition = parse(((Element) node),
                            parserContext, ArgumentConfig.class, false);
                    String name = id + "." + argumentIndex;
                    BeanDefinitionHolder argumentBeanDefinitionHolder = new BeanDefinitionHolder(
                            argumentBeanDefinition, name);
                    arguments.add(argumentBeanDefinitionHolder);
                }
            }
        }
        if (arguments != null) {
            beanDefinition.getPropertyValues().addPropertyValue("arguments", arguments);
        }
    }
}

```


* 解析argument子节点

#### parseMultiRef

```java


private static void parseMultiRef(String property, String value, RootBeanDefinition beanDefinition,
            ParserContext parserContext) {
	String[] values = value.split("\\s*[,]+\\s*");
	ManagedList list = null;
    for (int i = 0; i < values.length; i++) {
        String v = values[i];
        if (v != null && v.length() > 0) {
        	if (list == null) {
                list = new ManagedList();
            }
        	list.add(new RuntimeBeanReference(v));
        }
    }
    beanDefinition.getPropertyValues().addPropertyValue(property, list);
}

```

* 总结：dubbo标签解析时并不会去读取dubbo.properties内的属性值。








<file_sep>---
layout: post
title: spring源码解析--自定义标签
date: 2017-07-25 15:48:00
categories:
- java
- spring
tags:
- spring
- java
- 源码
---

spring初始化的时候，是如何解析自定义标签的呢？先看看下面的的时序图。

![初始化到自定义标签解析调用时序图](http://otor8zzyt.bkt.clouddn.com/spring/spring%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%87%E7%AD%BE%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B.png "初始化到自定义标签解析调用时序图")

最终spring是交给```BeanDefinitionParserDelegate```类的```parseCustomElement(Element ele, BeanDefinition containingBd)```方法去解析的

下面看看```parseCustomElement(Element ele, BeanDefinition containingBd)```方法

```java

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
	//获取命名空间  http://www.wgq.com/schema/user
	String namespaceUri = getNamespaceURI(ele);
	//根据命名空间获取 NamespaceHandler
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

```

* 获取命名空间直接调用的是```org.w3c.dom.Node```自带的方法获取
* 然后便是根据命名空间获取```NamespaceHandler```了，跟踪```resolve```方法

### resolve方法
```java

public NamespaceHandler resolve(String namespaceUri) {
	//获取handler缓存集合
	Map<String, Object> handlerMappings = getHandlerMappings();
	Object handlerOrClassName = handlerMappings.get(namespaceUri);
	if (handlerOrClassName == null) {
		return null;
	}
	//根据缓存获取hanlder已初始化直接返回
	else if (handlerOrClassName instanceof NamespaceHandler) {
		return (NamespaceHandler) handlerOrClassName;
	}
	//未初始化则进行初始化，并替换缓存中的值为初始化后的对象
	else {
		String className = (String) handlerOrClassName;
		try {
			Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
			if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
				throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
						"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
			}
			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
			namespaceHandler.init();
			handlerMappings.put(namespaceUri, namespaceHandler);
			return namespaceHandler;
		}
		catch (ClassNotFoundException ex) {
			throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
					namespaceUri + "] not found", ex);
		}
		catch (LinkageError err) {
			throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
					namespaceUri + "]: problem with handler class file or dependent class", err);
		}
	}
}

```

观看上面的源码，主要分成以下几步：
* 获取```handlerMappings```缓存集合
* 从缓存中获取handler，如果已初始化则直接返回，未初始化则进行初始化工作。

我们先看看```getHandlerMappings()```干了些什么
#### getHandlerMappings()
```java

private Map<String, Object> getHandlerMappings() {
	if (this.handlerMappings == null) {
		synchronized (this) {
			if (this.handlerMappings == null) {
				try {
					Properties mappings =
							PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
					if (logger.isDebugEnabled()) {
						logger.debug("Loaded NamespaceHandler mappings: " + mappings);
					}
					Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
					CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
					this.handlerMappings = handlerMappings;
				}
				catch (IOException ex) {
					throw new IllegalStateException(
							"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
				}
			}
		}
	}
	return this.handlerMappings;
}

```

* 从上面的代码可以看出，主要是从```handlerMappingsLocation```这个地址下获取键值然后缓存下来
* 那么```handlerMappingsLocation```值是什么呢？看下面这张图

![handlerMappingsLocation属性值](http://otor8zzyt.bkt.clouddn.com/spring/handlerMappingsLocation.png "handlerMappingsLocation属性值")

* 可以很清楚的看到this.handlerMappingsLocation=META-INF/spring.handlers。

```java
##spring.handlers
http\://www.wgq.com/schema/user=com.wgq.spring.source.namespacehandler.MyNamespaceHandler

```

* 看完getHandlerMappings我们在看看```namespaceHandler.init()```初始化的时候做了啥


#### namespaceHandler.init()

```java

@Override
public void init() {
	// TODO Auto-generated method stub
	registerBeanDefinitionParser("user", new UserBeanDefintionParser());
}

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
	this.parsers.put(elementName, parser);
}
```

* 可以很清楚的看到，在handler初始化的时候会把我们自定义的```UserBeanDefintionParser```注册进去

### handler.parse

看完了resolve方法，下面来看看handler.parse这个方法,其调用的是```NamespaceHandlerSupport```里面的parse方法

```java

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
	return findParserForElement(element, parserContext).parse(element, parserContext);
}

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
	String localName = parserContext.getDelegate().getLocalName(element);
	BeanDefinitionParser parser = this.parsers.get(localName);
	if (parser == null) {
		parserContext.getReaderContext().fatal(
				"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
	}
	return parser;
}

```

* 根据```localName```找到```BeanDefinitionParser```，例：localName="user"。
* ```this.parsers```在前面提到过，通过```namespaceHandler.init()```的方法把自定义的BeanDefinitionParser注册进去
* 然后直接调用```AbstractBeanDefinitionParser```下parse方法

一般来说我们的自定义BeanDefinitionParser的类会实现```AbstractSingleBeanDefinitionParser```，比如：
```java

package com.wgq.spring.source.parser;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.w3c.dom.Element;

import com.wgq.spring.source.pojo.User;

public class UserBeanDefintionParser extends AbstractSingleBeanDefinitionParser {

	protected Class getBeanClass(Element element) {  
        return User.class;  
    }  
  
    protected void doParse(Element element, BeanDefinitionBuilder bean) {  
        String userName = element.getAttribute("username");  
        String email = element.getAttribute("email");  
  
        bean.addPropertyValue("username", userName);  
        bean.addPropertyValue("email", email);  
    }  

}


```

* 上面我们说直接调用的是```AbstractBeanDefinitionParser```下```parse```方法，那为什么这里继承的是```AbstractSingleBeanDefinitionParser```类呢？先看看```AbstractBeanDefinitionParser```下```parse```方法

```java

//AbstractBeanDefinitionParser
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
	AbstractBeanDefinition definition = parseInternal(element, parserContext);
	if (definition != null && !parserContext.isNested()) {
		try {
			String id = resolveId(element, definition, parserContext);
			if (!StringUtils.hasText(id)) {
				parserContext.getReaderContext().error(
						"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
								+ "' when used as a top-level tag", element);
			}
			String[] aliases = null;
			if (shouldParseNameAsAliases()) {
				String name = element.getAttribute(NAME_ATTRIBUTE);
				if (StringUtils.hasLength(name)) {
					aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
				}
			}
			BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
			registerBeanDefinition(holder, parserContext.getRegistry());
			if (shouldFireEvents()) {
				BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
				postProcessComponentDefinition(componentDefinition);
				parserContext.registerComponent(componentDefinition);
			}
		}
		catch (BeanDefinitionStoreException ex) {
			parserContext.getReaderContext().error(ex.getMessage(), element);
			return null;
		}
	}
	return definition;
}

//AbstractSingleBeanDefinitionParser
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
	String parentName = getParentName(element);
	if (parentName != null) {
		builder.getRawBeanDefinition().setParentName(parentName);
	}
	Class<?> beanClass = getBeanClass(element);
	if (beanClass != null) {
		builder.getRawBeanDefinition().setBeanClass(beanClass);
	}
	else {
		String beanClassName = getBeanClassName(element);
		if (beanClassName != null) {
			builder.getRawBeanDefinition().setBeanClassName(beanClassName);
		}
	}
	builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
	if (parserContext.isNested()) {
		// Inner bean definition must receive same scope as containing bean.
		builder.setScope(parserContext.getContainingBeanDefinition().getScope());
	}
	if (parserContext.isDefaultLazyInit()) {
		// Default-lazy-init applies to custom bean definitions as well.
		builder.setLazyInit(true);
	}
	doParse(element, parserContext, builder);
	return builder.getBeanDefinition();
}

```

* ```parse```方法会调用其子类```AbstractSingleBeanDefinitionParser```的```parseInternal```方法，在```parseInternal```方法内，会调用```doParse```方法（也就是我们自定义的方法）
* 当然您也可以直接继承```AbstractBeanDefinitionParser```类，去重写其的```parse```方法，spring内开启aop注解功能的自定义标签就是这样的。

### aop自定义标签的实现
```java

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
	 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
	 * and '{@code scoped-proxy}' tags.
	 */
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

}

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}

	private void extendBeanDefinition(Element element, ParserContext parserContext) {
		BeanDefinition beanDef =
				parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
		if (element.hasChildNodes()) {
			addIncludePatterns(element, parserContext, beanDef);
		}
	}

	private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
		ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
		NodeList childNodes = element.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++) {
			Node node = childNodes.item(i);
			if (node instanceof Element) {
				Element includeElement = (Element) node;
				TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
				valueHolder.setSource(parserContext.extractSource(includeElement));
				includePatterns.add(valueHolder);
			}
		}
		if (!includePatterns.isEmpty()) {
			includePatterns.setSource(parserContext.extractSource(element));
			beanDef.getPropertyValues().add("includePatterns", includePatterns);
		}
	}

}

//aop标签的spring.schemas
http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframework/aop/config/spring-aop-3.2.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.1.xsd

//aop标签的spring.handlers
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

```

### 自定义标签实现(例子)

```MyNamespaceHandler```<br />

```java

package com.wgq.spring.source.namespacehandler;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

import com.wgq.spring.source.parser.UserBeanDefintionParser;

public class MyNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		// TODO Auto-generated method stub
		registerBeanDefinitionParser("user", new UserBeanDefintionParser());
	}

}


```

```UserBeanDefintionParser```<br />
```java

package com.wgq.spring.source.parser;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.w3c.dom.Element;

import com.wgq.spring.source.pojo.User;

	public class UserBeanDefintionParser extends AbstractSingleBeanDefinitionParser {
	
		protected Class getBeanClass(Element element) {  
	        return User.class;  
	    }  
	  
	    protected void doParse(Element element, BeanDefinitionBuilder bean) {  
	        String userName = element.getAttribute("username");  
	        String email = element.getAttribute("email");  
	  
	        bean.addPropertyValue("username", userName);  
	        bean.addPropertyValue("email", email);  
	    }  
	
	}


```

```spring.handlers```<br />
```java

http\://www.wgq.com/schema/user=com.wgq.spring.source.namespacehandler.MyNamespaceHandler

```
```spring.schemas```<br />
```java

http\://www.wgq.com/schema/user.xsd=META-INF/spring-test.xsd

```
```spring-test.xsd```<br />
```xml

<?xml version="1.0" encoding="UTF-8"?>  
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.wgq.com/schema/user"  
    xmlns:tns="http://www.wgq.com/schema/user" elementFormDefault="qualified">  
    <element name="user">  
        <complexType>  
        	<attribute name="id" type="string" />  
            <attribute name="username" type="string" />  
            <attribute name="password" type="<PASSWORD>" />  
            <attribute name="email" type="string" />  
        </complexType>  
    </element>  
</schema>  

```
```dispatcherServlet-custom-tag.xml```<br />
```xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:myname="http://www.wgq.com/schema/user"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop   
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.wgq.com/schema/user 
       http://www.wgq.com/schema/user.xsd">
       
    <myname:user id="user" username="1111" email="sss"></myname:user>  
       
       
</beans>

```