从框架源码中学习结构型设计模式

文章目录

  • 从框架源码学习结构型设计模式
    • 适配器模式
      • 应用实例
      • 案例一:dubbo框架日志适配器
        • Logger接口
        • 日志实现类
        • Logger适配器接口
        • LoggerAdapter实现类
        • Logger日志工厂
    • 桥接模式
      • 应用场景
      • 案例:dubbo源码-远程调用模块channelHandler设计
        • ChannelHandler是一个SPI拓展接口,用户可以定制自己的Handler
        • 抽象类:桥接ChannelHandler并实现自己的Handler
        • ChannelHandler实现类
        • 抽象类实现类
    • 组合模式
    • 装饰器模式
      • 案例:apache common-collections源码List分析
        • jdk List接口源码
        • List装饰器抽象方法
        • 序列化装饰器抽象方法
        • FixedSizeList源码
        • LazyList实现类
    • 外观模式(门面模式)
      • 案例:sl4j日志使用
    • 享元模式
      • RocketMQ过滤器工厂创建Filter
    • 代理模式
      • 静态代理
        • 案例:rocketmq中滚动记录文件,先将日志记录到指定文件代理类实现
      • 动态代理
        • JDK动态代理
          • 案例:dubbo中jdk动态代理工厂实现
        • CGLIB动态代理
          • 案例:dubbo中cglib创建代理类
        • javassist动态代码创建

从框架源码学习结构型设计模式

模式包括
结构型模式 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern)

适配器模式

使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。最典型的例子如:读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡

应用实例

JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。

public class EnumerationAdapter<E> implements Iterator<E> {Enumeration<E> enumeration;public EnumerationAdapter(Enumeration<E> enumeration) {this.enumeration = enumeration;}@Overridepublic boolean hasNext() {return enumeration.hasMoreElements();}@Overridepublic E next() {return enumeration.nextElement();}@Overridepublic void remove() {throw new UnsupportedOperationException("remove");}
}

案例一:dubbo框架日志适配器

dubbo中通过LoggerFactory日志工厂创建log对象,流行的日志框架有log4j、sl4j、log4j2、logback等而他们创建日志的对象各不相同,如果不用适配器直接在LoggerFactory上创建日志对象,那么每新加入一个新的日志框架都需要去修改LoggerFactory类,而利用适配器的话新加入的日志框架可以基于SPI实现LoggerAdapter接口实现对象创建逻辑,并且通过Adapter封装统一的getLogger()、setLogger()、setLevel()统一方法,然后通过LoggerFactory#setLoggerAdapter()方法将对象放入日志工厂中。

在这里插入图片描述

Logger接口

public interface Logger {/*** Logs a message with trace log level.** @param msg log this message*/void trace(String msg);/*** Logs an error with trace log level.** @param e log this cause*/void trace(Throwable e);/*** Logs an error with trace log level.** @param msg log this message* @param e   log this cause*/void trace(String msg, Throwable e);/*** Logs a message with debug log level.** @param msg log this message*/void debug(String msg);/*** Logs an error with debug log level.** @param e log this cause*/void debug(Throwable e);/*** Logs an error with debug log level.** @param msg log this message* @param e   log this cause*/void debug(String msg, Throwable e);/*** Logs a message with info log level.** @param msg log this message*/void info(String msg);/*** Logs an error with info log level.** @param e log this cause*/void info(Throwable e);/*** Logs an error with info log level.** @param msg log this message* @param e   log this cause*/void info(String msg, Throwable e);/*** Logs a message with warn log level.** @param msg log this message*/void warn(String msg);/*** Logs a message with warn log level.** @param e log this message*/void warn(Throwable e);/*** Logs a message with warn log level.** @param msg log this message* @param e   log this cause*/void warn(String msg, Throwable e);/*** Logs a message with error log level.** @param msg log this message*/void error(String msg);/*** Logs an error with error log level.** @param e log this cause*/void error(Throwable e);/*** Logs an error with error log level.** @param msg log this message* @param e   log this cause*/void error(String msg, Throwable e);/*** Is trace logging currently enabled?** @return true if trace is enabled*/boolean isTraceEnabled();/*** Is debug logging currently enabled?* * @return true if debug is enabled*/boolean isDebugEnabled();/*** Is info logging currently enabled?** @return true if info is enabled*/boolean isInfoEnabled();/*** Is warn logging currently enabled?** @return true if warn is enabled*/boolean isWarnEnabled();/*** Is error logging currently enabled?** @return true if error is enabled*/boolean isErrorEnabled();}

日志实现类

public class Log4jLogger implements Logger {private static final String FQCN = FailsafeLogger.class.getName();private final org.apache.log4j.Logger logger;public Log4jLogger(org.apache.log4j.Logger logger) {this.logger = logger;}@Overridepublic void trace(String msg) {logger.log(FQCN, Level.TRACE, msg, null);}@Overridepublic void trace(Throwable e) {logger.log(FQCN, Level.TRACE, e == null ? null : e.getMessage(), e);}@Overridepublic void trace(String msg, Throwable e) {logger.log(FQCN, Level.TRACE, msg, e);}@Overridepublic void debug(String msg) {logger.log(FQCN, Level.DEBUG, msg, null);}@Overridepublic void debug(Throwable e) {logger.log(FQCN, Level.DEBUG, e == null ? null : e.getMessage(), e);}@Overridepublic void debug(String msg, Throwable e) {logger.log(FQCN, Level.DEBUG, msg, e);}@Overridepublic void info(String msg) {logger.log(FQCN, Level.INFO, msg, null);}@Overridepublic void info(Throwable e) {logger.log(FQCN, Level.INFO, e == null ? null : e.getMessage(), e);}@Overridepublic void info(String msg, Throwable e) {logger.log(FQCN, Level.INFO, msg, e);}@Overridepublic void warn(String msg) {logger.log(FQCN, Level.WARN, msg, null);}@Overridepublic void warn(Throwable e) {logger.log(FQCN, Level.WARN, e == null ? null : e.getMessage(), e);}@Overridepublic void warn(String msg, Throwable e) {logger.log(FQCN, Level.WARN, msg, e);}@Overridepublic void error(String msg) {logger.log(FQCN, Level.ERROR, msg, null);}@Overridepublic void error(Throwable e) {logger.log(FQCN, Level.ERROR, e == null ? null : e.getMessage(), e);}@Overridepublic void error(String msg, Throwable e) {logger.log(FQCN, Level.ERROR, msg, e);}@Overridepublic boolean isTraceEnabled() {return logger.isTraceEnabled();}@Overridepublic boolean isDebugEnabled() {return logger.isDebugEnabled();}@Overridepublic boolean isInfoEnabled() {return logger.isInfoEnabled();}@Overridepublic boolean isWarnEnabled() {return logger.isEnabledFor(Level.WARN);}@Overridepublic boolean isErrorEnabled() {return logger.isEnabledFor(Level.ERROR);}}

Logger适配器接口

@SPI
public interface LoggerAdapter {/*** Get a logger** @param key the returned logger will be named after clazz* @return logger*/Logger getLogger(Class<?> key);/*** Get a logger** @param key the returned logger will be named after key* @return logger*/Logger getLogger(String key);/*** Get the current logging level** @return current logging level*/Level getLevel();/*** Set the current logging level** @param level logging level*/void setLevel(Level level);/*** Get the current logging file** @return current logging file*/File getFile();/*** Set the current logging file** @param file logging file*/void setFile(File file);
}

LoggerAdapter实现类

public class Log4jLoggerAdapter implements LoggerAdapter {private File file;@SuppressWarnings("unchecked")public Log4jLoggerAdapter() {try {org.apache.log4j.Logger logger = LogManager.getRootLogger();if (logger != null) {Enumeration<Appender> appenders = logger.getAllAppenders();if (appenders != null) {while (appenders.hasMoreElements()) {Appender appender = appenders.nextElement();if (appender instanceof FileAppender) {FileAppender fileAppender = (FileAppender) appender;String filename = fileAppender.getFile();file = new File(filename);break;}}}}} catch (Throwable t) {}}private static org.apache.log4j.Level toLog4jLevel(Level level) {if (level == Level.ALL) {return org.apache.log4j.Level.ALL;}if (level == Level.TRACE) {return org.apache.log4j.Level.TRACE;}if (level == Level.DEBUG) {return org.apache.log4j.Level.DEBUG;}if (level == Level.INFO) {return org.apache.log4j.Level.INFO;}if (level == Level.WARN) {return org.apache.log4j.Level.WARN;}if (level == Level.ERROR) {return org.apache.log4j.Level.ERROR;}// if (level == Level.OFF)return org.apache.log4j.Level.OFF;}private static Level fromLog4jLevel(org.apache.log4j.Level level) {if (level == org.apache.log4j.Level.ALL) {return Level.ALL;}if (level == org.apache.log4j.Level.TRACE) {return Level.TRACE;}if (level == org.apache.log4j.Level.DEBUG) {return Level.DEBUG;}if (level == org.apache.log4j.Level.INFO) {return Level.INFO;}if (level == org.apache.log4j.Level.WARN) {return Level.WARN;}if (level == org.apache.log4j.Level.ERROR) {return Level.ERROR;}// if (level == org.apache.log4j.Level.OFF)return Level.OFF;}@Overridepublic Logger getLogger(Class<?> key) {return new Log4jLogger(LogManager.getLogger(key));}@Overridepublic Logger getLogger(String key) {return new Log4jLogger(LogManager.getLogger(key));}@Overridepublic Level getLevel() {return fromLog4jLevel(LogManager.getRootLogger().getLevel());}@Overridepublic void setLevel(Level level) {LogManager.getRootLogger().setLevel(toLog4jLevel(level));}@Overridepublic File getFile() {return file;}@Overridepublic void setFile(File file) {}}

Logger日志工厂

public class LoggerFactory {private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap<>();private static volatile LoggerAdapter LOGGER_ADAPTER;// search common-used logging frameworksstatic {String logger = System.getProperty("dubbo.application.logger", "");switch (logger) {case "slf4j":setLoggerAdapter(new Slf4jLoggerAdapter());break;case "jcl":setLoggerAdapter(new JclLoggerAdapter());break;case "log4j":setLoggerAdapter(new Log4jLoggerAdapter());break;case "jdk":setLoggerAdapter(new JdkLoggerAdapter());break;case "log4j2":setLoggerAdapter(new Log4j2LoggerAdapter());break;default:List<Class<? extends LoggerAdapter>> candidates = Arrays.asList(Log4jLoggerAdapter.class,Slf4jLoggerAdapter.class,Log4j2LoggerAdapter.class,JclLoggerAdapter.class,JdkLoggerAdapter.class);for (Class<? extends LoggerAdapter> clazz : candidates) {try {setLoggerAdapter(clazz.newInstance());break;} catch (Throwable ignored) {}}}}private LoggerFactory() {}public static void setLoggerAdapter(String loggerAdapter) {if (loggerAdapter != null && loggerAdapter.length() > 0) {setLoggerAdapter(ExtensionLoader.getExtensionLoader(LoggerAdapter.class).getExtension(loggerAdapter));}}/*** Set logger provider** @param loggerAdapter logger provider*/public static void setLoggerAdapter(LoggerAdapter loggerAdapter) {if (loggerAdapter != null) {Logger logger = loggerAdapter.getLogger(LoggerFactory.class.getName());logger.info("using logger: " + loggerAdapter.getClass().getName());LoggerFactory.LOGGER_ADAPTER = loggerAdapter;for (Map.Entry<String, FailsafeLogger> entry : LOGGERS.entrySet()) {entry.getValue().setLogger(LOGGER_ADAPTER.getLogger(entry.getKey()));}}}/*** Get logger provider** @param key the returned logger will be named after clazz* @return logger*/public static Logger getLogger(Class<?> key) {return LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(name)));}/*** Get logger provider** @param key the returned logger will be named after key* @return logger provider*/public static Logger getLogger(String key) {return LOGGERS.computeIfAbsent(key, k -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(k)));}/*** Get logging level** @return logging level*/public static Level getLevel() {return LOGGER_ADAPTER.getLevel();}/*** Set the current logging level** @param level logging level*/public static void setLevel(Level level) {LOGGER_ADAPTER.setLevel(level);}/*** Get the current logging file** @return current logging file*/public static File getFile() {return LOGGER_ADAPTER.getFile();}}

桥接模式

我们大家都熟悉,顾名思义就是用来将河的两岸联系起来的。而此处的桥是用来将两个独立的结构联系起来,而这两个被联系起来的结构可以独立的变化,所有其他的理解只要建立在这个层面上就会比较容易。

它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

优先文章链接

