每篇一句

千古以来要饭的没有要早饭的,知道为什么吗?

相关阅读

【小家Spring】聊聊Spring中的数据转换:Converter、ConversionService、TypeConverter、PropertyEditor

【小家Spring】聊聊Spring中的数据绑定 --- 属性访问器PropertyAccessor和实现类DirectFieldAccessor的使用


对Spring感兴趣可扫码加入wx群:`Java高工、架构师3群`(文末有二维码)


前言

这篇文章需要依赖于对属性访问器PropertyAccessor的理解,也就是上篇文章的内容:【小家Spring】聊聊Spring中的数据绑定 --- 属性访问器PropertyAccessor和实现类DirectFieldAccessor的使用

如果说上篇文章所说的PropertyAccessor你没有接触过和听过,那么本文即将要说的重点:BeanWrapper你应该多少有所耳闻吧~

BeanWrapper可以简单的把它理解为:一个方便开发人员使用字符串来对Java Bean的属性执行get、set操作的工具。关于它的数据转换使用了如下两种机制:

  1. PropertyEditor:隶属于Java Bean规范PropertyEditor只提供了String <-> Object的转换。
  2. ConversionService:Spring自3.0之后提供的替代PropertyEditor的机制(BeanWrapper在Spring的第一个版本就存在了~)

按照Spring官方文档的说法,当容器内没有注册ConversionService的时候,会退回使用PropertyEditor机制。言外之意:首选方案是ConversionService

其实了解的伙伴应该知道,这不是BeanWrapper的内容,而是父接口PropertyAccessor的内容~

BeanWrapper

官方解释:Spring低级JavaBeans基础设施的中央接口。通常来说并不直接使用BeanWrapper,而是借助BeanFactory或者DataBinder来一起使用~

//@since 13 April 2001  很清晰的看到,它也是个`PropertyAccessor`属性访问器
public interface BeanWrapper extends ConfigurablePropertyAccessor { // @since 4.1
void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
int getAutoGrowCollectionLimit(); Object getWrappedInstance();
Class<?> getWrappedClass(); // 获取属性们的PropertyDescriptor 获取属性们
PropertyDescriptor[] getPropertyDescriptors();
// 获取具体某一个属性~
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
}

BeanWrapper相当于一个代理器,Spring委托BeanWrapper完成Bean属性的填充工作。关于此接口的实现类,简单的说它只有唯一实现类:BeanWrapperImpl

BeanWrapperImpl

它作为BeanWrapper接口的默认实现,它足以满足所有的典型应用场景,它会缓存Bean的内省结果而提高效率。

在Spring2.5之前,此实现类是非public的,但在2.5之后给public了并且还提供了工厂:PropertyAccessorFactory帮助第三方框架能快速获取到一个实例~

