public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
3.2 Thread 类
1 2 3 4 5 6 7 8 9
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();
3.3 Callable/Future 带返回值的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
public class CallableDemo implements Callable<String> { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool (1); CallableDemo callableDemo = new CallableDemo(); Future<String> future = executorService.submit(callableDemo); System.out.println(future.get()); executorService.shutdown(); } @Override public String call() throws Exception { int a = 1; int b = 2; System.out.println(a + b); return "执行结果:" + (a + b); } }
public class Thread implements Runnable { /* Make sure registerNatives is the first thing <clinit> does. */ private static native void registerNatives(); static { registerNatives();//start0()方法是在此方法中注册的 }
public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ group.add(this);
boolean started = false; try { start0();//实体调用的是这个方法,它是native的 started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } }
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : Thread() #if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) #endif // INCLUDE_ALL_GCS { if (TraceThreadEvents) { tty->print_cr("creating thread %p", this); } initialize(); _jni_attach_state = _not_attaching_via_jni; set_entry_point(entry_point); // Create the native thread itself. // %note runtime_23 os::ThreadType thr_type = os::java_thread; thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread; os::create_thread(this, thr_type, stack_sz); _safepoint_visible = false; // The _osthread may be NULL here because we ran out of memory (too many threads active). // We need to throw and OutOfMemoryError - however we cannot do this here because the caller // may hold a lock and all locks must be unlocked before throwing the exception (throwing // the exception consists of creating the exception object & initializing it, initialization // will leave the VM via a JavaCall and then all locks must be unlocked). // // The thread is still suspended when we reach here. Thread must be explicit started // by creator! Furthermore, the thread must also explicitly be added to the Threads list // by calling Threads:add. The reason why this is not done here, is because the thread // object must be fully initialized (take a look at JVM_Start) }
void Thread::start(Thread* thread) { trace("start", thread); // Start is different from resume in that its safety is guaranteed by context or // being called from a Java method synchronized on the Thread object. if (!DisableStartThread) { if (thread->is_Java_thread()) { // Initialize the thread state to RUNNABLE before starting this thread. // Can not set it after the thread started because we do not know the // exact thread state at that time. It could be in MONITOR_WAIT or // in SLEEPING or some other state. java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(), java_lang_Thread::RUNNABLE); } os::start_thread(thread); } }
// The first routine called by a new Java thread void JavaThread::run() { // initialize thread-local alloc buffer related fields this->initialize_tlab();
// used to test validitity of stack trace backs this->record_base_of_stack_pointer();
// Record real stack base and size. this->record_stack_base_and_size();
// Initialize thread local storage; set before calling MutexLocker this->initialize_thread_local_storage();
this->create_stack_guard_pages();
this->cache_global_variables();
// Thread is now sufficient initialized to be handled by the safepoint code as being // in the VM. Change thread state from _thread_new to _thread_in_vm ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
// This operation might block. We call that after all safepoint checks for a new thread has // been completed. this->set_active_handles(JNIHandleBlock::allocate_block());
if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_start(this); }
EventThreadStart event; if (event.should_commit()) { event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); event.commit(); }
// We call another function to do the rest so we are sure that the stack addresses used // from there will be lower than the stack base just computed thread_main_inner();
// Note, thread is no longer valid at this point! }
public void interrupt() { if (this != Thread.currentThread()) checkAccess();
synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); }
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate oop java_thread = JNIHandles::resolve_non_null(jthread); MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock); // We need to re-resolve the java_thread, since a GC might have happened during the // acquire of the lock JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)); if (thr != NULL) { Thread::interrupt(thr); } JVM_END
void os::interrupt(Thread* thread) { assert(Thread::current() == thread || Threads_lock->owned_by_self(), "possibility of dangling Thread pointer"); //获取本地线程对象 OSThread* osthread = thread->osthread(); //判断本地线程是否为中断 if (!osthread->interrupted()) { //设置中断状态为true osthread->set_interrupted(true); // More than one thread can get here with the same value of osthread, // resulting in multiple notifications. We do, however, want the store // to interrupted() to be visible to other threads before we execute unpark(). //内存屏障的目的是使得interrupted状态对其他线程立即可见 OrderAccess::fence(); //_SleepEvent相当于Thread.sleep,表示如果线程调用了sleep方法,则通过unpark唤醒 ParkEvent * const slp = thread->_SleepEvent ; if (slp != NULL) slp->unpark() ; }
// For JSR166. Unpark even if interrupt status already was set if (thread->is_Java_thread()) ((JavaThread*)thread)->parker()->unpark(); //_ParkEvent用于synchronized同步块和Object.wait(),这里相当于也是通过unpark进行唤醒 ParkEvent * ev = thread->_ParkEvent ; if (ev != NULL) ev->unpark() ;
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // XPathParser,dom 和 SAX 都有用到 >> parseConfiguration(parser.evalNode("/configuration")); return configuration; }
BusinessMapper mapper = session.getMapper(BusinessMapper.class); Business business = mapper.selectBusinessById(1);
1 2 3 4 5
<mapper namespace="com.sy.mapper.BusinessMapper">
<select id="selectBusinessById" resultMap="BaseResultMap" statementType="PREPARED" > select * from bsuiness where bid = #{bid} </select>
3.1 getMapper()方法
1、DefaultSqlSession中的getMapper()方法:
1 2 3 4
@Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
2、Configuration类中的getMapper()方法:
1 2 3
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
3、MapperRegistry中的getMapper()方法:
1 2 3 4 5 6 7 8 9 10 11
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
public <T> T selectOne(String statement, Object parameter) { // 来到了 DefaultSqlSession // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } }
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) { throw new ExecutorException("Executor was closed."); } CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); // 0 cacheKey.update(rowBounds.getLimit()); // 2147483647 = 2^31-1 cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); // development } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
即为方法相同、翻页偏移相同、SQL相同、参数值相同、数据源环境相同才会被认定为同一个查询。
注意看下CacheKey类的属性,里面有一个List按照顺序存放了上面的六要素。
1 2 3 4 5 6 7 8 9
private static final int DEFAULT_MULTIPLIER = 37; private static final int DEFAULT_HASHCODE = 17;
private final int multiplier; private int hashcode; private long checksum; private int count; // 8/21/2017 - Sonarlint flags this as needing to be marked transient. While true if content is not serializable, this is not always true and thus should not be marked transient. private List<Object> updateList;
if (boundSql == null) { // issue #435, get the key before calculating the statement generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); }
只要cacheEnabled=true基本执行器就会被装饰。有没有配置cache,决定了在启动的时候会不会创建这个mapper的Cache对象,只是最终会影响到CachingExecutorquery 方法里面的判断。如果某些查询方法对数据的实时性要求很高,不需要二级缓存,怎么办?我们可以在单个Statement ID 上显式关闭二级缓存(默认是true):
肯特·贝克和沃德·坎宁安在1987年,利用克里斯托佛·亚历山大在建筑设计领域里的思想开发了设计模式并把此思想应用在Smalltalk中的图形用户接口(GUI)的生成中。一年后埃里希·伽玛在他的苏黎世大学博士毕业论文中开始尝试把这种思想改写为适用于软件开发。与此同时James Coplien 在1989年至1991年也在利用相同的思想致力于C++的开发,而后于1991年发表了他的著作Advanced C++ Programming Styles and Idioms。同年Erich Gamma 得到了博士学位,然后去了美国,在那与Richard Helm, Ralph Johnson ,John Vlissides 合作出版了《设计模式:可复用面向对象软件的基础》(Design Patterns - Elements of Reusable Object-Oriented Software) 一书,在此书中共收录了 23 种设计模式。
这四位作者在软件开发领域里以“四人帮”(英语,Gang of Four,简称GoF)而闻名,并且他们在此书中的协作导致了软件设计模式的突破。有时,GoF也会用于代指《设计模式》这本书。
/** * Invoked for a directory before entries in the directory are visited. * * <p> If this method returns {@link FileVisitResult#CONTINUE CONTINUE}, * then entries in the directory are visited. If this method returns {@link * FileVisitResult#SKIP_SUBTREE SKIP_SUBTREE} or {@link * FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then entries in the * directory (and any descendants) will not be visited. * * @param dir * a reference to the directory * @param attrs * the directory's basic attributes * * @return the visit result * * @throws IOException * if an I/O error occurs */ FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException;
/** * Invoked for a file in a directory. * * @param file * a reference to the file * @param attrs * the file's basic attributes * * @return the visit result * * @throws IOException * if an I/O error occurs */ FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException;
/** * Invoked for a file that could not be visited. This method is invoked * if the file's attributes could not be read, the file is a directory * that could not be opened, and other reasons. * * @param file * a reference to the file * @param exc * the I/O exception that prevented the file from being visited * * @return the visit result * * @throws IOException * if an I/O error occurs */ FileVisitResult visitFileFailed(T file, IOException exc) throws IOException;
/** * Invoked for a directory after entries in the directory, and all of their * descendants, have been visited. This method is also invoked when iteration * of the directory completes prematurely (by a {@link #visitFile visitFile} * method returning {@link FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS}, * or an I/O error when iterating over the directory). * * @param dir * a reference to the directory * @param exc * {@code null} if the iteration of the directory completes without * an error; otherwise the I/O exception that caused the iteration * of the directory to complete prematurely * * @return the visit result * * @throws IOException * if an I/O error occurs */ FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException; }
public enum FileVisitResult { /** * Continue. When returned from a {@link FileVisitor#preVisitDirectory * preVisitDirectory} method then the entries in the directory should also * be visited. */ //当前的遍历过程将会继续 CONTINUE, /** * Terminate. */ //表示当前的遍历过程将会停止 TERMINATE, /** * Continue without visiting the entries in this directory. This result * is only meaningful when returned from the {@link * FileVisitor#preVisitDirectory preVisitDirectory} method; otherwise * this result type is the same as returning {@link #CONTINUE}. */ //当前的遍历过程将会继续,但是要忽略当前目录下的所有节点 SKIP_SUBTREE, /** * Continue without visiting the <em>siblings</em> of this file or directory. * If returned from the {@link FileVisitor#preVisitDirectory * preVisitDirectory} method then the entries in the directory are also * skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory} * method is not invoked. */ //当前的遍历过程将会继续,但是要忽略当前文件/目录的兄弟节点 SKIP_SIBLINGS; }
public class AddInterpreter extends Interpreter { public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); }
@Override public int interpret() { return this.left.interpret() + this.right.interpret(); } }
创建减法运算表达式SubInterpreter类:
1 2 3 4 5 6 7 8 9 10
public class SubInterpreter extends Interpreter { public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); }
@Override public int interpret() { return this.left.interpret() - this.right.interpret(); } }
创建乘法运算表达式MultiInterpreter类:
1 2 3 4 5 6 7 8 9 10
public class MultiInterpreter extends Interpreter { public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); }
@Override public int interpret() { return this.left.interpret() * this.right.interpret(); } }
创建除法运算表达式DivInterpreter类:
1 2 3 4 5 6 7 8 9 10
public class DivInterpreter extends Interpreter { public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); }
@Override public int interpret() { return this.left.interpret() / this.right.interpret(); } }
创建数学表达式NumInterpreter类:
1 2 3 4 5 6 7 8 9 10 11 12 13
public class NumInterpreter implements IArithmeticInterpreter {
private int value;
public NumInterpreter(int value) { this.value = value; }
@Override public int interpret() { return this.value; } }
private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large. if (Math.abs(period) > (Long.MAX_VALUE >> 1)) period >>= 1;
synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; }
queue.add(task); if (queue.getMin() == task) queue.notify(); } }
public interface StateManageableMessageContext extends MessageContext {
/** * Create a serializable memento, or token representing a snapshot of the internal state of this message context. * @return the messages memento */ public Serializable createMessagesMemento();
/** * Set the state of this context from the memento provided. After this call, the messages in this context will match * what is encapsulated inside the memento. Any previous state will be overridden. * @param messagesMemento the messages memento */ public void restoreMessages(Serializable messagesMemento);
/** * Configure the message source used to resolve messages added to this context. May be set at any time to change how * coded messages are resolved. * @param messageSource the message source * @see MessageContext#addMessage(MessageResolver) */ public void setMessageSource(MessageSource messageSource); }
public class DefaultMessageContext implements StateManageableMessageContext {
private static final Log logger = LogFactory.getLog(DefaultMessageContext.class);
private MessageSource messageSource;
@SuppressWarnings("serial") private Map<Object, List<Message>> sourceMessages = new AbstractCachingMapDecorator<Object, List<Message>>( new LinkedHashMap<Object, List<Message>>()) {
protected List<Message> create(Object source) { return new ArrayList<Message>(); } };
/** * Creates a new default message context. Defaults to a message source that simply resolves default text and cannot * resolve localized message codes. */ public DefaultMessageContext() { init(null); }
/** * Creates a new default message context. * @param messageSource the message source to resolve messages added to this context */ public DefaultMessageContext(MessageSource messageSource) { init(messageSource); }
public MessageSource getMessageSource() { return messageSource; }
// implementing message context
public Message[] getAllMessages() { List<Message> messages = new ArrayList<Message>(); for (List<Message> list : sourceMessages.values()) { messages.addAll(list); } return messages.toArray(new Message[messages.size()]); }
public Message[] getMessagesByCriteria(MessageCriteria criteria) { List<Message> messages = new ArrayList<Message>(); for (List<Message> sourceMessages : this.sourceMessages.values()) { for (Message message : sourceMessages) { if (criteria.test(message)) { messages.add(message); } } } return messages.toArray(new Message[messages.size()]); }
public boolean hasErrorMessages() { for (List<Message> sourceMessages : this.sourceMessages.values()) { for (Message message : sourceMessages) { if (message.getSeverity() == Severity.ERROR) { return true; } } } return false; }
public void addMessage(MessageResolver messageResolver) { Locale currentLocale = LocaleContextHolder.getLocale(); if (logger.isDebugEnabled()) { logger.debug("Resolving message using " + messageResolver); } Message message = messageResolver.resolveMessage(messageSource, currentLocale); List<Message> messages = sourceMessages.get(message.getSource()); if (logger.isDebugEnabled()) { logger.debug("Adding resolved message " + message); } messages.add(message); }
public void clearMessages() { sourceMessages.clear(); }
// implementing state manageable message context
public Serializable createMessagesMemento() { return new LinkedHashMap<Object, List<Message>>(sourceMessages); }
@SuppressWarnings("unchecked") public void restoreMessages(Serializable messagesMemento) { sourceMessages.putAll((Map<Object, List<Message>>) messagesMemento); }
public void setMessageSource(MessageSource messageSource) { if (messageSource == null) { messageSource = new DefaultTextFallbackMessageSource(); } this.messageSource = messageSource; }
// internal helpers
private void init(MessageSource messageSource) { setMessageSource(messageSource); // create the 'null' source message list eagerly to ensure global messages are indexed first this.sourceMessages.get(null); }
public String toString() { return new ToStringCreator(this).append("sourceMessages", sourceMessages).toString(); }
@Component("orderStateListener") @WithStateMachine(name = "orderStateMachine") public class OrderStateListenerImpl{ @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER") public boolean payTransition(Message<OrderStatusChangeEvent> message) { Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_DELIVER); System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString()); return true; } @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE") public boolean deliverTransition(Message<OrderStatusChangeEvent> message) { Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_RECEIVE); System.out.println("发货,状态机反馈信息:" + message.getHeaders().toString()); return true; } @OnTransition(source = "WAIT_RECEIVE", target = "FINISH") public boolean receiveTransition(Message<OrderStatusChangeEvent> message){ Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.FINISH); System.out.println("收货,状态机反馈信息:" + message.getHeaders().toString()); return true; } }
6、创建IOrderService接口
1 2 3 4 5 6 7 8 9 10 11 12
public interface IOrderService { //创建新订单 Order create(); //发起支付 Order pay(int id); //订单发货 Order deliver(int id); //订单收货 Order receive(int id); //获取所有订单信息 Map<Integer, Order> getOrders(); }
@Service("orderService") public class OrderServiceImpl implements IOrderService {
@Autowired private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine; @Autowired private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister; private int id = 1; private Map<Integer, Order> orders = new HashMap<>();
public Order create() { Order order = new Order(); order.setStatus(OrderStatus.WAIT_PAYMENT); order.setId(id++); orders.put(order.getId(), order); return order; }
public Order pay(int id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试支付,订单号:" + id); Message message = MessageBuilder.withPayload(OrderStatusChangeEvent.PAYED).setHeader("order", order).build(); if (!sendEvent(message, order)) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 支付失败, 状态异常,订单号:" + id); } return orders.get(id); }
public Order deliver(int id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试发货,订单号:" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.DELIVERY).setHeader("order", order).build(), orders.get(id))) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 发货失败,状态异常,订单号:" + id); } return orders.get(id); }
public Order receive(int id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.RECEIVED).setHeader("order", order).build(), orders.get(id))) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 收货失败,状态异常,订单号:" + id); } return orders.get(id); }
public class PhaseId implements Comparable { private final int ordinal; private String phaseName; private static int nextOrdinal = 0; private static final String ANY_PHASE_NAME = "ANY"; public static final PhaseId ANY_PHASE = new PhaseId("ANY"); private static final String RESTORE_VIEW_NAME = "RESTORE_VIEW"; public static final PhaseId RESTORE_VIEW = new PhaseId("RESTORE_VIEW"); private static final String APPLY_REQUEST_VALUES_NAME = "APPLY_REQUEST_VALUES"; public static final PhaseId APPLY_REQUEST_VALUES = new PhaseId("APPLY_REQUEST_VALUES"); private static final String PROCESS_VALIDATIONS_NAME = "PROCESS_VALIDATIONS"; public static final PhaseId PROCESS_VALIDATIONS = new PhaseId("PROCESS_VALIDATIONS"); private static final String UPDATE_MODEL_VALUES_NAME = "UPDATE_MODEL_VALUES"; public static final PhaseId UPDATE_MODEL_VALUES = new PhaseId("UPDATE_MODEL_VALUES"); private static final String INVOKE_APPLICATION_NAME = "INVOKE_APPLICATION"; public static final PhaseId INVOKE_APPLICATION = new PhaseId("INVOKE_APPLICATION"); private static final String RENDER_RESPONSE_NAME = "RENDER_RESPONSE"; public static final PhaseId RENDER_RESPONSE = new PhaseId("RENDER_RESPONSE"); private static final PhaseId[] values; public static final List VALUES;