  1. 《菜鸟教程-桥接模式》
  2. 《知乎-秒懂设计模式》
  3. 《设计模式-桥接模式(诺基亚:我觉得我还能抢救下)》

应用场景

按照手机分类有智能手机、按钮手机、翻盖手机等,按照商品又有华为、小米、诺基亚等等

public class BridgeModel {/*** 品牌*/public interface Brand{void start();void shutdown();}/*** 手机抽象类*/public abstract class Phone{Brand brand;/*** 这段代码就是"桥接"思想,将另一个类和抽象类组合* @param brand*/public Phone(Brand brand) {this.brand = brand;}void start(){this.brand.start();}void shutdown(){this.brand.shutdown();}}class HuaWei implements Brand{@Overridepublic void start() {System.out.println("华为 开机");}@Overridepublic void shutdown() {System.out.println("华为 关机");}}class XiaoMi implements Brand{@Overridepublic void start() {System.out.println("小米 开机");}@Overridepublic void shutdown() {System.out.println("小米 关机");}}class Nokia implements Brand{@Overridepublic void start() {System.out.println("诺基亚 开机");}@Overridepublic void shutdown() {System.out.println("诺基亚 关机");}}/*** 带键盘按钮手机*/class ButtonIphone extends Phone{public ButtonIphone(Brand brand) {super(brand);}}/*** 智能手机*/class SmartIphone extends Phone{public SmartIphone(Brand brand) {super(brand);}}@Testpublic void runTest() {ButtonIphone buttonIphone = new ButtonIphone(new Nokia());buttonIphone.start();buttonIphone.shutdown();SmartIphone huawei = new SmartIphone(new HuaWei());huawei.start();huawei.shutdown();SmartIphone xiaomi = new SmartIphone(new XiaoMi());xiaomi.start();xiaomi.shutdown();}}

案例:dubbo源码-远程调用模块channelHandler设计

ChannelHandler是一个SPI拓展接口,用户可以定制自己的Handler

@SPI
public interface ChannelHandler {/*** on channel connected.** @param channel channel.*/void connected(Channel channel) throws RemotingException;/*** on channel disconnected.** @param channel channel.*/void disconnected(Channel channel) throws RemotingException;/*** on message sent.** @param channel channel.* @param message message.*/void sent(Channel channel, Object message) throws RemotingException;/*** on message received.** @param channel channel.* @param message message.*/void received(Channel channel, Object message) throws RemotingException;/*** on exception caught.** @param channel   channel.* @param exception exception.*/void caught(Channel channel, Throwable exception) throws RemotingException;}

抽象类:桥接ChannelHandler并实现自己的Handler

public abstract class AbstractChannelHandlerDelegate implements ChannelHandlerDelegate {protected ChannelHandler handler;protected AbstractChannelHandlerDelegate(ChannelHandler handler) {Assert.notNull(handler, "handler == null");this.handler = handler;}@Overridepublic ChannelHandler getHandler() {if (handler instanceof ChannelHandlerDelegate) {return ((ChannelHandlerDelegate) handler).getHandler();}return handler;}@Overridepublic void connected(Channel channel) throws RemotingException {handler.connected(channel);}@Overridepublic void disconnected(Channel channel) throws RemotingException {handler.disconnected(channel);}@Overridepublic void sent(Channel channel, Object message) throws RemotingException {handler.sent(channel, message);}@Overridepublic void received(Channel channel, Object message) throws RemotingException {handler.received(channel, message);}@Overridepublic void caught(Channel channel, Throwable exception) throws RemotingException {handler.caught(channel, exception);}
}

ChannelHandler实现类

public class MockedChannelHandler implements ChannelHandler {//    ConcurrentMap<String, Channel> channels = new ConcurrentHashMap<String, Channel>();ConcurrentHashSet<Channel> channels = new ConcurrentHashSet<Channel>();@Overridepublic void connected(Channel channel) throws RemotingException {channels.add(channel);}@Overridepublic void disconnected(Channel channel) throws RemotingException {channels.remove(channel);}@Overridepublic void sent(Channel channel, Object message) throws RemotingException {channel.send(message);}@Overridepublic void received(Channel channel, Object message) throws RemotingException {//echo channel.send(message);}@Overridepublic void caught(Channel channel, Throwable exception) throws RemotingException {throw new RemotingException(channel, exception);}public Set<Channel> getChannels() {return Collections.unmodifiableSet(channels);}
}

抽象类实现类

public class MultiMessageHandler extends AbstractChannelHandlerDelegate {public MultiMessageHandler(ChannelHandler handler) {super(handler);}@SuppressWarnings("unchecked")@Overridepublic void received(Channel channel, Object message) throws RemotingException {if (message instanceof MultiMessage) {MultiMessage list = (MultiMessage) message;for (Object obj : list) {handler.received(channel, obj);}} else {handler.received(channel, message);}}
}

组合模式

组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。

具体可以参考该文章:http://c.biancheng.net/view/1373.html

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

案例:apache common-collections源码List分析

apache common-collections是对jdk collections功能的补充,用了大量的装饰器设计模式,一下摘取List为例

commons-collections使用介绍之List

jdk List接口源码

public interface List<E> extends Collection<E> {//继承了Collection接口int size();boolean isEmpty();boolean contains(Object o);Iterator<E> iterator();Object[] toArray();<T> T[] toArray(T[] a);boolean add(E e);boolean remove(Object o);boolean containsAll(Collection<?> c);boolean addAll(Collection<? extends E> c);boolean removeAll(Collection<?> c);boolean retainAll(Collection<?> c);boolean equals(Object o);int hashCode();default Spliterator<E> spliterator() {return Spliterators.spliterator(this, Spliterator.ORDERED);}
}

List装饰器抽象方法

public abstract class AbstractListDecorator extends AbstractCollectionDecorator implements List {protected AbstractListDecorator() {}protected AbstractListDecorator(List list) {super(list);}protected List getList() {return (List)this.getCollection();}public void add(int index, Object object) {this.getList().add(index, object);}public boolean addAll(int index, Collection coll) {return this.getList().addAll(index, coll);}public Object get(int index) {return this.getList().get(index);}public int indexOf(Object object) {return this.getList().indexOf(object);}public int lastIndexOf(Object object) {return this.getList().lastIndexOf(object);}public ListIterator listIterator() {return this.getList().listIterator();}public ListIterator listIterator(int index) {return this.getList().listIterator(index);}public Object remove(int index) {return this.getList().remove(index);}public Object set(int index, Object object) {return this.getList().set(index, object);}public List subList(int fromIndex, int toIndex) {return this.getList().subList(fromIndex, toIndex);}
}

序列化装饰器抽象方法

public abstract class AbstractSerializableListDecorator extends AbstractListDecorator implements Serializable {private static final long serialVersionUID = 2684959196747496299L;protected AbstractSerializableListDecorator(List list) {super(list);}private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();out.writeObject(this.collection);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();this.collection = (Collection)in.readObject();}
}

FixedSizeList源码

FixedSizeList修饰另一个列表防止添加/删除并且固定列表大小。add、remove、clear和retain操作是不被支持的,set方法是允许的但是不会影响列表大小。

public class FixedSizeList extends AbstractSerializableListDecorator implements BoundedCollection {private static final long serialVersionUID = -2218010673611160319L;public static List decorate(List list) {return new FixedSizeList(list);}protected FixedSizeList(List list) {super(list);}public boolean add(Object object) {throw new UnsupportedOperationException("List is fixed size");}public void add(int index, Object object) {throw new UnsupportedOperationException("List is fixed size");}public boolean addAll(Collection coll) {throw new UnsupportedOperationException("List is fixed size");}public boolean addAll(int index, Collection coll) {throw new UnsupportedOperationException("List is fixed size");}public void clear() {throw new UnsupportedOperationException("List is fixed size");}public Object get(int index) {return this.getList().get(index);}public int indexOf(Object object) {return this.getList().indexOf(object);}public Iterator iterator() {return UnmodifiableIterator.decorate(this.getCollection().iterator());}public int lastIndexOf(Object object) {return this.getList().lastIndexOf(object);}public ListIterator listIterator() {return new FixedSizeList.FixedSizeListIterator(this.getList().listIterator(0));}public ListIterator listIterator(int index) {return new FixedSizeList.FixedSizeListIterator(this.getList().listIterator(index));}public Object remove(int index) {throw new UnsupportedOperationException("List is fixed size");}public boolean remove(Object object) {throw new UnsupportedOperationException("List is fixed size");}public boolean removeAll(Collection coll) {throw new UnsupportedOperationException("List is fixed size");}public boolean retainAll(Collection coll) {throw new UnsupportedOperationException("List is fixed size");}public Object set(int index, Object object) {return this.getList().set(index, object);}public List subList(int fromIndex, int toIndex) {List sub = this.getList().subList(fromIndex, toIndex);return new FixedSizeList(sub);}public boolean isFull() {return true;}public int maxSize() {return this.size();}static class FixedSizeListIterator extends AbstractListIteratorDecorator {protected FixedSizeListIterator(ListIterator iterator) {super(iterator);}public void remove() {throw new UnsupportedOperationException("List is fixed size");}public void add(Object object) {throw new UnsupportedOperationException("List is fixed size");}}
}

LazyList实现类

LazyList修饰另一个列表,当调用get方法时,如果索引超出列表长度,列表会自动增长,我们可以通过一个工厂获得超出索引位置的值。LazyList和GrowthList都可以实现对修饰的列表进行增长,但是LazyList发生在get时候,而GrowthList发生在set和add时候,我们也可以混合使用这两种列表。

public class LazyList extends AbstractSerializableListDecorator {private static final long serialVersionUID = -1708388017160694542L;protected final Factory factory;public static List decorate(List list, Factory factory) {return new LazyList(list, factory);}protected LazyList(List list, Factory factory) {super(list);if (factory == null) {throw new IllegalArgumentException("Factory must not be null");} else {this.factory = factory;}}public Object get(int index) {int size = this.getList().size();Object object;if (index < size) {object = this.getList().get(index);if (object == null) {object = this.factory.create();this.getList().set(index, object);return object;} else {return object;}} else {for(int i = size; i < index; ++i) {this.getList().add((Object)null);}object = this.factory.create();this.getList().add(object);return object;}}public List subList(int fromIndex, int toIndex) {List sub = this.getList().subList(fromIndex, toIndex);return new LazyList(sub, this.factory);}
}

外观模式(门面模式)

其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。用一张图来表示门面模式的结构为:
在这里插入图片描述

简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,设计到3个角色。

1)门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合(模块)。

2)子系统(模块)角色:实现了子系统的功能。它对客户角色和 Facade 是未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。

3)客户角色:通过调用 Facede 来完成要实现的功能。

日志门面(抽象层)日志实现
JCL(java.util.logging)JUL
SLF4jlog4j、log4j2、logback

slf4j的作用:只要所有代码都使用门面对象slf4j,我们就不需要关心其具体实现,最终所有地方使用一种具体实现即可,更换、维护都非常方便

sl4j作用以及原理

案例:sl4j日志使用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {// HelloWorld.class 就是你要打印的指定类的日志,// 如果你想在其它类中打印,那就把 HelloWorld.class 替换成目标类名.class 即可。Logger logger = LoggerFactory.getLogger(HelloWorld.class); logger.info("Hello World");}
}

享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。

RocketMQ过滤器工厂创建Filter

public class FilterFactory {public static final FilterFactory INSTANCE = new FilterFactory();protected static final Map<String, FilterSpi> FILTER_SPI_HOLDER = new HashMap<String, FilterSpi>(4);static {FilterFactory.INSTANCE.register(new SqlFilter());}/*** Register a filter.* <br>* Note:* <li>1. Filter registered will be used in broker server, so take care of it's reliability and performance.</li>*/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);}/*** Un register a filter.*/public FilterSpi unRegister(String type) {return FILTER_SPI_HOLDER.remove(type);}/*** Get a filter registered, null if none exist.*/public FilterSpi get(String type) {return FILTER_SPI_HOLDER.get(type);}

代理模式

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

静态代理

静态代理的代理关系在编译期间就已经确定了的。它适合于代理类较少且确定的情况

案例:rocketmq中滚动记录文件,先将日志记录到指定文件代理类实现

    private static InternalLogger createLogger(final String loggerName) {String clientLogLevel = System.getProperty(CLIENT_LOG_LEVEL, "INFO");boolean additive = "true".equalsIgnoreCase(System.getProperty(CLIENT_LOG_ADDITIVE));InternalLogger logger = InternalLoggerFactory.getLogger(loggerName);InnerLoggerFactory.InnerLogger innerLogger = (InnerLoggerFactory.InnerLogger) logger;Logger realLogger = innerLogger.getLogger();//if (rocketmqClientAppender == null) {//   createClientAppender();//}realLogger.addAppender(new AppenderProxy());realLogger.setLevel(Level.toLevel(clientLogLevel));realLogger.setAdditivity(additive);return logger;}    static class AppenderProxy extends Appender {private Appender proxy;@Overrideprotected void append(LoggingEvent event) {if (null == proxy) {proxy = ClientLogger.createClientAppender();}proxy.doAppend(event);}@Overridepublic void close() {if (null != proxy) {proxy.close();}}}

动态代理

代理类在程序运行时创建的代理方式叫动态代理

JDK动态代理

JDK动态代理是基于接口的方式,换句话来说就是代理类和目标类都实现同一个接口,利用jdk自带的包通过目标类实现类创建代理类,具体参考我另一个博客jdk、cglib动态代理代码示例

案例:dubbo中jdk动态代理工厂实现
public class JdkProxyFactory extends AbstractProxyFactory {@Override@SuppressWarnings("unchecked")public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));}@Overridepublic <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {return new AbstractProxyInvoker<T>(proxy, type, url) {@Overrideprotected Object doInvoke(T proxy, String methodName,Class<?>[] parameterTypes,Object[] arguments) throws Throwable {Method method = proxy.getClass().getMethod(methodName, parameterTypes);return method.invoke(proxy, arguments);}};}
}

其他相关类源码

public interface Node {URL getUrl();boolean isAvailable();void destroy();
}
public interface Invoker<T> extends Node {Class<T> getInterface();Result invoke(Invocation invocation) throws RpcException;
}
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {Logger logger = LoggerFactory.getLogger(AbstractProxyInvoker.class);private final T proxy;private final Class<T> type;private final URL url;public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {if (proxy == null) {throw new IllegalArgumentException("proxy == null");}if (type == null) {throw new IllegalArgumentException("interface == null");}if (!type.isInstance(proxy)) {throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);}this.proxy = proxy;this.type = type;this.url = url;}@Overridepublic Class<T> getInterface() {return type;}@Overridepublic URL getUrl() {return url;}@Overridepublic boolean isAvailable() {return true;}@Overridepublic void destroy() {}@Overridepublic Result invoke(Invocation invocation) throws RpcException {try {Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());CompletableFuture<Object> future = wrapWithFuture(value);CompletableFuture<AppResponse> appResponseFuture = future.handle((obj, t) -> {AppResponse result = new AppResponse();if (t != null) {if (t instanceof CompletionException) {result.setException(t.getCause());} else {result.setException(t);}} else {result.setValue(obj);}return result;});return new AsyncRpcResult(appResponseFuture, invocation);} catch (InvocationTargetException e) {if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {logger.error("Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.", e);}return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);} catch (Throwable e) {throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);}}private CompletableFuture<Object> wrapWithFuture(Object value) {if (RpcContext.getContext().isAsyncStarted()) {return ((AsyncContextImpl)(RpcContext.getContext().getAsyncContext())).getInternalFuture();} else if (value instanceof CompletableFuture) {return (CompletableFuture<Object>) value;}return CompletableFuture.completedFuture(value);}protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;@Overridepublic String toString() {return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString());}}
public class InvokerInvocationHandler implements InvocationHandler {private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);private final Invoker<?> invoker;private ConsumerModel consumerModel;private URL url;private String protocolServiceKey;public InvokerInvocationHandler(Invoker<?> handler) {this.invoker = handler;this.url = invoker.getUrl();String serviceKey = this.url.getServiceKey();this.protocolServiceKey = this.url.getProtocolServiceKey();if (serviceKey != null) {this.consumerModel = ApplicationModel.getConsumerModel(serviceKey);}}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getDeclaringClass() == Object.class) {return method.invoke(invoker, args);}String methodName = method.getName();Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length == 0) {if ("toString".equals(methodName)) {return invoker.toString();} else if ("$destroy".equals(methodName)) {invoker.destroy();return null;} else if ("hashCode".equals(methodName)) {return invoker.hashCode();}} else if (parameterTypes.length == 1 && "equals".equals(methodName)) {return invoker.equals(args[0]);}RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), protocolServiceKey, args);String serviceKey = invoker.getUrl().getServiceKey();rpcInvocation.setTargetServiceUniqueName(serviceKey);// invoker.getUrl() returns consumer url.RpcContext.setRpcContext(invoker.getUrl());if (consumerModel != null) {rpcInvocation.put(Constants.CONSUMER_MODEL, consumerModel);rpcInvocation.put(Constants.METHOD_MODEL, consumerModel.getMethodModel(method));}return invoker.invoke(rpcInvocation).recreate();}
}
@SPI("javassist")
public interface ProxyFactory {/*** create proxy.** @param invoker* @return proxy*/@Adaptive({PROXY_KEY})<T> T getProxy(Invoker<T> invoker) throws RpcException;/*** create proxy.** @param invoker* @return proxy*/@Adaptive({PROXY_KEY})<T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;/*** create invoker.** @param <T>* @param proxy* @param type* @param url* @return invoker*/@Adaptive({PROXY_KEY})<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
public abstract class AbstractProxyFactory implements ProxyFactory {private static final Class<?>[] INTERNAL_INTERFACES = new Class<?>[]{EchoService.class, Destroyable.class};@Overridepublic <T> T getProxy(Invoker<T> invoker) throws RpcException {return getProxy(invoker, false);}@Overridepublic <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {Set<Class<?>> interfaces = new HashSet<>();String config = invoker.getUrl().getParameter(INTERFACES);if (config != null && config.length() > 0) {String[] types = COMMA_SPLIT_PATTERN.split(config);for (String type : types) {// TODO can we load successfully for a different classloader?.interfaces.add(ReflectUtils.forName(type));}}if (generic) {if (!GenericService.class.isAssignableFrom(invoker.getInterface())) {interfaces.add(com.alibaba.dubbo.rpc.service.GenericService.class);}try {// find the real interface from urlString realInterface = invoker.getUrl().getParameter(Constants.INTERFACE);interfaces.add(ReflectUtils.forName(realInterface));} catch (Throwable e) {// ignore}}interfaces.add(invoker.getInterface());interfaces.addAll(Arrays.asList(INTERNAL_INTERFACES));return getProxy(invoker, interfaces.toArray(new Class<?>[0]));}public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);}

CGLIB动态代理

CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法

案例:dubbo中cglib创建代理类
    @Testpublic void testCglibProxy() throws Exception {ITest test = (ITest) Proxy.getProxy(ITest.class).newInstance((proxy, method, args) -> {System.out.println(method.getName());return null;});Enhancer enhancer = new Enhancer();enhancer.setSuperclass(test.getClass());enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> null);try {enhancer.create();} catch (IllegalArgumentException e) {e.printStackTrace();Assertions.fail();}}

javassist动态代码创建

javassist的强大之处在于它操作字节码的能力,可以动态的修改类,加载类,添加删除字段、方法等操作。当然也可以实现动态代理

简单使用案例

public class JavassistProxyFactory extends AbstractProxyFactory {@Override@SuppressWarnings("unchecked")public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));}@Overridepublic <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);return new AbstractProxyInvoker<T>(proxy, type, url) {@Overrideprotected Object doInvoke(T proxy, String methodName,Class<?>[] parameterTypes,Object[] arguments) throws Throwable {return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);}};}

动态字节码生成

    public static Wrapper getWrapper(Class<?> c) {while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.{c = c.getSuperclass();}if (c == Object.class) {return OBJECT_WRAPPER;}return WRAPPER_MAP.computeIfAbsent(c, Wrapper::makeWrapper);}private static Wrapper makeWrapper(Class<?> c) {if (c.isPrimitive()) {throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);}String name = c.getName();ClassLoader cl = ClassUtils.getClassLoader(c);StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types>Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance>List<String> mns = new ArrayList<>(); // method names.List<String> dmns = new ArrayList<>(); // declaring method names.// get all public field.for (Field f : c.getFields()) {String fn = f.getName();Class<?> ft = f.getType();if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) {continue;}c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");pts.put(fn, ft);}Method[] methods = c.getMethods();// get all public method.boolean hasMethod = hasMethods(methods);if (hasMethod) {c3.append(" try{");for (Method m : methods) {//ignore Object's method.if (m.getDeclaringClass() == Object.class) {continue;}String mn = m.getName();c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");int len = m.getParameterTypes().length;c3.append(" && ").append(" $3.length == ").append(len);boolean overload = false;for (Method m2 : methods) {if (m != m2 && m.getName().equals(m2.getName())) {overload = true;break;}}if (overload) {if (len > 0) {for (int l = 0; l < len; l++) {c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"").append(m.getParameterTypes()[l].getName()).append("\")");}}}c3.append(" ) { ");if (m.getReturnType() == Void.TYPE) {c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");} else {c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");}c3.append(" }");mns.add(mn);if (m.getDeclaringClass() == c) {dmns.add(mn);}ms.put(ReflectUtils.getDesc(m), m);}c3.append(" } catch(Throwable e) { ");c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");c3.append(" }");}c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");// deal with get/set method.Matcher matcher;for (Map.Entry<String, Method> entry : ms.entrySet()) {String md = entry.getKey();Method method = entry.getValue();if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {String pn = propertyName(matcher.group(1));c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");pts.put(pn, method.getReturnType());} else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {String pn = propertyName(matcher.group(1));c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");pts.put(pn, method.getReturnType());} else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {Class<?> pt = method.getParameterTypes()[0];String pn = propertyName(matcher.group(1));c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");pts.put(pn, pt);}}c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or getter method in class " + c.getName() + ".\"); }");// make classlong id = WRAPPER_CLASS_COUNTER.getAndIncrement();ClassGenerator cc = ClassGenerator.newInstance(cl);cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);cc.setSuperClass(Wrapper.class);cc.addDefaultConstructor();cc.addField("public static String[] pns;"); // property name array.cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.cc.addField("public static String[] mns;"); // all method name array.cc.addField("public static String[] dmns;"); // declared method name array.for (int i = 0, len = ms.size(); i < len; i++) {cc.addField("public static Class[] mts" + i + ";");}cc.addMethod("public String[] getPropertyNames(){ return pns; }");cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");cc.addMethod("public String[] getMethodNames(){ return mns; }");cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");cc.addMethod(c1.toString());cc.addMethod(c2.toString());cc.addMethod(c3.toString());try {Class<?> wc = cc.toClass();// setup static field.wc.getField("pts").set(null, pts);wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));wc.getField("mns").set(null, mns.toArray(new String[0]));wc.getField("dmns").set(null, dmns.toArray(new String[0]));int ix = 0;for (Method m : ms.values()) {wc.getField("mts" + ix++).set(null, m.getParameterTypes());}return (Wrapper) wc.newInstance();} catch (RuntimeException e) {throw e;} catch (Throwable e) {throw new RuntimeException(e.getMessage(), e);} finally {cc.release();ms.clear();mns.clear();dmns.clear();}}

优秀文章:菜鸟教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MDC日志logback整合使用

MDC日志logback整合使用 为什么使用MDC记录日志&#xff1f; 场景&#xff1a; 由于我的搜索服务并发量比较高&#xff0c;而处理一次搜索请求需要记录多个日志&#xff0c;因此日志特别多的情况下去查一次搜索整个日志打印情况会比较复杂。 解决方案&#xff1a; 可以使用用…

如何合理的配置线程数?

文章目录题记Java并发编程实战美团技术团队追求参数设置合理性线程池参数动态化题记 我想不管是在面试中、还是工作中&#xff0c;我们总会面临这种问题&#xff0c;那么到底有没有一种计算公式去告诉我们如何去配置呢&#xff1f; 答案是&#xff1a;没有 想要合理的配置线…

基于CompletableFuture并发任务编排实现

文章目录并发任务编排实现不带返回值/参数传递任务串行执行并行执行并行执行-自定义线程池阻塞等待&#xff1a;多并行任务执行完再执行任意一个任务并发执行完就执行下个任务串并行任务依赖场景带返回值/参数传递任务带返回值实现串行执行多线程任务串行执行对任务并行执行&am…

搜索研发工程师需要掌握的一些技能

文章目录基础语言数据结构与算法工程方面搜索相关搜索主要模块电商搜索流程分词相关搜索召回相似度算法相关词推荐排序相关国美搜索搜索算法工程师需要掌握的技能基础 语言 大部分公司用的是Solr、ElasticSearch&#xff0c;都是基于Java实现的&#xff0c;因此熟悉掌握Java语…

Flink入门看完这篇文章就够了

文章目录第一章&#xff1a;概述第一节&#xff1a;什么是Flink&#xff1f;第二节&#xff1a;Flink特点&#xff1f;第三节&#xff1a;Flink应用场景&#xff1f;第四节&#xff1a;Flink核心组成第五节&#xff1a;Flink处理模型&#xff1a;流处理和批处理第六节&#xff…

word小结

域代码/域结果显示设置 word选项---->>高级------>>显示域代码而非域值将样式传给其它文件使用 首先启动Word打开包含这些样式的一个文件&#xff0c;然后选择“工具”---->“模板和加载项”。在弹出的对话框中单击“管理器”按钮。在弹出的“管理器”对话框中&…

线程属性总结

今天面试那哥们问起线程属性&#xff0c;me竟然就说出了一个&#xff0c;囧 学习&#xff1a;http://blog.csdn.net/zsf8701/article/details/7842392 http://blog.csdn.net/jxhnuaa/article/details/3254299 http://blog.sina.com.cn/s/blog_9bd573450101hgdr.html int pthre…

百度2015校园招聘软件开发笔试题及答案

简单题&#xff08;本题共30分&#xff09; 请简述Tcp-ip的3次握手以及4次挥手过程&#xff1f;并解释为何关闭连接需要4次挥手(10分) 详细答案参见TCP/IP协议三次握手与四次握手流程解析 TCP三次握手、四次挥手过程如下: 通常情况下&#xff0c;一个正常的TCP连接&#xf…

linux ps 命令使用

Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照&#xff0c;就是执行ps命令的那个时刻的那些进程&#xff0c;如果想要动态的显示进程信息&#xff0c;就可以使用top命令。 linux上进程有5种状态 ps命令使…

UML序列图总结

序列图主要用于展示对象之间交互的顺序。 序列图将交互关系表示为一个二维图。纵向是时间轴&#xff0c;时间沿竖线向下延伸。横向轴代表了在协作中各独立对象的类元角色。类元角色用生命线表示。当对象存在时&#xff0c;角色用一条虚线表示&#xff0c;当对象的过程处于激活…

UML用例图总结

用例图主要用来描述 用户、需求、系统功能单元 之间的关系。它展示了一个外部用户能够观察到的系统功能模型图。 【用途】&#xff1a;帮助开发团队以一种可视化的方式理解系统的功能需求。 用例图所包含的元素如下&#xff1a; 1. 参与者(Actor) 表示与您的应用程序或…

Linux网络编程常见面试题

概述 TCP和UDP是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议。 TCP&#xff1a;传输控制协议&#xff0c;一种面向连接的协议&#xff0c;给用户进程提供可靠的全双工的字节流&#xff0c;TCP套接口是字节流套接口(stream socket)的一种。UDP&#xff1a;用户…

linux动态库查找路径以及依赖关系梳理

编译时与运行时库的路径 linux下&#xff0c;编译时与运行时库的搜索路径是不同的 运行时动态库的路径搜索顺序 LD_PRELOAD环境变量&#xff0c;一般用于hack 编译目标代码时指定的动态库搜索路径(指的是用 -wl,rpath 或-R选项而不是-L)&#xff0c;readelf -d命令可以查看编…

eclipse--android开发环境搭建教程

引言 在windows安装Android的开发环境不简单也说不上算复杂&#xff0c;但由于国内无法正常访问google给android开发环境搭建带来不小的麻烦。现将本人搭建过程记录如下&#xff0c;希望会对投身android开发的小伙伴有所帮助。 android开发环境部署过程 安装JDK环境 下载安装…

eclipse--python开发环境搭建

pydev插件介绍 PyDev is a Python IDE for Eclipse pydev官方网站&#xff1a;http://www.pydev.org/ 在Eclipse中安装pydev插件 启动Eclipse, 点击Help->Install New Software… 在弹出的对话框中&#xff0c;点Add 按钮。 Name中填:Pydev, Location中填http://pydev.or…

Win7虚拟无线AP以及Android手机抓包

设备要求 Windows7操作系统装有无线网卡的笔记本或台式机无线网卡必须支持“承载网络” 查看无线网卡是否支持“承载” 方法一: 开始菜单→所有程序→附件→命令提示符→右键“以管理员权限运行”; 键入命令“netsh wlan show drivers”,查看“支持承载网络”这一项,如果是…

CMD命令之BAT脚本路径信息

CD命令解疑 cd是chdir的缩写&#xff0c;命令详解参见cd /? 可以看到/d参数的解释如下&#xff1a; 使用 /D命令行开关&#xff0c;除了改变驱动器的当前目录之外&#xff0c;还可改变当前驱动器。 通常我们在xp系统中打开cmd窗口时&#xff0c;会显示 C:\Documents and Se…

【ubuntu 22.04】安装vscode并配置正常访问应用商店

注意&#xff1a;要去vscode官网下载deb安装包&#xff0c;在软件商店下载的版本不支持输入中文 在ubuntu下用火狐浏览器无法访问vscode官网&#xff0c;此时可以手动进行DNS解析&#xff0c;打开DNS在线查询工具&#xff0c;解析以下主机地址&#xff08;复制最后一个IP地址&a…

卷积与傅立叶变换

一、卷积 1、一维的卷积 连续&#xff1a; 在泛函分析中&#xff0c;卷积是通过两个函数f(x)f(x)和g(x)g(x)生成第三个函数的一种算子&#xff0c;它代表的意义是&#xff1a;两个函数中的一个(我取g(x)g(x)&#xff0c;可以任意取)函数&#xff0c;把g(x)g(x)经过翻转平移,…