public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {

	// 缓存内省结果~
@Nullable
private CachedIntrospectionResults cachedIntrospectionResults;
// The security context used for invoking the property methods.
@Nullable
private AccessControlContext acc; // 构造方法都是沿用父类的~
public BeanWrapperImpl() {
this(true);
}
...
private BeanWrapperImpl(Object object, String nestedPath, BeanWrapperImpl parent) {
super(object, nestedPath, parent);
setSecurityContext(parent.acc);
} // @since 4.3 设置目标对象~~~
public void setBeanInstance(Object object) {
this.wrappedObject = object;
this.rootObject = object;
this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
// 设置内省的clazz
setIntrospectionClass(object.getClass());
} // 复写父类的方法 增加内省逻辑
@Override
public void setWrappedInstance(Object object, @Nullable String nestedPath, @Nullable Object rootObject) {
super.setWrappedInstance(object, nestedPath, rootObject);
setIntrospectionClass(getWrappedClass());
} // 如果cachedIntrospectionResults它持有的BeanClass并不是传入的clazz 那就清空缓存 重新来~~~
protected void setIntrospectionClass(Class<?> clazz) {
if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) {
this.cachedIntrospectionResults = null;
}
}
private CachedIntrospectionResults getCachedIntrospectionResults() {
if (this.cachedIntrospectionResults == null) {
// forClass此方法:生成此clazz的类型结果,并且缓存了起来~~
this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
}
return this.cachedIntrospectionResults;
}
... // 获取到此属性的处理器。此处是个BeanPropertyHandler 内部类~
@Override
@Nullable
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
return (pd != null ? new BeanPropertyHandler(pd) : null);
}
@Override
protected BeanWrapperImpl newNestedPropertyAccessor(Object object, String nestedPath) {
return new BeanWrapperImpl(object, nestedPath, this);
}
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
return getCachedIntrospectionResults().getPropertyDescriptors();
} // 获取具体某一个属性的PropertyDescriptor
@Override
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
BeanWrapperImpl nestedBw = (BeanWrapperImpl) getPropertyAccessorForPropertyPath(propertyName);
String finalPath = getFinalPath(nestedBw, propertyName);
PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(finalPath);
if (pd == null) {
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName, "No property '" + propertyName + "' found");
}
return pd;
}
... // 此处理器处理的是PropertyDescriptor
private class BeanPropertyHandler extends PropertyHandler {
private final PropertyDescriptor pd; // 是否可读、可写 都是由PropertyDescriptor 去决定了~
// java.beans.PropertyDescriptor~~
public BeanPropertyHandler(PropertyDescriptor pd) {
super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null);
this.pd = pd;
}
...
@Override
@Nullable
public Object getValue() throws Exception {
...
ReflectionUtils.makeAccessible(readMethod);
return readMethod.invoke(getWrappedInstance(), (Object[]) null);
}
...
}
}

从继承体系上,首先我们应该能看出来BeanWrapperImpl的三重身份:

  1. Bean包裹器
  2. 属性访问器(PropertyAccessor)
  3. 属性编辑器注册表(PropertyEditorRegistry)

从源码中继续分析还能再得出如下两个结论:

  1. 它给属性赋值调用的是Method方法,如readMethod.invokewriteMethod.invoke
  2. 它对Bean的操作,大都委托给CachedIntrospectionResults去完成~

因此若想了解它,必然主要是要先了解java.beans.PropertyDescriptororg.springframework.beans.CachedIntrospectionResults,首当其冲的自然还有Java内省


Java内省Introspector

首先可以先了解下JavaBean的概念:一种特殊的类,主要用于传递数据信息。这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。

因此JavaBean都有如下几个特征:

  1. 属性都是私有的;
  2. 有无参的public构造方法;
  3. 对私有属性根据需要提供公有的getXxx方法以及setXxx方法;
  4. getters必须有返回值没有方法参数;setter值没有返回值,有方法参数;

符合这些特征的类,被称为JavaBean;JDK中提供了一套API用来访问某个属性的getter/setter方法,这些API存放在java.beans中,这就是内省(Introspector)

内省和反射的区别

反射:Java反射机制是在运行中,对任意一个类,能够获取得到这个类的所有属性和方法;它针对的是任意类

内省(Introspector):是Java语言对JavaBean类属性、事件的处理方法

  1. 反射可以操作各种类的属性,而内省只是通过反射来操作JavaBean的属性
  2. 内省设置属性值肯定会调用seter方法,反射可以不用(反射可直接操作属性Field)
  3. 反射就像照镜子,然后能看到.class的所有,是客观的事实。内省更像主观的判断:比如看到getName()内省就会认为这个类中有name字段,但事实上并不一定会有name;通过内省可以获取bean的getter/setter

既然反射比内省比内省强大这么多,那内省用在什么时候场景呢?下面给出一个示例来说明它的用武之地:

	// 就这样简单几步,就完成了表单到User对象的封装~
public void insertUser(HttpServletRequest request) throws Exception {
User user = new User(); // 遍历:根据字段名去拿值即可(此处省略判空、类型转换等细节,不在本文讨论范围)
PropertyDescriptor[] pds = Introspector.getBeanInfo(User.class).getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
pd.getWriteMethod().invoke(user, request.getParameter(pd.getName()));
}
}

