public interface Runnable { /** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object’s * run method to be called in that separately executing * thread. *
* The general contract of the method run is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
public interface Iterator<E> { /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ boolean hasNext();
/** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next();
/** * Removes from the underlying collection the last element returned * by this iterator (optional operation). This method can be called * only once per call to {@link #next}. The behavior of an iterator * is unspecified if the underlying collection is modified while the * iteration is in progress in any way other than by calling this * method. * * @implSpec * The default implementation throws an instance of * {@link UnsupportedOperationException} and performs no other action. * * @throws UnsupportedOperationException if the {@code remove} * operation is not supported by this iterator * * @throws IllegalStateException if the {@code next} method has not * yet been called, or the {@code remove} method has already * been called after the last call to the {@code next} * method */ default void remove() { throw new UnsupportedOperationException("remove"); }
/** * Performs the given action for each remaining element until all elements * have been processed or the action throws an exception. Actions are * performed in the order of iteration, if that order is specified. * Exceptions thrown by the action are relayed to the caller. * * @implSpec * <p>The default implementation behaves as if: * <pre>{@code * while (hasNext()) * action.accept(next()); * }</pre> * * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount;
public boolean hasNext() { return cursor != size; }
@SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; }
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification();
@Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); }
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
public boolean hasPrevious() { return cursor != 0; }
public int nextIndex() { return cursor; }
public int previousIndex() { return cursor - 1; }
@SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; }
public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification();
责任链模式(Chain of Responsibility Pattern)是将链中的每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直到有对象处理这个请求为止。责任模式主要是解耦请求与处理,客户只要将请求发送到对应的链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点的对象进行处理。
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); Assert.state(this.request == null, "This FilterChain has already been called!"); if (this.iterator == null) { this.iterator = this.filters.iterator(); }
/** * Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events. */ void handlerAdded(ChannelHandlerContext ctx) throws Exception;
/** * Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events * anymore. */ void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
/** * Gets called if a {@link Throwable} was thrown. * * @deprecated is part of {@link ChannelInboundHandler} */ @Deprecated void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
/** * Indicates that the same instance of the annotated {@link ChannelHandler} * can be added to one or more {@link ChannelPipeline}s multiple times * without a race condition. * <p> * If this annotation is not specified, you have to create a new handler * instance every time you add it to a pipeline because it has unshared * state such as member variables. * <p> * This annotation is provided for documentation purpose, just like * <a href="http://www.javaconcurrencyinpractice.com/annotations/doc/">the JCIP annotations</a>. */ @Inherited @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Sharable { // no value } }
/** * Registers the given driver with the {@code DriverManager}. * A newly-loaded driver class should call * the method {@code registerDriver} to make itself * known to the {@code DriverManager}. If the driver is currently * registered, no action is taken. * * @param driver the new JDBC Driver that is to be registered with the * {@code DriverManager} * @exception SQLException if a database access error occurs * @exception NullPointerException if {@code driver} is null */ public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
registerDriver(driver, null); }
/** * Registers the given driver with the {@code DriverManager}. * A newly-loaded driver class should call * the method {@code registerDriver} to make itself * known to the {@code DriverManager}. If the driver is currently * registered, no action is taken. * * @param driver the new JDBC Driver that is to be registered with the * {@code DriverManager} * @param da the {@code DriverAction} implementation to be used when * {@code DriverManager#deregisterDriver} is called * @exception SQLException if a database access error occurs * @exception NullPointerException if {@code driver} is null * @since 1.8 */ public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
/* Register the driver if it has not already been added to our list */ if(driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); } else { // This is for compatibility with the original DriverManager throw new NullPointerException(); }
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. *<p> * <B>Note:</B> If a property is specified as part of the {@code url} and * is also specified in the {@code Properties} object, it is * implementation-defined as to which value will take precedence. * For maximum portability, an application should only specify a * property once. * * @param url a database url of the form * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> * @param info a list of arbitrary string tag/value pairs as * connection arguments; normally at least a "user" and * "password" property should be included * @return a Connection to the URL * @exception SQLException if a database access error occurs or the url is * {@code null} * @throws SQLTimeoutException when the driver has determined that the * timeout value specified by the {@code setLoginTimeout} method * has been exceeded and has at least tried to cancel the * current database connection attempt */ @CallerSensitive public static Connection getConnection(String url, java.util.Properties info) throws SQLException {
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. *<p> * <B>Note:</B> If the {@code user} or {@code password} property are * also specified as part of the {@code url}, it is * implementation-defined as to which value will take precedence. * For maximum portability, an application should only specify a * property once. * * @param url a database url of the form * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> * @param user the database user on whose behalf the connection is being * made * @param password the user's password * @return a connection to the URL * @exception SQLException if a database access error occurs or the url is * {@code null} * @throws SQLTimeoutException when the driver has determined that the * timeout value specified by the {@code setLoginTimeout} method * has been exceeded and has at least tried to cancel the * current database connection attempt */ @CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties();
if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); }
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. * * @param url a database url of the form * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> * @return a connection to the URL * @exception SQLException if a database access error occurs or the url is * {@code null} * @throws SQLTimeoutException when the driver has determined that the * timeout value specified by the {@code setLoginTimeout} method * has been exceeded and has at least tried to cancel the * current database connection attempt */ @CallerSensitive public static Connection getConnection(String url) throws SQLException {
java.util.Properties info = new java.util.Properties(); return (getConnection(url, info, Reflection.getCallerClass())); } private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { // synchronize loading of the correct classloader. if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } }
if(url == null) { throw new SQLException("The url cannot be null", "08001"); }
// Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } }
public Folder(String name, Integer level) { super(name); this.level = level; this.dirs = new ArrayList<>(); }
public boolean add(Directory dir) { return dirs.add(dir); }
public boolean remove(Directory dir) { return dirs.remove(dir); }
public Object get(int index) { return dirs.get(index); }
public void list() { for(Directory dir : dirs) { System.out.println(dir.name); } }
@Override public void show() { System.out.println(this.name); for (Directory dir : this.dirs) { //控制显示格式 if (this.level != null) { for (int i = 0; i < this.level; i++) { //打印空格控制格式 System.out.print(" "); } for (int i = 0; i < this.level; i++) { //每一行开始打印一个+号 if (i == 0) { System.out.print("+"); } System.out.print("-"); } } //打印名称 dir.show(); } } }
1 2 3 4 5 6 7 8 9 10 11
public class File extends Directory {
public File(String name) { super(name); }
@Override public void show() { System.out.println(this.name); } }
public void putAll(Map<? extends K, ? extends V> m) { putMapEntries(m, true); }
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } }
public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; }
public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); }
public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; }
public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } }
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
public final class Long extends Number implements Comparable<Long> { public static Long valueOf(long var0) { return var0 >= -128L && var0 <= 127L ? Long.LongCache.cache[(int)var0 + 128] : new Long(var0); } private static class LongCache { private LongCache(){} static final Long cache[] = new Long[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Long(i - 128); } } //... }
public class SubSystemA { public void doA() { System.out.println("doing A stuff"); } }
public class SubSystemB { public void doB() { System.out.println("doing B stuff"); } }
public class SubSystemC { public void doC() { System.out.println("doing C stuff"); } }
然后,创建外观角色 Facade 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public class Facade { private SubSystemA a = new SubSystemA(); private SubSystemB b = new SubSystemB(); private SubSystemC c = new SubSystemC(); // 对外接口 public void doA() { this.a.doA(); } // 对外接口 public void doB() { this.b.doB(); } // 对外接口 public void doC() { this.c.doC(); } }
测试main方法:
1 2 3 4 5 6
public static void main(String[] args) { Facade facade = new Facade(); facade.doA(); facade.doB(); facade.doC(); }
public class CouponStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("领取的优惠券在指定时间到店消费,订单的价格直接减优惠券面额抵扣!"); } }
返现促销策略 CashBackStrategy 类:
1 2 3 4 5 6
public class CashBackStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("返现促销,返回的金额转到支付账号!"); } }
拼团优惠策略 GroupBuyStrategy 类:
1 2 3 4 5 6
public class GroupBuyStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("拼团,满5人成团,全团享受团购价!"); } }
无优惠策略 EmptyStrategy 类:
1 2 3 4 5 6
public class EmptyStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("无促销活动!"); } }
然后创建促销活动方案 PromotionActivity 类:
1 2 3 4 5 6 7 8 9 10 11 12
public class PromotionActivity {
private IPromotionStrategy promotionStrategy;
public PromotionActivity(IPromotionStrategy promotionStrategy) { this.promotionStrategy = promotionStrategy; }
public void execute() { promotionStrategy.doPromotion(); } }
编写测试类:
1 2 3 4 5 6
public static void main(String[] args) { PromotionActivity activity_618 = new PromotionActivity(new CouponStrategy()); PromotionActivity activity_1212 = new PromotionActivity(new CashBackStrategy()); activity_618.execute(); activity_1212.execute(); }
private static Map<String, IPromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>(); static { PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON, new CouponStrategy()); PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK, new CashBackStrategy()); PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY, new GroupBuyStrategy()); }
private static final IPromotionStrategy NO_PROMOTION = new EmptyStrategy();
public static final Map<String, Payment> PAYMENT_MAP = new HashMap<>();
static { PAYMENT_MAP.put(PayKey.ALIPAY, new AliPay()); PAYMENT_MAP.put(PayKey.WECHATPAY, new WechatPay()); PAYMENT_MAP.put(PayKey.UNIONPAY, new UnionPay()); }
public static void main(String[] args) throws ParseException {
Order order = new Order();
order.setId("010101001");
//Date today = new Date();
//order.setCreateTime(today.getTime());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = sdf.parse("2019/02/01");
order.setCreateTime(date.getTime());
IOrderService orderService = new OrderServiceStaticProxy(new OrderService());
orderService.createOrder(order);
public class Customer implements Person { @Override public void lookForMate() { System.out.println("高富帅"); System.out.println("身高180cm"); System.out.println("有房有车"); } }
测试main方法代码:
1 2 3 4 5 6 7
public static void main(String[] args) {
JDKMarriage marriage = new JDKMarriage();
Person person = (Person) marriage.getInstance(new Customer()); person.lookForMate(); }
public void after() { System.out.println("代理方法执行结束了......"); } }
测试main方法代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
public static void main(String[] args) throws ParseException { Order order = new Order(); order.setId("010101001"); // Date today = new Date(); // order.setCreateTime(today.getTime());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); Date date = sdf.parse("2019/02/01"); order.setCreateTime(date.getTime());
IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy().getInstance(new OrderService()); orderService.createOrder(order); }
运行结果:
依然可以达到想要的运行效果。但是,动态代理实现之后,我们不仅能实现 Order 的数据源动态路由,还可以实现其他任何类的数据源路由。
@Nullable public Object getObject() throws BeansException { this.initializeAdvisorChain(); if (this.isSingleton()) { return this.getSingletonInstance(); } else { if (this.targetName == null) { this.logger.info("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property."); }
return this.newPrototypeInstance(); } }
在 getObject()方法中,主要调用 getSingletonInstance() 和newPrototypeInstance() ; 在 Spring 的配置中,如果不做任何设置,那么 Spring 代理生成的 Bean 都是单例对象。如果修改 scope则每次创建一个新的原型对象。newPrototypeInstance()里面的逻辑比较复杂,我们后面的课程再做深入研究,这里我们先做简单的了解。
3.2 Spring 中的代理选择原则
Spring 利用动态代理实现 AOP 有两个非常重要的类,一个是 JdkDynamicAopProxy 类和 CglibAopProxy 类,来看一下类图: