知乎网站建设,深圳手机端网站建设专业公司,wordpress 页面分类,公众号开发公司排行榜文章目录从框架源码中解读创建型设计模式工厂模式案例一#xff1a;RocketMQ源码-创建Producer生产者案例二#xff1a;RocketMQ源码-创建过滤器工厂抽象工厂案例一#xff1a;Dubbo源码-创建缓存的抽象工厂案例二#xff1a;RocketMQ源码-创建日志对象的抽象工厂单例模式面…
文章目录从框架源码中解读创建型设计模式工厂模式案例一RocketMQ源码-创建Producer生产者案例二RocketMQ源码-创建过滤器工厂抽象工厂案例一Dubbo源码-创建缓存的抽象工厂案例二RocketMQ源码-创建日志对象的抽象工厂单例模式面试官单例有几种写法案例一dubbo源码-饿汉式案例二RocketMQ源码-懒汉式-非线程安全案例三双重检查锁案例四线程安全synchronized方法案例五枚举类案例六静态内部类建造者模式案例dubbo源码使用原型模式案例RocketMQ源码-拷贝数组对象从框架源码中解读创建型设计模式
概念创建型设计模式顾名思义是用来创建对象的同时隐藏创建逻辑的方式而不是通过new关键字直接实例化对象使得程序判别某个对象是否需要创建时更加灵活。
工厂模式
工厂模式是最常见的设计模式。通过工厂封装对象创建逻辑提供一个接口供调用者创建对象。
案例一RocketMQ源码-创建Producer生产者
public class ProducerFactory {public static DefaultMQProducer getRMQProducer(String ns) {DefaultMQProducer producer new DefaultMQProducer(RandomUtil.getStringByUUID());producer.setInstanceName(UUID.randomUUID().toString());producer.setNamesrvAddr(ns);try {producer.start();} catch (MQClientException e) {e.printStackTrace();}return producer;}
}每调用一次都会获得新的对象实例。 案例二RocketMQ源码-创建过滤器工厂
public class FilterFactory {public static final FilterFactory INSTANCE new FilterFactory();protected static final MapString, FilterSpi FILTER_SPI_HOLDER new HashMapString, FilterSpi(4);static {FilterFactory.INSTANCE.register(new SqlFilter());}public void register(FilterSpi filterSpi) {if (FILTER_SPI_HOLDER.containsKey(filterSpi.ofType())) {throw new IllegalArgumentException(String.format(Filter spi type(%s) already exist!, filterSpi.ofType()));}FILTER_SPI_HOLDER.put(filterSpi.ofType(), filterSpi);}public FilterSpi unRegister(String type) {return FILTER_SPI_HOLDER.remove(type);}public FilterSpi get(String type) {return FILTER_SPI_HOLDER.get(type);}}没创建完将对象缓存到本地内存中之后从内存中获取对象 抽象工厂
用来创建工厂的工厂。
案例一Dubbo源码-创建缓存的抽象工厂
先定义一个创建工厂的接口(SPI:表示这个接口是基于SPI拓展接口)。
SPI(lru)
public interface CacheFactory {Adaptive(cache)Cache getCache(URL url, Invocation invocation);
}定义一个抽象工厂实现通用的getCache()方法并将对象管理逻辑定义在抽象类中并提供一个createCache()方法让工厂的实现类不用关系内部对象管理逻辑只需要实现createCache()方法即可。
public abstract class AbstractCacheFactory implements CacheFactory {private final ConcurrentMapString, Cache caches new ConcurrentHashMapString, Cache();Overridepublic Cache getCache(URL url, Invocation invocation) {url url.addParameter(METHOD_KEY, invocation.getMethodName());String key url.toFullString();Cache cache caches.get(key);if (cache null) {caches.put(key, createCache(url));cache caches.get(key);}return cache;}protected abstract Cache createCache(URL url);}实现抽象工厂的工厂实现类缓存有多种实现方式有LRU、LFU等等
public class LruCacheFactory extends AbstractCacheFactory {Overrideprotected Cache createCache(URL url) {return new LruCache(url);}}public class LfuCacheFactory extends AbstractCacheFactory {Overrideprotected Cache createCache(URL url) {return new LfuCache(url);}}过期时间缓存实现工厂
public class ExpiringCacheFactory extends AbstractCacheFactory {Overrideprotected Cache createCache(URL url) {return new ExpiringCache(url);}
}案例二RocketMQ源码-创建日志对象的抽象工厂
public abstract class InternalLoggerFactory {public static final String LOGGER_SLF4J slf4j;public static final String LOGGER_INNER inner;public static final String DEFAULT_LOGGER LOGGER_SLF4J;private static String loggerType null;//缓存容器private static ConcurrentHashMapString, InternalLoggerFactory loggerFactoryCache new ConcurrentHashMapString, InternalLoggerFactory();//通过类获取对象实例public static InternalLogger getLogger(Class clazz) {return getLogger(clazz.getName());}//通过日志类型获取内部日志对象实例public static InternalLogger getLogger(String name) {return getLoggerFactory().getLoggerInstance(name);}//获取内部工厂对象private static InternalLoggerFactory getLoggerFactory() {InternalLoggerFactory internalLoggerFactory null;if (loggerType ! null) {internalLoggerFactory loggerFactoryCache.get(loggerType);}if (internalLoggerFactory null) {internalLoggerFactory loggerFactoryCache.get(DEFAULT_LOGGER);}if (internalLoggerFactory null) {internalLoggerFactory loggerFactoryCache.get(LOGGER_INNER);}if (internalLoggerFactory null) {throw new RuntimeException([RocketMQ] Logger init failed, please check logger);}return internalLoggerFactory;}//设置当前日志类型public static void setCurrentLoggerType(String type) {loggerType type;}//程序启动默认注册Slf4j工厂和内部日志工厂到loggerFactoryCache容器中static {try {new Slf4jLoggerFactory();} catch (Throwable e) {//ignore}try {new InnerLoggerFactory();} catch (Throwable e) {//ignore}}//注册工厂逻辑protected void doRegister() {String loggerType getLoggerType();if (loggerFactoryCache.get(loggerType) ! null) {return;}loggerFactoryCache.put(loggerType, this);}protected abstract void shutdown();//获取内部日志对象protected abstract InternalLogger getLoggerInstance(String name);//获取日志类型protected abstract String getLoggerType();
}通过抽象工厂实现Slf4jLoggerFactory工厂
public class Slf4jLoggerFactory extends InternalLoggerFactory {public Slf4jLoggerFactory() {LoggerFactory.getILoggerFactory();doRegister();}Overrideprotected String getLoggerType() {return InternalLoggerFactory.LOGGER_SLF4J;}Overrideprotected InternalLogger getLoggerInstance(String name) {return new Slf4jLogger(name);}Overrideprotected void shutdown() {}public static class Slf4jLogger implements InternalLogger {private Logger logger null;public Slf4jLogger(String name) {logger LoggerFactory.getLogger(name);}Overridepublic String getName() {return logger.getName();}Overridepublic void debug(String s) {logger.debug(s);}Overridepublic void info(String s) {logger.info(s);}Overridepublic void warn(String s) {logger.warn(s);}Overridepublic void warn(String s, Throwable throwable) {logger.warn(s, throwable);}Overridepublic void error(String s) {logger.error(s);}Overridepublic void error(String s, Throwable throwable) {logger.error(s, throwable);}}
}单例模式
单例模式Singleton Pattern是 Java 中最简单的设计模式之一。该类负责创建自己的对象同时确保只有单个对象被创建同时提供了一种访问其唯一对象的方式。
面试官单例有几种写法
饿汉式类加载时就初始化浪费内存懒汉式-非线程安全用到的时候才初始化懒汉式-线程安全synchronized方法每次都需要加载性能慢懒汉式-双重检查锁这种方式比第三种性能更高但是每次都需要做判断而且书写麻烦个人建议还不如用静态内部类方式枚举这是实现单例模式的最佳方法。它更简洁自动支持序列化机制绝对防止多次实例化。推荐使用静态内部类在主类中提供一个静态内部类在初始化时候创建对象主类提供获取单例对象方法用到的时候初始化通过ClassLoader机制保证只有一个线程创建实例。推荐使用
案例一dubbo源码-饿汉式
public class ShutdownHookCallbacks {public static final ShutdownHookCallbacks INSTANCE new ShutdownHookCallbacks();private final ListShutdownHookCallback callbacks new LinkedList();ShutdownHookCallbacks() {loadCallbacks();}public ShutdownHookCallbacks addCallback(ShutdownHookCallback callback) {synchronized (this) {this.callbacks.add(callback);}return this;}public CollectionShutdownHookCallback getCallbacks() {synchronized (this) {sort(this.callbacks);return this.callbacks;}}public void clear() {synchronized (this) {callbacks.clear();}}private void loadCallbacks() {ExtensionLoaderShutdownHookCallback loader ExtensionLoader.getExtensionLoader(ShutdownHookCallback.class);loader.getSupportedExtensionInstances().forEach(this::addCallback);}public void callback() {getCallbacks().forEach(callback - execute(callback::callback));}
}案例二RocketMQ源码-懒汉式-非线程安全
public class MQClientManager {private final static InternalLogger log ClientLogger.getLog();private static MQClientManager instance new MQClientManager();private AtomicInteger factoryIndexGenerator new AtomicInteger();private ConcurrentMapString/* clientId */, MQClientInstance factoryTable new ConcurrentHashMapString, MQClientInstance();private MQClientManager() {}public static MQClientManager getInstance() {return instance;}public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientConfig) {return getOrCreateMQClientInstance(clientConfig, null);}//懒汉式public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientConfig, RPCHook rpcHook) {String clientId clientConfig.buildMQClientId();MQClientInstance instance this.factoryTable.get(clientId);if (null instance) {instance new MQClientInstance(clientConfig.cloneClientConfig(),this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);MQClientInstance prev this.factoryTable.putIfAbsent(clientId, instance);if (prev ! null) {instance prev;log.warn(Returned Previous MQClientInstance for clientId:[{}], clientId);} else {log.info(Created new MQClientInstance for clientId:[{}], clientId);}}return instance;}public void removeClientFactory(final String clientId) {this.factoryTable.remove(clientId);}
}特别注意使用这种方式获取单例非线程安全的那RocketMQ这样使用不是有错呢如果只是单纯这样使用肯定是有错的但是上层调用加了synchronized就没有问题如下
public class DefaultMQPullConsumerImpl implements MQConsumerInner {...public synchronized void start() throws MQClientException {switch (this.serviceState) {case CREATE_JUST:this.serviceState ServiceState.START_FAILED;this.checkConfig();this.copySubscription();if (this.defaultMQPullConsumer.getMessageModel() MessageModel.CLUSTERING) {this.defaultMQPullConsumer.changeInstanceNameToPID();}this.mQClientFactory MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQPullConsumer, this.rpcHook);...
}
案例三双重检查锁
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton null) { synchronized (Singleton.class) { if (singleton null) { singleton new Singleton(); } } } return singleton; }
}案例四线程安全synchronized方法
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance null) { instance new Singleton(); } return instance; }
}案例五枚举类
public enum Singleton {INSTANCE;public void doSomething() {System.out.println(doSomething);}}案例六静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; }
}建造者模式
使用多个简单的对象一步步构成复制对象。
案例dubbo源码使用
package org.apache.dubbo.config.bootstrap.builders;import org.apache.dubbo.config.RegistryConfig;import java.util.Map;/*** This is a builder for build {link RegistryConfig}.** since 2.7*/
public class RegistryBuilder extends AbstractBuilderRegistryConfig, RegistryBuilder {/*** Register center address*/private String address;/*** Username to login register center*/private String username;/*** Password to login register center*/private String password;/*** Default port for register center*/private Integer port;/*** Protocol for register center*/private String protocol;/*** Network transmission type*/private String transporter;private String server;private String client;private String cluster;...public static RegistryBuilder newBuilder() {return new RegistryBuilder();}public RegistryBuilder id(String id) {return super.id(id);}public RegistryBuilder address(String address) {this.address address;return getThis();}public RegistryBuilder username(String username) {this.username username;return getThis();}public RegistryBuilder password(String password) {this.password password;return getThis();}...public RegistryConfig build() {RegistryConfig registry new RegistryConfig();super.build(registry);registry.setCheck(check);registry.setClient(client);registry.setCluster(cluster);registry.setDefault(isDefault);registry.setDynamic(dynamic);registry.setExtraKeys(extraKeys);registry.setFile(file);registry.setGroup(group);registry.setParameters(parameters);registry.setPassword(password);registry.setPort(port);registry.setProtocol(protocol);registry.setRegister(register);registry.setServer(server);registry.setSession(session);registry.setSimplified(simplified);registry.setSubscribe(subscribe);registry.setTimeout(timeout);registry.setTransporter(transporter);registry.setUsername(username);registry.setVersion(version);registry.setWait(wait);registry.setUseAsConfigCenter(useAsConfigCenter);registry.setUseAsMetadataCenter(useAsMetadataCenter);registry.setAccepts(accepts);registry.setPreferred(preferred);registry.setWeight(weight);registry.setAddress(address);return registry;}Overrideprotected RegistryBuilder getThis() {return this;}
}
原型模式
用来拷贝对象通过实现Cloneable接口中的clone()方法使用时注意深拷贝、浅拷贝问题。
案例RocketMQ源码-拷贝数组对象
package org.apache.rocketmq.filter.util;/*** Wrapper of bytes array, in order to operate single bit easily.*/
public class BitsArray implements Cloneable {private byte[] bytes;private int bitLength;public static BitsArray create(int bitLength) {return new BitsArray(bitLength);}private BitsArray(int bitLength) {this.bitLength bitLength;// init bytesint temp bitLength / Byte.SIZE;if (bitLength % Byte.SIZE 0) {temp;}bytes new byte[temp];for (int i 0; i bytes.length; i) {bytes[i] (byte) 0x00;}}private BitsArray(byte[] bytes) {if (bytes null || bytes.length 1) {throw new IllegalArgumentException(Bytes is empty!);}this.bitLength bytes.length * Byte.SIZE;this.bytes new byte[bytes.length];System.arraycopy(bytes, 0, this.bytes, 0, this.bytes.length);}...public BitsArray clone() {byte[] clone new byte[this.byteLength()];System.arraycopy(this.bytes, 0, clone, 0, this.byteLength());return create(clone, bitLength());}
}