通过内省可以很轻松的将form表单的内容填充进对象里面,比反射轻松省力多了。其实像MyBatis这种框架,底层都用到了Java的内省机制。

内省的API主要有Introspector、BeanInfo、PropertyDescriptor等,下面就以他三为例来操作一个JavaBean:

@Getter
@Setter
@ToString
public class Child { private String name;
private Integer age; }
使用Introspector + BeanInfo
    public static void main(String[] args) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(Child.class); BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); // 打印
System.out.println(beanDescriptor);
System.out.println("------------------------------");
Arrays.stream(methodDescriptors).forEach(x -> System.out.println(x));
System.out.println("------------------------------");
Arrays.stream(propertyDescriptors).forEach(x -> System.out.println(x));
System.out.println("------------------------------");
}

输入内容如下:

java.beans.BeanDescriptor[name=Child; beanClass=class com.fsx.bean.Child]
------------------------------
java.beans.MethodDescriptor[name=getClass; method=public final native java.lang.Class java.lang.Object.getClass()]
java.beans.MethodDescriptor[name=getName; method=public java.lang.String com.fsx.bean.Child.getName()]
java.beans.MethodDescriptor[name=setAge; method=public void com.fsx.bean.Child.setAge(java.lang.Integer)]
java.beans.MethodDescriptor[name=setName; method=public void com.fsx.bean.Child.setName(java.lang.String)]
java.beans.MethodDescriptor[name=getAge; method=public java.lang.Integer com.fsx.bean.Child.getAge()]
java.beans.MethodDescriptor[name=wait; method=public final void java.lang.Object.wait() throws java.lang.InterruptedException]
java.beans.MethodDescriptor[name=notifyAll; method=public final native void java.lang.Object.notifyAll()]
java.beans.MethodDescriptor[name=notify; method=public final native void java.lang.Object.notify()]
java.beans.MethodDescriptor[name=wait; method=public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException]
java.beans.MethodDescriptor[name=hashCode; method=public native int java.lang.Object.hashCode()]
java.beans.MethodDescriptor[name=wait; method=public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException]
java.beans.MethodDescriptor[name=equals; method=public boolean java.lang.Object.equals(java.lang.Object)]
java.beans.MethodDescriptor[name=toString; method=public java.lang.String com.fsx.bean.Child.toString()]
------------------------------
java.beans.PropertyDescriptor[name=age; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer com.fsx.bean.Child.getAge(); writeMethod=public void com.fsx.bean.Child.setAge(java.lang.Integer)]
java.beans.PropertyDescriptor[name=class; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String com.fsx.bean.Child.getName(); writeMethod=public void com.fsx.bean.Child.setName(java.lang.String)]
------------------------------

可以看到getMethodDescriptors()它把父类的MethodDescriptor也拿出来了。

PropertyDescriptor中比较特殊的是因为有getClass()方法,因此class也算是一个PropertyDescriptor,但是它没有writeMethod哦~

关于BeanInfo,Spring在3.1提供了一个类ExtendedBeanInfo继承自它实现了功能扩展,并且提供了BeanInfoFactory来专门生产它~~~(实现类为:ExtendedBeanInfoFactory

但是如果只想拿某一个属性的话,使用Introspector就不是那么方便了,下面介绍更为常用的PropertyDescriptor来处理某一个属性~

PropertyDescriptor 属性描述器

属性描述符描述了Java bean通过一对访问器方法导出的一个属性。上面的示例此处用PropertyDescriptor试试:

    public static void main(String[] args) throws IntrospectionException {
PropertyDescriptor age = new PropertyDescriptor("age", Child.class);
System.out.println(age.getPropertyType()); //class java.lang.Integer
System.out.println(age.getDisplayName()); //age // 最重要的两个方法~~~
System.out.println(age.getReadMethod()); //public java.lang.Integer com.fsx.bean.Child.getAge()
System.out.println(age.getWriteMethod()); //public void com.fsx.bean.Child.setAge(java.lang.Integer)
}

可以看到它可以实现更加细粒度的控制。将PropertyDescriptor类的一些主要方法描述如下:

  1. getPropertyType(),获得属性的Class对象;
  2. getReadMethod(),获得用于读取属性值的方法;
  3. getWriteMethod(),获得用于写入属性值的方法;
  4. setReadMethod(Method readMethod),设置用于读取属性值的方法;
  5. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。

CachedIntrospectionResults

Spring如果需要依赖注入那么就必须依靠Java内省这个特性了,说到Spring IOC与JDK内省的结合那么就不得不说一下Spring中的CachedIntrospectionResults这个类了。

它是Spring提供的专门用于缓存JavaBean的PropertyDescriptor描述信息的类,不能被应用代码直接使用。

它的缓存信息是被静态存储起来的(应用级别),因此对于同一个类型的被操作的JavaBean并不会都创建一个新的CachedIntrospectionResults,因此,这个类使用了工厂模式,使用私有构造器和一个静态的forClass工厂方法来获取实例。

public final class CachedIntrospectionResults {

	// 它可以通过在spring.properties里设置这个属性,来关闭内省的缓存~~~
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses = SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME); // 此处使用了SpringFactoriesLoader这个SPI来加载BeanInfoFactory,唯一实现类是ExtendedBeanInfoFactory
/** Stores the BeanInfoFactory instances. */
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader()); static final Set<ClassLoader> acceptedClassLoaders = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
static final ConcurrentMap<Class<?>, CachedIntrospectionResults> strongClassCache = new ConcurrentHashMap<>(64);
static final ConcurrentMap<Class<?>, CachedIntrospectionResults> softClassCache = new ConcurrentReferenceHashMap<>(64); // 被包裹类的BeanInfo~~~也就是目标类
private final BeanInfo beanInfo;
// 它缓存了被包裹类的所有属性的属性描述器PropertyDescriptor。
private final Map<String, PropertyDescriptor> propertyDescriptorCache; ... // 其它的都是静态方法
// 只有它会返回一个实例,此类是单例的设计~ 它保证了每个beanClass都有一个CachedIntrospectionResults 对象,然后被缓存起来~
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException { ... }
}

本处理类的核心内容是Java内省getBeanInfo()以及PropertyDescriptor~注意:为了使此内省缓存生效,有个前提条件请保证了:

  • 确保将Spring框架的Jar包和你的应用类使用的是同一个ClassLoader加载的,这样在任何情况下会允许随着应用的生命周期来清楚缓存。

因此对于web应用来说,Spring建议给web容器注册一个IntrospectorCleanupListener监听器来防止多ClassLoader布局,这样也可以有效的利用caching从而提高效率~


监听器的配置形如这样(此处以web.xml里配置为例):

<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

说明:请保证此监听器配置在第一个位置,比ContextLoaderListener还靠前~ 此监听器能有效的防止内存泄漏问题~~~(因为内省的缓存是应用级别的全局缓存,很容易造成泄漏的~)

其实流行框架比如struts, Quartz等在使用JDK的内省时,存在没有释的内存泄漏问题~


DirectFieldAccessFallbackBeanWrapper

说完了BeanWrapperImpl,可以看看它的子类DirectFieldAccessFallbackBeanWrapper,他就像BeanWrapperImplDirectFieldAccessor的结合体。它先用BeanWrapperImpl.getPropertyValue(),若抛出异常了(毕竟内省不是十分靠谱,哈哈)再用DirectFieldAccessor~~~此子类在JedisClusterConnection有被使用到过,比较简单没啥太多好说的~

PropertyAccessorFactory

Spring2.5后提供的快速获取PropertyAccessor两个重要实现类的工厂。

public final class PropertyAccessorFactory {
private PropertyAccessorFactory() {
}
// 生产一个BeanWrapperImpl(最为常用)
public static BeanWrapper forBeanPropertyAccess(Object target) {
return new BeanWrapperImpl(target);
}
// 生产一个DirectFieldAccessor
public static ConfigurablePropertyAccessor forDirectFieldAccess(Object target) {
return new DirectFieldAccessor(target);
} }

BeanWrapper使用Demo

说了这么多,是时候实战一把了~

// 省略Apple类和Size类,有需要的请参照上篇文章(加上@Getter、@Setter即可

    public static void main(String[] args) {
Apple apple = new Apple(); BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(apple); // ================当作一个普通的PropertyAccessor来使用 默认情况下字段也都必须有初始值才行~===================
// 设置普通属性
beanWrapper.setPropertyValue("color", "红色"); //请保证对应字段有set方法才行,否则抛错:Does the parameter type of the setter match the return type of the getter?
// 设置嵌套属性(注意:此处能够正常work是因为有= new Size(),
// 否则报错:Value of nested property 'size' is null 下同~)
beanWrapper.setPropertyValue("size.height", 10); // 设置集合/数组属性
beanWrapper.setPropertyValue("arrStr[0]", "arrStr");
beanWrapper.setPropertyValue("arrStr[1]", "arrStr1"); // 注意:虽然初始化时初始化过数组了,但是仍以此处的为准
// =========打印输出
System.out.println(apple); //Apple(color=红色, size=Size(height=10, width=null), arrStr=[arrStr, arrStr1], listStr=[], map={}, listList=[[]], listMap=[{}]) // 当作BeanWrapper使用
PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
PropertyDescriptor color = beanWrapper.getPropertyDescriptor("color");
System.out.println(propertyDescriptors.length); // 8
System.out.println(color); //org.springframework.beans.GenericTypeAwarePropertyDescriptor[name=color] System.out.println(beanWrapper.getWrappedClass()); //class com.fsx.bean.Apple
System.out.println(beanWrapper.getWrappedInstance()); //Apple(color=红色, size=Size(height=10...
}

上面代码能够清晰的表示了通过BeanWrapper来操作JavaBean还是非常之简便的。


最后,上一张比较丑的结构图,画一画属性编辑器、类型转换器、属性解析器、属性访问器大致的一个关系(此图不喜勿碰):

总结

BeanWrapper接口,作为Spring内部的一个核心接口,正如其名,它是bean的包裹类,即在内部中将会保存该bean的实例,提供其它一些扩展功能。

Spring对Bean的属性存取都是通过BeanWrapperImpl实现的,BeanWrapperImplBean是一对一的关系,BeanWrapperImpl通过属性的读方法写方法来存取Bean属性的。为了更加深刻的了解BeanWrapper,下篇文章会深入分析Spring BeanFactory对它的应用~

知识交流

The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群

若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群


![在这里插入图片描述](https://img-blog.csdnimg.cn/20190703175020107.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Y2NDEzODU3MTI=,size_16,color_FFFFFF,t_70,pic_center =300x)

详叙BeanWrapper和PropertyDescriptor的更多相关文章

  1. [Python3] 003 变量类型概述 & 数字类型详叙

    目录 0. 变量类型概述 1. 数字类型详叙 1.1 整数 1.1.1 常用进制 1.1.2 少废话,上例子 1.2 浮点数 1.2.1 使用浮点数时可以"偷懒" 1.2.2 科学 ...

  2. 【小家Spring】聊聊Spring中的数据绑定 --- BeanWrapper以及内省Introspector和PropertyDescriptor

    #### 每篇一句 > 千古以来要饭的没有要早饭的,知道为什么吗? #### 相关阅读 [[小家Spring]聊聊Spring中的数据转换:Converter.ConversionService ...

  3. C# PPT 为形状设置三维效果

    在PPT中,形状是非常重要的元素.3-D形状,立体多元,给人耳目一新的感觉.在幻灯片中添加3-D效果形状,必然会为PPT的整体效果增色不少.为形状设置三维格式时,可设置棱台,轮廓线,表面效果等. 本篇 ...

  4. Url路径重写的原理

    ASP.net的地址重写(URLRewriter)实现原理及代码示例 吴剑 2007-01-01 原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 概述 访问 ...

  5. JQuery 实现页面无刷新

    对于JQuery实现页面无刷新的效果,即:应用这个JQuery这个组件,可以实现在页面上加载数据库中的数据信息,但是并没有给用户页面刷新的感觉,这样既可以有效的进行数据交互,也可以不妨碍用户的其他操作 ...

  6. Java 7 中 NIO.2 的使用——第二节 元数据文件的属性

    如果你有很多疑问关于一个文件或目录,它是否是隐藏的,它的大小是多少,谁拥有它,你可以从元数据中得到这些信息.所谓的元数据,就是描述数据的数据. NIO.2组织了这些原数据的属性的概念,并提供了java ...

  7. c++中实现委托

    成员函数指针与高性能的C++委托(上篇) 撰文:Don Clugston 引子 标准C++中没有真正的面向对象的函数指针.这一点对C++来说是不幸的,因为面向对象的指针(也叫做"闭包(clo ...

  8. JAVA_用_JCO连接_SAP,实现调用SAP_的_RFC_函数(整理)(附一篇看起来比较全面的说明)(JCO报错信息)

    // 获取RFC返回的字段值 11 JCoParameterList exportParam = function.getExportParameterList(); 12 String exPara ...

  9. asp.net学习之SqlDataSource

    原文:asp.net学习之SqlDataSource 通过 SqlDataSource 控件,可以使用 Web 服务器控件访问位于关系数据库中的数据.其中可以包括 Microsoft SQL Serv ...

随机推荐

  1. Java HashMap实现原理 源码剖析

    HashMap是基于哈希表的Map接口实现,提供了所有可选的映射操作,并允许使用null值和null建,不同步且不保证映射顺序.下面记录一下研究HashMap实现原理. HashMap内部存储 在Ha ...

  2. How to setup Assigned Access in Windows 10 (Kiosk Mode) 设置分配的访问权限(Kiosk模式)

    Let’s say you’re building some sort of ingenious mechanical contraption to be displayed in public th ...

  3. EnterpriseLibrary 6.0 AOP 使用问题

    因为EnterPrise Library 6.0改动了模块的功能类不再自动从Unity创建了,也就是引导也不依赖Unity容器组件,需要先使用静态方法注册一下 private static void ...

  4. 事件循环和线程没有必然关系(就像Windows子线程默认没有消息循环一样),模态对话框和事件循环也没有必然关系(QWidget直接就可以)

    周末天冷,索性把电脑抱到床上上网,这几天看了 dbzhang800 博客关于 Qt 事件循环的几篇 Blog,发现自己对 Qt 的事件循环有不少误解.从来只看到现象,这次借 dbzhang800 的博 ...

  5. sklearn文本特征提取——TfidfVectorizer

    什么是TF-IDF IF-IDF(term frequency-inverse document frequency)词频-逆向文件频率.在处理文本时,如何将文字转化为模型可以处理的向量呢?IF-ID ...

  6. ML:吴恩达 机器学习 课程笔记(Week1~2)

    吴恩达(Andrew Ng)机器学习课程:课程主页 由于博客编辑器有些不顺手,所有的课程笔记将全部以手写照片形式上传.有机会将在之后上传课程中各个ML算法实现的Octave版本. Linear Reg ...

  7. 一个 Qt 显示图片的控件(继承QWidget,使用QPixmap记录图像,最后在paintEvent进行绘制,可缩放)

    Qt 中没有专门显示图片的控件,通常我们会使用QLabel来显示图片.但是QLabel 显示图片的能力还是有点弱.比如不支持图像的缩放一类的功能,使用起来不是很方便.因此我就自己写了个简单的类. 我这 ...

  8. 分布式存储系统GlusterFS初体验

    摘要: GlusterFS是Scale-Out存储解决方案Gluster的核心,它是一个开源的分布式文件系统,具有强大的横向扩展能力,通过扩展能够支持数PB存储容量和处理数千客户端.GlusterFS ...

  9. VS 查看是否有内存泄露的方法

    加入下列宏定义: #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) #else #defi ...

  10. Redis EXISTS命令耗时过长case排查

    一.背景 redis慢日志分析平台上线后,随便看了一下,发现onestore使用的缓存集群,存在大量的EXISTS命令慢查询的情况: 平均每个EXISTS命令需要13ms,最大耗时近20ms.这个结果 ...